From 3b269a5e6d0901adc58ce27b9eae51deba679788 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= Date: Wed, 23 Oct 2019 17:30:19 +0200 Subject: [PATCH] Use and return canonical paths in rpmverifyfile probe This is done to prevent false positives in implementation of rules file_permissions_unauthorized_suid and file_permissions_unauthorized_sgid proposed in ComplianceAsCode in https://github.com/ComplianceAsCode/content/pull/4648 caused by inconsistent symlink usage in rpmdb. Also improves logic when an exact file path is defined in rpmverifyfile_object we don't have to iterate over all RPMs in the rpmdb but we query the rpmdb directly. --- src/OVAL/probes/unix/linux/rpmverifyfile.c | 45 ++++++++++++++++------ 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/src/OVAL/probes/unix/linux/rpmverifyfile.c b/src/OVAL/probes/unix/linux/rpmverifyfile.c index c13e3a629..e17f1612b 100644 --- a/src/OVAL/probes/unix/linux/rpmverifyfile.c +++ b/src/OVAL/probes/unix/linux/rpmverifyfile.c @@ -137,6 +137,7 @@ static int rpmverify_collect(probe_ctx *ctx, Header pkgh; pcre *re = NULL; int ret = -1; + char *file_realpath = NULL; /* pre-compile regex if needed */ if (file_op == OVAL_OPERATION_PATTERN_MATCH) { @@ -153,7 +154,16 @@ static int rpmverify_collect(probe_ctx *ctx, RPMVERIFY_LOCK; - match = rpmtsInitIterator (g_rpm.rpmts, RPMDBI_PACKAGES, NULL, 0); + if (file != NULL && file_op == OVAL_OPERATION_EQUALS) { + /* + * When we know the exact file path we look for, we don't need to + * filter all RPM packages, but we can ask the rpmdb directly for + * the package which provides this file, similar to `rpm -q -f`. + */ + match = rpmtsInitIterator(g_rpm.rpmts, RPMDBI_INSTFILENAMES, file, 0); + } else { + match = rpmtsInitIterator(g_rpm.rpmts, RPMDBI_PACKAGES, NULL, 0); + } if (match == NULL) { ret = 0; goto ret; @@ -183,6 +193,8 @@ static int rpmverify_collect(probe_ctx *ctx, assume_d(RPMTAG_BASENAMES != 0, -1); assume_d(RPMTAG_DIRNAMES != 0, -1); + file_realpath = realpath(file, NULL); + while ((pkgh = rpmdbNextIterator (match)) != NULL) { SEXP_t *ent; rpmfi fi; @@ -190,6 +202,8 @@ static int rpmverify_collect(probe_ctx *ctx, struct rpmverify_res res; errmsg_t rpmerr; int i; + const char *current_file; + char *current_file_realpath; /* +SEXP_t *probe_ent_from_cstr(const char *name, oval_datatype_t type, @@ -231,43 +245,51 @@ static int rpmverify_collect(probe_ctx *ctx, fi = rpmfiNew(g_rpm.rpmts, pkgh, tag[i], 1); while (rpmfiNext(fi) != -1) { - res.file = oscap_strdup(rpmfiFN(fi)); + current_file = rpmfiFN(fi); + current_file_realpath = realpath(current_file, NULL); res.fflags = rpmfiFFlags(fi); res.oflags = omit; if (((res.fflags & RPMFILE_CONFIG) && (flags & RPMVERIFY_SKIP_CONFIG)) || ((res.fflags & RPMFILE_GHOST) && (flags & RPMVERIFY_SKIP_GHOST))) { - free(res.file); + free(current_file_realpath); continue; } switch(file_op) { case OVAL_OPERATION_EQUALS: - if (strcmp(res.file, file) != 0) { - free(res.file); + if (strcmp(current_file, file) != 0 && + current_file_realpath && file_realpath && + strcmp(current_file_realpath, file_realpath) != 0) { + free(current_file_realpath); continue; } + res.file = oscap_strdup(file); break; case OVAL_OPERATION_NOT_EQUAL: - if (strcmp(res.file, file) == 0) { - free(res.file); + if (strcmp(current_file, file) == 0 || + (current_file_realpath && file_realpath && + strcmp(current_file_realpath, file_realpath) == 0)) { + free(current_file_realpath); continue; } + res.file = current_file_realpath ? current_file_realpath : strdup(current_file); break; case OVAL_OPERATION_PATTERN_MATCH: - ret = pcre_exec(re, NULL, res.file, strlen(res.file), 0, 0, NULL, 0); + ret = pcre_exec(re, NULL, current_file, strlen(current_file), 0, 0, NULL, 0); switch(ret) { case 0: /* match */ + res.file = strdup(current_file); break; case -1: /* mismatch */ - free(res.file); + free(current_file_realpath); continue; default: dE("pcre_exec() failed!"); ret = -1; - free(res.file); + free(current_file_realpath); goto ret; } break; @@ -275,7 +297,7 @@ static int rpmverify_collect(probe_ctx *ctx, /* unsupported operation */ dE("Operation \"%d\" on `filepath' not supported", file_op); ret = -1; - free(res.file); + free(current_file_realpath); goto ret; } @@ -301,6 +323,7 @@ ret: pcre_free(re); RPMVERIFY_UNLOCK; + free(file_realpath); return (ret); } -- 2.21.0