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.
| ... | ... |
@@ -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 |
|