Browse code

clamd: log the file name when using fd-passing

This improvement looks up the filename given the file descriptor.
This is supported on Mac and Linux but not presently supported
on other UNIX operating systems. FD-passing is not available on
Windows.

On supported systems, the verdict in the clamd log and the VirusEvent
will show the actual file path instead of something like fd[14].

Micah Snyder (micasnyd) authored on 2021/01/26 13:35:49
Showing 5 changed files
... ...
@@ -23,6 +23,13 @@ ClamAV 0.103.1 is a bug patch release to address the following issues.
23 23
 
24 24
 - Fixed freshclam --on-update-execute=EXIT_1 temporary directory cleanup issue.
25 25
 
26
+- `clamd`'s log output and VirusEvent now provide the scan target's file path
27
+  instead of a file descriptor. The clamd socket API for submitting a scan by
28
+  FD-passing doesn't include a file path, this feature works by looking up the
29
+  file path by file descriptor. This feature works on Mac and Linux but is not
30
+  yet implemented for other UNIX operating systems.
31
+  FD-passing is not available for Windows.
32
+
26 33
 ### Acknowledgements
27 34
 
28 35
 The ClamAV team thanks the following individuals for their code submissions:
... ...
@@ -364,7 +364,7 @@ int scan_pathchk(const char *path, struct cli_ftw_cbdata *data)
364 364
     return 0;
365 365
 }
366 366
 
367
-int scanfd(
367
+cl_error_t scanfd(
368 368
     const client_conn_t *conn,
369 369
     unsigned long int *scanned,
370 370
     const struct cl_engine *engine,
... ...
@@ -373,13 +373,17 @@ int scanfd(
373 373
     int odesc,
374 374
     int stream)
375 375
 {
376
-    int ret, fd = conn->scanfd;
376
+    cl_error_t ret      = -1;
377
+    int fd              = conn->scanfd;
377 378
     const char *virname = NULL;
378 379
     STATBUF statbuf;
379 380
     struct cb_context context;
380 381
     char fdstr[32];
381 382
     const char *reply_fdstr;
382 383
 
384
+    char *filepath     = NULL;
385
+    char *log_filename = fdstr;
386
+
383 387
     UNUSEDPARAM(odesc);
384 388
 
385 389
     if (stream) {
... ...
@@ -396,41 +400,60 @@ int scanfd(
396 396
     }
397 397
     if (FSTAT(fd, &statbuf) == -1 || !S_ISREG(statbuf.st_mode)) {
398 398
         logg("%s: Not a regular file. ERROR\n", fdstr);
399
-        if (conn_reply(conn, reply_fdstr, "Not a regular file", "ERROR") == -1)
400
-            return CL_ETIMEOUT;
401
-        return -1;
399
+        if (conn_reply(conn, reply_fdstr, "Not a regular file", "ERROR") == -1) {
400
+            ret = CL_ETIMEOUT;
401
+            goto done;
402
+        }
403
+        ret = CL_BREAK;
404
+        goto done;
405
+    }
406
+
407
+    /* Try and get the real filename, for logging purposes */
408
+    if (!stream) {
409
+        if (CL_SUCCESS != cli_get_filepath_from_filedesc(fd, &filepath)) {
410
+            logg("*%s: Unable to determine the filepath given the file descriptor.\n", fdstr);
411
+        } else {
412
+            log_filename = filepath;
413
+        }
402 414
     }
403 415
 
404 416
     thrmgr_setactivetask(fdstr, NULL);
405 417
     context.filename = fdstr;
406 418
     context.virsize  = 0;
407 419
     context.scandata = NULL;
408
-    ret              = cl_scandesc_callback(fd, conn->filename, &virname, scanned, engine, options, &context);
420
+    ret              = cl_scandesc_callback(fd, log_filename, &virname, scanned, engine, options, &context);
409 421
     thrmgr_setactivetask(NULL, NULL);
410 422
 
411 423
     if (thrmgr_group_need_terminate(conn->group)) {
412 424
         logg("*Client disconnected while scanjob was active\n");
413
-        return ret == CL_ETIMEOUT ? ret : CL_BREAK;
425
+        ret = ret == CL_ETIMEOUT ? ret : CL_BREAK;
426
+        goto done;
414 427
     }
415 428
 
416 429
     if (ret == CL_VIRUS) {
417 430
         if (conn_reply_virus(conn, reply_fdstr, virname) == -1)
418 431
             ret = CL_ETIMEOUT;
419 432
         if (context.virsize && optget(opts, "ExtendedDetectionInfo")->enabled)
420
-            logg("%s: %s(%s:%llu) FOUND\n", fdstr, virname, context.virhash, context.virsize);
433
+            logg("%s: %s(%s:%llu) FOUND\n", log_filename, virname, context.virhash, context.virsize);
421 434
         else
422
-            logg("%s: %s FOUND\n", fdstr, virname);
423
-        virusaction(reply_fdstr, virname, opts);
435
+            logg("%s: %s FOUND\n", log_filename, virname);
436
+        virusaction(log_filename, virname, opts);
424 437
     } else if (ret != CL_CLEAN) {
425 438
         if (conn_reply(conn, reply_fdstr, cl_strerror(ret), "ERROR") == -1)
426 439
             ret = CL_ETIMEOUT;
427
-        logg("%s: %s ERROR\n", fdstr, cl_strerror(ret));
440
+        logg("%s: %s ERROR\n", log_filename, cl_strerror(ret));
428 441
     } else {
429 442
         if (conn_reply_single(conn, reply_fdstr, "OK") == CL_ETIMEOUT)
430 443
             ret = CL_ETIMEOUT;
431 444
         if (logok)
432
-            logg("%s: OK\n", fdstr);
445
+            logg("%s: OK\n", log_filename);
433 446
     }
447
+
448
+done:
449
+    if (NULL != filepath) {
450
+        free(filepath);
451
+    }
452
+
434 453
     return ret;
435 454
 }
436 455
 
... ...
@@ -65,7 +65,7 @@ struct cb_context {
65 65
     struct scan_cb_data *scandata;
66 66
 };
67 67
 
68
-int scanfd(const client_conn_t *conn, unsigned long int *scanned, const struct cl_engine *engine, struct cl_scan_options *options, const struct optstruct *opts, int odesc, int stream);
68
+cl_error_t scanfd(const client_conn_t *conn, unsigned long int *scanned, const struct cl_engine *engine, struct cl_scan_options *options, const struct optstruct *opts, int odesc, int stream);
69 69
 int scanstream(int odesc, unsigned long int *scanned, const struct cl_engine *engine, struct cl_scan_options *options, const struct optstruct *opts, char term);
70 70
 cl_error_t scan_callback(STATBUF *sb, char *filename, const char *msg, enum cli_ftw_reason reason, struct cli_ftw_cbdata *data);
71 71
 int scan_pathchk(const char *path, struct cli_ftw_cbdata *data);
... ...
@@ -262,6 +262,7 @@ CLAMAV_PRIVATE {
262 262
     cli_basename;
263 263
     cli_realpath;
264 264
     cli_codepage_to_utf8;
265
+    cli_get_filepath_from_filedesc;
265 266
 
266 267
     __cli_strcasestr;
267 268
     __cli_strndup;
... ...
@@ -188,6 +188,7 @@ EXPORTS __cli_strnlen @44390 NONAME
188 188
 EXPORTS __cli_strnstr @44391 NONAME
189 189
 EXPORTS cli_gentemp_with_prefix @44392 NONAME
190 190
 EXPORTS cli_basename @44393 NONAME
191
+EXPORTS cli_get_filepath_from_filedesc @44394 NONAME
191 192
 
192 193
 ; compatibility layer, tommath, zlib
193 194
 EXPORTS w32_srand @44269 NONAME
... ...
@@ -270,4 +271,4 @@ EXPORTS cli_sigperf_events_destroy @44350 NONAME
270 270
 EXPORTS cli_cache_init @44351 NONAME
271 271
 EXPORTS cli_cache_destroy @44352 NONAME
272 272
 EXPORTS cli_strntoul @44353 NONAME
273
-EXPORTS cli_realpath @44354 NONAME
274 273
\ No newline at end of file
274
+EXPORTS cli_realpath @44354 NONAME