Browse code

clamonacc - move fanotify init to startup check function to ensure elevated permission checking is done before daemonization; fix potential segfault when pswd struct does not get allocated during exclusion check

Mickey Sola authored on 2019/06/21 05:54:08
Showing 4 changed files
... ...
@@ -33,6 +33,10 @@
33 33
 #endif
34 34
 #include <time.h>
35 35
 #include <signal.h>
36
+#if defined(FANOTIFY)
37
+#include <sys/fanotify.h>
38
+#include <fcntl.h>
39
+#endif
36 40
 
37 41
 #include "../libclamav/clamav.h"
38 42
 #include "../libclamav/others.h"
... ...
@@ -220,6 +224,9 @@ int onas_start_eloop(struct onas_context **ctx) {
220 220
 
221 221
 static int startup_checks(struct onas_context *ctx) {
222 222
 
223
+#if defined(FANOTIFY)
224
+	char faerr[128];
225
+#endif
223 226
 	int ret = 0;
224 227
         cl_error_t err = CL_SUCCESS;
225 228
 
... ...
@@ -235,6 +242,17 @@ static int startup_checks(struct onas_context *ctx) {
235 235
 		goto done;
236 236
 	}
237 237
 
238
+#if defined(FANOTIFY)
239
+        ctx->fan_fd = fanotify_init(FAN_CLASS_CONTENT | FAN_UNLIMITED_QUEUE | FAN_UNLIMITED_MARKS, O_LARGEFILE | O_RDONLY);
240
+        if (ctx->fan_fd < 0) {
241
+            logg("!Clamonacc: fanotify_init failed: %s\n", cli_strerror(errno, faerr, sizeof(faerr)));
242
+            if (errno == EPERM)
243
+                logg("!Clamonacc: clamonacc must have elevated permissions ... exiting ...\n");
244
+            ret = 2;
245
+            goto done;
246
+        }
247
+#endif
248
+
238 249
         if (curl_global_init(CURL_GLOBAL_NOTHING)) {
239 250
             ret = 2;
240 251
             goto done;
... ...
@@ -284,7 +302,6 @@ void help(void)
284 284
 
285 285
 void* onas_cleanup(struct onas_context *ctx) {
286 286
 	onas_context_cleanup(ctx);
287
-	cl_cleanup_crypto();
288 287
 	logg_close();
289 288
 }
290 289
 
... ...
@@ -62,6 +62,9 @@ static int onas_fan_fd;
62 62
 static void onas_fan_exit(int sig)
63 63
 {
64 64
 	logg("*ClamFanotif: onas_fan_exit(), signal %d\n", sig);
65
+        if (sig == 11) {
66
+            logg("!Clamonacc: clamonacc has experienced a fatal error, if you continue to see this error, please run clamonacc with --debug and report the issue and crash report to the developpers\n");
67
+        }
65 68
 
66 69
 	if(onas_fan_fd) {
67 70
 		close(onas_fan_fd);
... ...
@@ -88,80 +91,72 @@ static void onas_fan_exit(int sig)
88 88
 
89 89
 cl_error_t onas_setup_fanotif(struct onas_context **ctx) {
90 90
 
91
-    const struct optstruct *pt;
92
-    short int scan;
93
-    unsigned int sizelimit = 0, extinfo;
91
+	const struct optstruct *pt;
92
+	short int scan;
93
+	unsigned int sizelimit = 0, extinfo;
94 94
 	uint64_t fan_mask = FAN_EVENT_ON_CHILD;
95
-    char err[128];
96
-
97
-    pthread_attr_t ddd_attr;
98
-    struct ddd_thrarg *ddd_tharg = NULL;
99 95
 
100
-    ddd_pid = 0;
101
-
102
-    /* Initialize fanotify */
103
-    onas_fan_fd = fanotify_init(FAN_CLASS_CONTENT | FAN_UNLIMITED_QUEUE | FAN_UNLIMITED_MARKS, O_LARGEFILE | O_RDONLY);
104
-    if (onas_fan_fd < 0) {
105
-		logg("!ClamFanotif: fanotify_init failed: %s\n", cli_strerror(errno, err, sizeof(err)));
106
-        if (errno == EPERM)
107
-			logg("!ClamFanotif: clamonacc must have elevated permissions ... exiting ...\n");
108
-		return CL_EOPEN;
109
-    }
96
+	pthread_attr_t ddd_attr;
97
+	struct ddd_thrarg *ddd_tharg = NULL;
110 98
 
99
+	ddd_pid = 0;
111 100
 
112 101
 	if (!ctx || !*ctx) {
113 102
 		logg("!ClamFanotif: unable to start clamonacc. (bad context)\n");
114 103
 		return CL_EARG;
115
-    }
104
+	}
116 105
 
117
-	(*ctx)->fan_fd = onas_fan_fd;
106
+        onas_fan_fd = (*ctx)->fan_fd;
118 107
 	(*ctx)->fan_mask = fan_mask;
119 108
 
120 109
 	if (optget((*ctx)->clamdopts, "OnAccessPrevention")->enabled && !optget((*ctx)->clamdopts, "OnAccessMountPath")->enabled) {
121 110
 		logg("*ClamFanotif: kernel-level blocking feature enabled ... preventing malicious files access attempts\n");
122 111
 		(*ctx)->fan_mask |= FAN_ACCESS_PERM | FAN_OPEN_PERM;
123
-    } else {
112
+	} else {
124 113
 		logg("*ClamFanotif: kernel-level blocking feature disabled ...\n");
125 114
 		if (optget((*ctx)->clamdopts, "OnAccessPrevention")->enabled && optget((*ctx)->clamdopts, "OnAccessMountPath")->enabled) {
126 115
 			logg("*ClamFanotif: feature not available when watching mounts ... \n");
127 116
 		}
128 117
 		(*ctx)->fan_mask |= FAN_ACCESS | FAN_OPEN;
129
-    }
118
+	}
130 119
 
131 120
 	if ((pt = optget((*ctx)->clamdopts, "OnAccessMountPath"))->enabled) {
132
-        while (pt) {
121
+		while (pt) {
133 122
 			if(fanotify_mark(onas_fan_fd, FAN_MARK_ADD | FAN_MARK_MOUNT, (*ctx)->fan_mask, (*ctx)->fan_fd, pt->strarg) != 0) {
134 123
 				logg("!ClamFanotif: can't include mountpoint '%s'\n", pt->strarg);
135 124
 				return CL_EARG;
136
-            } else
125
+			} else {
137 126
 				logg("*ClamFanotif: recursively watching the mount point '%s'\n", pt->strarg);
138
-            pt = (struct optstruct *)pt->nextarg;
139
-        }
127
+			}
128
+			pt = (struct optstruct *)pt->nextarg;
129
+		}
140 130
 
141 131
 	} else if (!optget((*ctx)->clamdopts, "OnAccessDisableDDD")->enabled) {
142 132
 		(*ctx)->ddd_enabled = 1;
143
-    } else {
133
+	} else {
144 134
 		if((pt = optget((*ctx)->clamdopts, "OnAccessIncludePath"))->enabled) {
145
-            while (pt) {
135
+			while (pt) {
146 136
 				if(fanotify_mark(onas_fan_fd, FAN_MARK_ADD, (*ctx)->fan_mask, (*ctx)->fan_fd, pt->strarg) != 0) {
147 137
 					logg("!ClamFanotif: can't include path '%s'\n", pt->strarg);
148 138
 					return CL_EARG;
149
-                } else
139
+				} else {
150 140
 					logg("*ClamFanotif: watching directory '%s' (non-recursively)\n", pt->strarg);
151
-                pt = (struct optstruct *)pt->nextarg;
152
-            }
153
-        } else {
141
+				}
142
+				pt = (struct optstruct *)pt->nextarg;
143
+			}
144
+		} else {
154 145
 			logg("!ClamFanotif: please specify at least one path with OnAccessIncludePath\n");
155 146
 			return CL_EARG;
156
-        }
157
-    }
147
+		}
148
+	}
158 149
 
159
-    /* Load other options. */
150
+	/* Load other options. */
160 151
 	(*ctx)->sizelimit = optget((*ctx)->clamdopts, "OnAccessMaxFileSize")->numarg;
161
-	if((*ctx)->sizelimit)
152
+	if((*ctx)->sizelimit) {
162 153
 		logg("*ClamFanotif: max file size limited to %lu bytes\n", (*ctx)->sizelimit);
163
-    else
154
+	} else {
164 155
 		logg("*ClamFanotif: file size limit disabled\n");
156
+	}
165 157
 
166 158
 	extinfo = optget((*ctx)->clamdopts, "ExtendedDetectionInfo")->enabled;
167 159
 
... ...
@@ -38,9 +38,12 @@
38 38
 #include "../../clamd/scanner.h"
39 39
 #include "../clamonacc.h"
40 40
 #include "../client/onaccess_client.h"
41
+#include "../scan/onaccess_scque.h"
41 42
 
42 43
 #if defined(FANOTIFY)
43 44
 
45
+extern pthread_cond_t onas_scque_empty_cond;
46
+
44 47
 int onas_fan_checkowner(int pid, const struct optstruct *opts)
45 48
 {
46 49
     struct passwd *pwd;
... ...
@@ -49,6 +52,7 @@ int onas_fan_checkowner(int pid, const struct optstruct *opts)
49 49
     const struct optstruct *opt      = NULL;
50 50
     const struct optstruct *opt_root = NULL;
51 51
     const struct optstruct *opt_uname = NULL;
52
+    int retry = 0;
52 53
 
53 54
     /* always ignore ourselves */
54 55
     if (pid == (int)getpid()) {
... ...
@@ -79,9 +83,45 @@ int onas_fan_checkowner(int pid, const struct optstruct *opts)
79 79
         if (opt_uname->enabled) {
80 80
             while (opt_uname)
81 81
             {
82
+                errno = 0;
82 83
                 pwd = getpwuid(sb.st_uid);
83
-                if (!strncmp(opt_uname->strarg, pwd->pw_name, strlen(opt_uname->strarg)))
84
-                    return CHK_FOUND;
84
+		if (NULL == pwd) {
85
+			if (errno) {
86
+				logg("*ClamMisc: internal error (failed to exclude event) ... %s\n", strerror(errno));
87
+				switch (errno) {
88
+					case EIO:
89
+						logg("*ClamMisc: system i/o failed while retrieving username information (excluding for safety)\n");
90
+						return CHK_FOUND;
91
+						break;
92
+					case EINTR:
93
+						logg("*ClamMisc: caught signal while retrieving username information from system (excluding for safety)\n");
94
+						return CHK_FOUND;
95
+						break;
96
+					case EMFILE:
97
+					case ENFILE:
98
+						if (0 == retry) {
99
+							logg("*ClamMisc: waiting for consumer thread to catch up then retrying ...\n");
100
+							sleep(3);
101
+							retry = 1;
102
+							continue;
103
+						} else {
104
+							logg("*ClamMisc: fds have been exhausted ... attempting to force the consumer thread to catch up ... (excluding for safety)\n");
105
+							pthread_cond_signal(&onas_scque_empty_cond);
106
+							sleep(3);
107
+							return CHK_FOUND;
108
+						}
109
+					case ERANGE:
110
+					default:
111
+						logg("*ClamMisc: unknown error occurred (excluding for safety)\n");
112
+						return CHK_FOUND;
113
+						break;
114
+				}
115
+			}
116
+		} else {
117
+			if (!strncmp(opt_uname->strarg, pwd->pw_name, strlen(opt_uname->strarg))) {
118
+				return CHK_FOUND;
119
+			}
120
+		}
85 121
                 opt_uname = opt_uname->nextarg;
86 122
             }
87 123
         }
... ...
@@ -52,7 +52,7 @@ static void onas_destroy_event_queue_node(struct onas_event_queue_node *node);
52 52
 static pthread_mutex_t onas_queue_lock = PTHREAD_MUTEX_INITIALIZER;
53 53
 
54 54
 static pthread_mutex_t onas_scque_loop = PTHREAD_MUTEX_INITIALIZER;
55
-static pthread_cond_t onas_scque_empty_cond = PTHREAD_COND_INITIALIZER;
55
+pthread_cond_t onas_scque_empty_cond = PTHREAD_COND_INITIALIZER;
56 56
 extern pthread_t scque_pid;
57 57
 
58 58
 static threadpool g_thpool;