Browse code

Disable following symlinks when opening log files

The log module used by clamd and freshclam may follow symlinks.
This is a potential security concern since the log may be owned by
the unprivileged service but may be opened by the service running as
root on startup.

For Windows, we'll define O_NOFOLLOW so the code works, though the issue
does not affect Windows.

Issue reported by Detlef.

Micah Snyder authored on 2024/08/27 03:00:51
Showing 1 changed files
... ...
@@ -58,6 +58,12 @@
58 58
 
59 59
 #include "output.h"
60 60
 
61
+// Define O_NOFOLLOW for systems that don't have it.
62
+// Notably, Windows doesn't have O_NOFOLLOW.
63
+#ifndef O_NOFOLLOW
64
+#define O_NOFOLLOW 0
65
+#endif
66
+
61 67
 #ifdef CL_THREAD_SAFE
62 68
 #include <pthread.h>
63 69
 pthread_mutex_t logg_mutex     = PTHREAD_MUTEX_INITIALIZER;
... ...
@@ -304,7 +310,6 @@ int logg(loglevel_t loglevel, const char *str, ...)
304 304
     char buffer[1025], *abuffer = NULL, *buff;
305 305
     time_t currtime;
306 306
     size_t len;
307
-    mode_t old_umask;
308 307
 #ifdef F_WRLCK
309 308
     struct flock fl;
310 309
 #endif
... ...
@@ -338,18 +343,36 @@ int logg(loglevel_t loglevel, const char *str, ...)
338 338
     logg_open();
339 339
 
340 340
     if (!logg_fp && logg_file) {
341
-        old_umask = umask(0037);
342
-        if ((logg_fp = fopen(logg_file, "at")) == NULL) {
343
-            umask(old_umask);
341
+        int logg_file_fd = -1;
342
+
343
+        logg_file_fd = open(logg_file, O_WRONLY | O_CREAT | O_APPEND | O_NOFOLLOW, 0640);
344
+        if (-1 == logg_file_fd) {
345
+            char errbuf[128];
346
+            cli_strerror(errno, errbuf, sizeof(errbuf));
347
+            printf("ERROR: Failed to open log file %s: %s\n", logg_file, errbuf);
348
+
344 349
 #ifdef CL_THREAD_SAFE
345 350
             pthread_mutex_unlock(&logg_mutex);
346 351
 #endif
347
-            printf("ERROR: Can't open %s in append mode (check permissions!).\n", logg_file);
348
-            if (len > sizeof(buffer))
352
+            if (abuffer)
349 353
                 free(abuffer);
350 354
             return -1;
351
-        } else
352
-            umask(old_umask);
355
+        }
356
+
357
+        logg_fp = fdopen(logg_file_fd, "at");
358
+        if (NULL == logg_fp) {
359
+            char errbuf[128];
360
+            cli_strerror(errno, errbuf, sizeof(errbuf));
361
+            printf("ERROR: Failed to convert the open log file descriptor for %s to a FILE* handle: %s\n", logg_file, errbuf);
362
+
363
+            close(logg_file_fd);
364
+#ifdef CL_THREAD_SAFE
365
+            pthread_mutex_unlock(&logg_mutex);
366
+#endif
367
+            if (abuffer)
368
+                free(abuffer);
369
+            return -1;
370
+        }
353 371
 
354 372
 #ifdef F_WRLCK
355 373
         if (logg_lock) {
... ...
@@ -362,11 +385,16 @@ int logg(loglevel_t loglevel, const char *str, ...)
362 362
                 else
363 363
 #endif
364 364
                 {
365
+                    char errbuf[128];
366
+                    cli_strerror(errno, errbuf, sizeof(errbuf));
367
+                    printf("ERROR: Failed to lock the log file %s: %s\n", logg_file, errbuf);
368
+
365 369
 #ifdef CL_THREAD_SAFE
366 370
                     pthread_mutex_unlock(&logg_mutex);
367 371
 #endif
368
-                    printf("ERROR: %s is locked by another process\n", logg_file);
369
-                    if (len > sizeof(buffer))
372
+                    fclose(logg_fp);
373
+                    logg_fp = NULL;
374
+                    if (abuffer)
370 375
                         free(abuffer);
371 376
                     return -1;
372 377
                 }
... ...
@@ -441,8 +469,9 @@ int logg(loglevel_t loglevel, const char *str, ...)
441 441
     pthread_mutex_unlock(&logg_mutex);
442 442
 #endif
443 443
 
444
-    if (len > sizeof(buffer))
444
+    if (abuffer)
445 445
         free(abuffer);
446
+
446 447
     return 0;
447 448
 }
448 449