summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2023-04-10 20:33:24 +0300
committerTimo Teräs <timo.teras@iki.fi>2023-04-11 20:55:13 +0300
commit67c0583a5e18c27880e2785536be3e66ff1c4bdd (patch)
treeead75e2bb978646cc87184137f85f55470477d51
parentf514cfe6aa8b50c60c61e3f23ec3ac174661fd6b (diff)
downloadapk-tools-67c0583a5e18c27880e2785536be3e66ff1c4bdd.tar.gz
apk-tools-67c0583a5e18c27880e2785536be3e66ff1c4bdd.tar.bz2
apk-tools-67c0583a5e18c27880e2785536be3e66ff1c4bdd.tar.xz
apk-tools-67c0583a5e18c27880e2785536be3e66ff1c4bdd.zip
audit: implement detail records
-rw-r--r--doc/apk-audit.8.scd21
-rw-r--r--src/app_audit.c74
2 files changed, 67 insertions, 28 deletions
diff --git a/doc/apk-audit.8.scd b/doc/apk-audit.8.scd
index 70bd667..52e8733 100644
--- a/doc/apk-audit.8.scd
+++ b/doc/apk-audit.8.scd
@@ -13,17 +13,21 @@ apk audit - audit directories for changes
*apk audit* audits the system or specified directories for changes compared to
the package database.
-The audit can be done against configuration files only (--backup) to generate
+The audit can be done against configuration files only (*--backup*) to generate
list of files needed to be stored in the overlay in run-from-tmps configuration.
-Alternatively, it can audit all installed files (--system or --full) to
+Alternatively, it can audit all installed files (*--system* or *--full*) to
e.g. detect unauthorized modifications of system files.
By default, the output format is one file per line, for each modified file.
-A character is printed indicating the change detected, followed by a space,
-then the affected path. The changes detected are:
-
-|[ A
-:< File added
+A character is printed indicating the line type, followed by a space,
+then the affected path or details. The changes detected are:
+
+|[ -
+:< Database detail record
+| \+
+: On-disk detail record
+| A
+: File added
| d
: Directory added
| D
@@ -51,6 +55,9 @@ then the affected path. The changes detected are:
Check file permissions too. Namely, the uid, gid and file mode will
be checked in addition to the file content.
+*--details*
+ Enable reporting of detail records.
+
*--full*
Audit all system files. Same as *--system*, but in addition reports
all added directories and files. A built-in default override for
diff --git a/src/app_audit.c b/src/app_audit.c
index 52dbc73..694d8b5 100644
--- a/src/app_audit.c
+++ b/src/app_audit.c
@@ -35,11 +35,13 @@ struct audit_ctx {
unsigned check_permissions : 1;
unsigned packages_only : 1;
unsigned ignore_busybox_symlinks : 1;
+ unsigned details : 1;
};
#define AUDIT_OPTIONS(OPT) \
OPT(OPT_AUDIT_backup, "backup") \
OPT(OPT_AUDIT_check_permissions, "check-permissions") \
+ OPT(OPT_AUDIT_details, "details") \
OPT(OPT_AUDIT_full, "full") \
OPT(OPT_AUDIT_ignore_busybox_symlinks, "ignore-busybox-symlinks") \
OPT(OPT_AUDIT_packages, "packages") \
@@ -82,6 +84,9 @@ static int option_parse_applet(void *ctx, struct apk_db_options *dbopts, int opt
case OPT_AUDIT_check_permissions:
actx->check_permissions = 1;
break;
+ case OPT_AUDIT_details:
+ actx->details = 1;
+ break;
case OPT_AUDIT_ignore_busybox_symlinks:
actx->ignore_busybox_symlinks = 1;
break;
@@ -120,9 +125,9 @@ struct audit_tree_ctx {
static int audit_file(struct audit_ctx *actx,
struct apk_database *db,
struct apk_db_file *dbf,
- int dirfd, const char *name)
+ int dirfd, const char *name,
+ struct apk_file_info *fi)
{
- struct apk_file_info fi;
int rv = 0;
if (!dbf) return 'A';
@@ -131,24 +136,23 @@ static int audit_file(struct audit_ctx *actx,
APK_FI_NOFOLLOW |
APK_FI_XATTR_CSUM(dbf->acl->xattr_csum.type ?: APK_CHECKSUM_DEFAULT) |
APK_FI_CSUM(dbf->csum.type),
- &fi, &db->atoms) != 0)
+ fi, &db->atoms) != 0)
return 'e';
if (dbf->csum.type != APK_CHECKSUM_NONE &&
- apk_checksum_compare(&fi.csum, &dbf->csum) != 0)
+ apk_checksum_compare(&fi->csum, &dbf->csum) != 0)
rv = 'U';
- else if (!S_ISLNK(fi.mode) && !dbf->diri->pkg->ipkg->broken_xattr &&
- apk_checksum_compare(&fi.xattr_csum, &dbf->acl->xattr_csum) != 0)
+ else if (!S_ISLNK(fi->mode) && !dbf->diri->pkg->ipkg->broken_xattr &&
+ apk_checksum_compare(&fi->xattr_csum, &dbf->acl->xattr_csum) != 0)
rv = 'x';
- else if (S_ISLNK(fi.mode) && dbf->csum.type == APK_CHECKSUM_NONE)
+ else if (S_ISLNK(fi->mode) && dbf->csum.type == APK_CHECKSUM_NONE)
rv = 'U';
else if (actx->check_permissions) {
- if ((fi.mode & 07777) != (dbf->acl->mode & 07777))
+ if ((fi->mode & 07777) != (dbf->acl->mode & 07777))
rv = 'M';
- else if (fi.uid != dbf->acl->uid || fi.gid != dbf->acl->gid)
+ else if (fi->uid != dbf->acl->uid || fi->gid != dbf->acl->gid)
rv = 'M';
}
- apk_fileinfo_free(&fi);
return rv;
}
@@ -174,15 +178,29 @@ static int audit_directory(struct audit_ctx *actx,
return 0;
}
+static const char *format_checksum(const apk_blob_t csum, apk_blob_t b)
+{
+ const char *ret = b.ptr;
+ if (csum.len == 0) return "";
+ apk_blob_push_blob(&b, APK_BLOB_STR(" hash="));
+ apk_blob_push_hexdump(&b, csum);
+ apk_blob_push_blob(&b, APK_BLOB_PTR_LEN("", 1));
+ return ret;
+}
+
static void report_audit(struct audit_ctx *actx,
- char reason, apk_blob_t bfull, struct apk_package *pkg)
+ char reason, apk_blob_t bfull,
+ struct apk_db_dir *dir,
+ struct apk_db_file *file,
+ struct apk_file_info *fi)
{
- if (!reason)
- return;
+ struct apk_package *pkg = file ? file->diri->pkg : NULL;
+ char csum_buf[8+APK_BLOB_CHECKSUM_BUF];
+
+ if (!reason) return;
if (actx->packages_only) {
- if (pkg == NULL || pkg->state_int != 0)
- return;
+ if (!pkg || pkg->state_int != 0) return;
pkg->state_int = 1;
if (apk_verbosity < 1)
printf("%s\n", pkg->name->name);
@@ -190,8 +208,21 @@ static void report_audit(struct audit_ctx *actx,
printf(PKG_VER_FMT "\n", PKG_VER_PRINTF(pkg));
} else if (apk_verbosity < 1) {
printf(BLOB_FMT "\n", BLOB_PRINTF(bfull));
- } else
+ } else {
+ if (actx->details) {
+ if (file)
+ printf("- mode=%o uid=%d gid=%d%s\n",
+ file->acl->mode & 07777, file->acl->uid, file->acl->gid,
+ format_checksum(APK_BLOB_CSUM(file->csum), APK_BLOB_BUF(csum_buf)));
+ else if (dir && reason != 'D' && reason != 'd')
+ printf("- mode=%o uid=%d gid=%d\n",
+ dir->mode & 07777, dir->uid, dir->gid);
+ if (fi) printf("+ mode=%o uid=%d gid=%d%s\n",
+ fi->mode & 07777, fi->uid, fi->gid,
+ format_checksum(APK_BLOB_CSUM(fi->csum), APK_BLOB_BUF(csum_buf)));
+ }
printf("%c " BLOB_FMT "\n", reason, BLOB_PRINTF(bfull));
+ }
}
static int determine_file_protect_mode(struct apk_db_dir *dir, const char *name)
@@ -233,7 +264,7 @@ static int audit_directory_tree_item(void *ctx, int dirfd, const char *name)
if (apk_fileinfo_get(dirfd, name, APK_FI_NOFOLLOW, &fi, &db->atoms) < 0) {
dbf = apk_db_file_query(db, bdir, bent);
if (dbf) dbf->audited = 1;
- report_audit(actx, 'e', bfull, dbf ? dbf->diri->pkg : NULL);
+ report_audit(actx, 'e', bfull, NULL, dbf, NULL);
goto done;
}
@@ -264,7 +295,7 @@ static int audit_directory_tree_item(void *ctx, int dirfd, const char *name)
recurse_check:
atctx->path[atctx->pathlen++] = '/';
bfull.len++;
- report_audit(actx, reason, bfull, NULL);
+ report_audit(actx, reason, bfull, dir, NULL, &fi);
if (reason != 'D' && recurse) {
atctx->dir = child;
reason = apk_dir_foreach_file(
@@ -326,8 +357,9 @@ recurse_check:
if (n == 11 && memcmp(target, "/bin/bbsuid", 11) == 0)
goto done;
}
- if (!reason) reason = audit_file(actx, db, dbf, dirfd, name);
- report_audit(actx, reason, bfull, dbf ? dbf->diri->pkg : NULL);
+ if (!reason) reason = audit_file(actx, db, dbf, dirfd, name, &fi);
+ report_audit(actx, reason, bfull, NULL, dbf, &fi);
+ apk_fileinfo_free(&fi);
}
done:
@@ -370,7 +402,7 @@ static int audit_missing_files(apk_hash_item item, void *pctx)
if (determine_file_protect_mode(dir, file->name) == APK_PROTECT_IGNORE) return 0;
len = snprintf(path, sizeof(path), DIR_FILE_FMT, DIR_FILE_PRINTF(dir, file));
- report_audit(actx, 'X', APK_BLOB_PTR_LEN(path, len), file->diri->pkg);
+ report_audit(actx, 'X', APK_BLOB_PTR_LEN(path, len), NULL, file, NULL);
return 0;
}