Browse code

Fix file access issue if in low privelege process

Removing problematic call to convert file descriptors to filepaths.

Added filename and tempfile names to scandesc calls in clamd.

Added a general scan option to treat the scan engine as unprivileged,
meaning that the scan engine will not have read access to the file.

Added check to drop a temp file for RAR's where the we don't have
read access to the filepath provided (i.e. unprivileged is set, or
access() check fails).

Micah Snyder (micasnyd) authored on 2020/01/24 10:42:33
Showing 6 changed files
... ...
@@ -391,7 +391,7 @@ int scanfd(
391 391
     context.filename = fdstr;
392 392
     context.virsize  = 0;
393 393
     context.scandata = NULL;
394
-    ret              = cl_scandesc_callback(fd, NULL, &virname, scanned, engine, options, &context);
394
+    ret              = cl_scandesc_callback(fd, conn->filename, &virname, scanned, engine, options, &context);
395 395
     thrmgr_setactivetask(NULL, NULL);
396 396
 
397 397
     if (thrmgr_group_need_terminate(conn->group)) {
... ...
@@ -564,7 +564,7 @@ int scanstream(
564 564
         context.filename = peer_addr;
565 565
         context.virsize  = 0;
566 566
         context.scandata = NULL;
567
-        ret              = cl_scandesc_callback(tmpd, NULL, &virname, scanned, engine, options, &context);
567
+        ret              = cl_scandesc_callback(tmpd, tmpname, &virname, scanned, engine, options, &context);
568 568
         thrmgr_setactivetask(NULL, NULL);
569 569
     } else {
570 570
         ret = -1;
... ...
@@ -160,10 +160,11 @@ struct cl_scan_options {
160 160
 };
161 161
 
162 162
 /* general */
163
-#define CL_SCAN_GENERAL_ALLMATCHES                  0x1 /* scan in all-match mode */
164
-#define CL_SCAN_GENERAL_COLLECT_METADATA            0x2 /* collect metadata (--gen-json) */
165
-#define CL_SCAN_GENERAL_HEURISTICS                  0x4 /* option to enable heuristic alerts */
166
-#define CL_SCAN_GENERAL_HEURISTIC_PRECEDENCE        0x8 /* allow heuristic match to take precedence. */
163
+#define CL_SCAN_GENERAL_ALLMATCHES                  0x1  /* scan in all-match mode */
164
+#define CL_SCAN_GENERAL_COLLECT_METADATA            0x2  /* collect metadata (--gen-json) */
165
+#define CL_SCAN_GENERAL_HEURISTICS                  0x4  /* option to enable heuristic alerts */
166
+#define CL_SCAN_GENERAL_HEURISTIC_PRECEDENCE        0x8  /* allow heuristic match to take precedence. */
167
+#define CL_SCAN_GENERAL_UNPRIVILEGED                0x10 /* scanner will not have read access to files. */
167 168
 
168 169
 /* parsing capabilities options */
169 170
 #define CL_SCAN_PARSE_ARCHIVE                       0x1
... ...
@@ -493,6 +493,7 @@ extern int have_rar;
493 493
 #define SCAN_COLLECT_METADATA (ctx->options->general & CL_SCAN_GENERAL_COLLECT_METADATA)
494 494
 #define SCAN_HEURISTICS (ctx->options->general & CL_SCAN_GENERAL_HEURISTICS)
495 495
 #define SCAN_HEURISTIC_PRECEDENCE (ctx->options->general & CL_SCAN_GENERAL_HEURISTIC_PRECEDENCE)
496
+#define SCAN_UNPRIVILEGED (ctx->options->general & CL_SCAN_GENERAL_UNPRIVILEGED)
496 497
 
497 498
 #define SCAN_PARSE_ARCHIVE (ctx->options->parse & CL_SCAN_PARSE_ARCHIVE)
498 499
 #define SCAN_PARSE_ELF (ctx->options->parse & CL_SCAN_PARSE_ELF)
... ...
@@ -276,6 +276,9 @@ static cl_error_t cli_scanrar(const char *filepath, int desc, cli_ctx *ctx)
276 276
         if (unrar_ret == UNRAR_EMEM) {
277 277
             status = CL_EMEM;
278 278
             goto done;
279
+        } else if (unrar_ret == UNRAR_EOPEN) {
280
+            status = CL_EOPEN;
281
+            goto done;
279 282
         } else {
280 283
             status = CL_EFORMAT;
281 284
             goto done;
... ...
@@ -2871,11 +2874,15 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2871 2871
                             cli_set_container(ctx, CL_TYPE_RAR, csize);
2872 2872
                             cli_dbgmsg("RAR/RAR-SFX signature found at %u\n", (unsigned int)fpt->offset);
2873 2873
 
2874
-                            if ((ctx->sub_filepath == NULL) || (fpt->offset != 0)) {
2874
+#ifdef _WIN32
2875
+                            if ((fpt->offset != 0) || (SCAN_UNPRIVILEGED) || (NULL == ctx->sub_filepath) || (0 != _access_s(ctx->sub_filepath, R_OK))) {
2876
+#else
2877
+                            if ((fpt->offset != 0) || (SCAN_UNPRIVILEGED) || (NULL == ctx->sub_filepath) || (0 != access(ctx->sub_filepath, R_OK))) {
2878
+#endif
2875 2879
                                 /*
2876
-                             * If map is not file-backed, or offset is not at the start of the file...
2877
-                             * ...have to dump to file for scanrar.
2878
-                             */
2880
+                                 * If map is not file-backed, or offset is not at the start of the file...
2881
+                                 * ...have to dump to file for scanrar.
2882
+                                 */
2879 2883
                                 nret = fmap_dump_to_file(map, ctx->sub_filepath, ctx->engine->tmpdir, &tmpname, &tmpfd, fpt->offset, fpt->offset + csize);
2880 2884
                                 if (nret != CL_SUCCESS) {
2881 2885
                                     cli_dbgmsg("cli_scanraw: failed to generate temporary file.\n");
... ...
@@ -2894,6 +2901,25 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
2894 2894
                             /* scan file */
2895 2895
                             nret = cli_scanrar(filepath, fd, ctx);
2896 2896
 
2897
+                            if ((NULL == tmpname) && (CL_EOPEN == nret)) {
2898
+                                /*
2899
+                                 * Failed to open the file using the original filename.
2900
+                                 * Try writing the file descriptor to a temp file and try again.
2901
+                                 */
2902
+                                nret = fmap_dump_to_file(map, ctx->sub_filepath, ctx->engine->tmpdir, &tmpname, &tmpfd, fpt->offset, fpt->offset + csize);
2903
+                                if (nret != CL_SUCCESS) {
2904
+                                    cli_dbgmsg("cli_scanraw: failed to generate temporary file.\n");
2905
+                                    ret        = nret;
2906
+                                    break_loop = 1;
2907
+                                    break;
2908
+                                }
2909
+                                filepath = tmpname;
2910
+                                fd       = tmpfd;
2911
+
2912
+                                /* try to scan again */
2913
+                                nret = cli_scanrar(filepath, fd, ctx);
2914
+                            }
2915
+
2897 2916
                             if (tmpfd != -1) {
2898 2917
                                 /* If dumped tempfile, need to cleanup */
2899 2918
                                 close(tmpfd);
... ...
@@ -3521,7 +3547,11 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
3521 3521
                 char *tmpname = NULL;
3522 3522
                 int tmpfd     = -1;
3523 3523
 
3524
-                if (ctx->sub_filepath == NULL) {
3524
+#ifdef _WIN32
3525
+                if ((SCAN_UNPRIVILEGED) || (NULL == ctx->sub_filepath) || (0 != _access_s(ctx->sub_filepath, R_OK))) {
3526
+#else
3527
+                if ((SCAN_UNPRIVILEGED) || (NULL == ctx->sub_filepath) || (0 != access(ctx->sub_filepath, R_OK))) {
3528
+#endif
3525 3529
                     /* If map is not file-backed have to dump to file for scanrar. */
3526 3530
                     ret = fmap_dump_to_file(*ctx->fmap, ctx->sub_filepath, ctx->engine->tmpdir, &tmpname, &tmpfd, 0, SIZE_MAX);
3527 3531
                     if (ret != CL_SUCCESS) {
... ...
@@ -3539,6 +3569,23 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type)
3539 3539
                 /* scan file */
3540 3540
                 ret = cli_scanrar(filepath, fd, ctx);
3541 3541
 
3542
+                if ((NULL == tmpname) && (CL_EOPEN == ret)) {
3543
+                    /*
3544
+                     * Failed to open the file using the original filename.
3545
+                     * Try writing the file descriptor to a temp file and try again.
3546
+                     */
3547
+                    ret = fmap_dump_to_file(*ctx->fmap, ctx->sub_filepath, ctx->engine->tmpdir, &tmpname, &tmpfd, 0, SIZE_MAX);
3548
+                    if (ret != CL_SUCCESS) {
3549
+                        cli_dbgmsg("cli_scanraw: failed to generate temporary file.\n");
3550
+                        break;
3551
+                    }
3552
+                    filepath = tmpname;
3553
+                    fd       = tmpfd;
3554
+
3555
+                    /* try to scan again */
3556
+                    ret = cli_scanrar(filepath, fd, ctx);
3557
+                }
3558
+
3542 3559
                 if (tmpfd != -1) {
3543 3560
                     /* If dumped tempfile, need to cleanup */
3544 3561
                     close(tmpfd);
... ...
@@ -4265,17 +4312,7 @@ static cl_error_t scan_common(int desc, cl_fmap_t *map, const char *filepath, co
4265 4265
         }
4266 4266
     }
4267 4267
 
4268
-    /* Best effort to determine the filename if not provided.
4269
-     * May still be NULL if filename could not be determined. */
4270
-    if (filepath == NULL) {
4271
-        char *fpath = NULL;
4272
-
4273
-        if (desc >= 0) {
4274
-            (void)cli_get_filepath_from_filedesc(desc, &fpath);
4275
-        }
4276
-
4277
-        ctx.target_filepath = fpath;
4278
-    } else {
4268
+    if (filepath != NULL) {
4279 4269
         ctx.target_filepath = strdup(filepath);
4280 4270
     }
4281 4271
 
... ...
@@ -135,6 +135,7 @@ static cl_unrar_error_t unrar_retcode(int retcode)
135 135
         }
136 136
         case ERAR_EOPEN: {
137 137
             unrar_dbgmsg("unrar_retcode: Volume open error.\n");
138
+            status = UNRAR_EOPEN;
138 139
             break;
139 140
         }
140 141
         case ERAR_ECREATE: {
... ...
@@ -50,7 +50,8 @@ typedef enum cl_unrar_error_tag {
50 50
     UNRAR_BREAK,
51 51
     UNRAR_ENCRYPTED,
52 52
     UNRAR_EMEM,
53
-    UNRAR_ERR
53
+    UNRAR_ERR,
54
+    UNRAR_EOPEN
54 55
 } cl_unrar_error_t;
55 56
 
56 57
 typedef struct unrar_metadata_tag {