From 83ab02230115eab725bf92f111f4a3f2a41db5b1 Mon Sep 17 00:00:00 2001 From: Timo Teräs Date: Wed, 8 Apr 2015 10:25:44 +0300 Subject: audit xattrs ref #3027 --- src/apk_io.h | 2 ++ src/audit.c | 28 ++++++++++------- src/io.c | 98 +++++++++++++++++++++++++++++++++++++++++++----------------- 3 files changed, 90 insertions(+), 38 deletions(-) diff --git a/src/apk_io.h b/src/apk_io.h index ee81851..6e2e37c 100644 --- a/src/apk_io.h +++ b/src/apk_io.h @@ -149,6 +149,8 @@ apk_blob_t apk_blob_from_file(int atfd, const char *file); int apk_blob_to_file(int atfd, const char *file, apk_blob_t b, unsigned int flags); #define APK_FI_NOFOLLOW 0x80000000 +#define APK_FI_XATTR_CSUM(x) (((x) & 0xff) << 8) +#define APK_FI_CSUM(x) (((x) & 0xff)) int apk_fileinfo_get(int atfd, const char *filename, unsigned int flags, struct apk_file_info *fi); void apk_fileinfo_hash_xattr(struct apk_file_info *fi); diff --git a/src/audit.c b/src/audit.c index 3bc525b..cb295b8 100644 --- a/src/audit.c +++ b/src/audit.c @@ -93,30 +93,36 @@ static int audit_file(struct audit_ctx *actx, int dirfd, const char *name) { struct apk_file_info fi; + int rv = 0; if (dbf == NULL) return 'A'; dbf->audited = 1; - if (apk_fileinfo_get(dirfd, name, APK_FI_NOFOLLOW | dbf->csum.type, &fi) != 0) + if (apk_fileinfo_get(dirfd, name, + APK_FI_NOFOLLOW | + APK_FI_XATTR_CSUM(dbf->acl->xattr_csum.type ?: APK_CHECKSUM_DEFAULT) | + APK_FI_CSUM(dbf->csum.type), + &fi) != 0) return -EPERM; if (dbf->csum.type != APK_CHECKSUM_NONE && apk_checksum_compare(&fi.csum, &dbf->csum) != 0) - return 'U'; - - if (S_ISLNK(fi.mode) && dbf->csum.type == APK_CHECKSUM_NONE) - return 'U'; - - if (actx->check_permissions) { + rv = 'U'; + else if (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) + rv = 'U'; + else if (actx->check_permissions) { if ((fi.mode & 07777) != (dbf->acl->mode & 07777)) - return 'M'; - if (fi.uid != dbf->acl->uid || fi.gid != dbf->acl->gid) - return 'M'; + rv = 'M'; + else if (fi.uid != dbf->acl->uid || fi.gid != dbf->acl->gid) + rv = 'M'; } + apk_fileinfo_free(&fi); - return 0; + return rv; } static int audit_directory(struct audit_ctx *actx, diff --git a/src/io.c b/src/io.c index 8a23bb4..5debb5f 100644 --- a/src/io.c +++ b/src/io.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -543,26 +544,30 @@ static void hash_len_data(EVP_MD_CTX *ctx, uint32_t len, const void *ptr) EVP_DigestUpdate(ctx, ptr, len); } -void apk_fileinfo_hash_xattr(struct apk_file_info *fi) +void apk_fileinfo_hash_xattr_array(struct apk_xattr_array *xattrs, const EVP_MD *md, struct apk_checksum *csum) { struct apk_xattr *xattr; - const EVP_MD *md = apk_checksum_default(); EVP_MD_CTX mdctx; - if (!fi->xattrs || fi->xattrs->num == 0) { - fi->xattr_csum.type = APK_CHECKSUM_NONE; + if (!xattrs || xattrs->num == 0) { + csum->type = APK_CHECKSUM_NONE; return; } - qsort(fi->xattrs->item, fi->xattrs->num, sizeof(fi->xattrs->item[0]), cmp_xattr); + qsort(xattrs->item, xattrs->num, sizeof(xattrs->item[0]), cmp_xattr); EVP_DigestInit(&mdctx, md); - foreach_array_item(xattr, fi->xattrs) { + foreach_array_item(xattr, xattrs) { hash_len_data(&mdctx, strlen(xattr->name), xattr->name); hash_len_data(&mdctx, xattr->value.len, xattr->value.ptr); } - fi->xattr_csum.type = EVP_MD_CTX_size(&mdctx); - EVP_DigestFinal(&mdctx, fi->xattr_csum.data, NULL); + csum->type = EVP_MD_CTX_size(&mdctx); + EVP_DigestFinal(&mdctx, csum->data, NULL); +} + +void apk_fileinfo_hash_xattr(struct apk_file_info *fi) +{ + apk_fileinfo_hash_xattr_array(fi->xattrs, apk_checksum_default(), &fi->xattr_csum); } int apk_fileinfo_get(int atfd, const char *filename, unsigned int flags, @@ -570,7 +575,9 @@ int apk_fileinfo_get(int atfd, const char *filename, unsigned int flags, { struct stat64 st; struct apk_bstream *bs; - int checksum = flags & 0xffff, atflags = 0; + unsigned int checksum = flags & 0xff; + unsigned int xattr_checksum = (flags >> 8) & 0xff; + int atflags = 0; if (flags & APK_FI_NOFOLLOW) atflags |= AT_SYMLINK_NOFOLLOW; @@ -587,9 +594,47 @@ int apk_fileinfo_get(int atfd, const char *filename, unsigned int flags, .device = st.st_dev, }; - if (checksum == APK_CHECKSUM_NONE || S_ISDIR(st.st_mode)) + if (xattr_checksum != APK_CHECKSUM_NONE) { + ssize_t len, vlen; + int fd, i, r; + char val[1024], buf[1024]; + + r = 0; + fd = openat(atfd, filename, O_RDONLY); + if (fd >= 0) { + len = flistxattr(fd, buf, sizeof(buf)); + if (len > 0) { + struct apk_xattr_array *xattrs = NULL; + apk_xattr_array_init(&xattrs); + for (i = 0; i < len; i += strlen(&buf[i]) + 1) { + vlen = fgetxattr(fd, &buf[i], val, sizeof(val)); + if (vlen < 0) { + r = errno; + if (r == ENODATA) continue; + break; + } + *apk_xattr_array_add(&xattrs) = (struct apk_xattr) { + .name = &buf[i], + .value = *apk_blob_atomize_dup(APK_BLOB_PTR_LEN(val, vlen)), + }; + } + apk_fileinfo_hash_xattr_array(xattrs, apk_checksum_evp(xattr_checksum), &fi->xattr_csum); + apk_xattr_array_free(&xattrs); + } else r = errno; + close(fd); + } else r = errno; + + if (r && r != ENOTSUP) return -r; + + } + + if (checksum == APK_CHECKSUM_NONE) + return 0; + + if (S_ISDIR(st.st_mode)) return 0; + /* Checksum file content */ if ((flags & APK_FI_NOFOLLOW) && S_ISLNK(st.st_mode)) { char *target = alloca(st.st_size); if (target == NULL) @@ -600,23 +645,22 @@ int apk_fileinfo_get(int atfd, const char *filename, unsigned int flags, EVP_Digest(target, st.st_size, fi->csum.data, NULL, apk_checksum_evp(checksum), NULL); fi->csum.type = checksum; - return 0; - } - - bs = apk_bstream_from_file(atfd, filename); - if (!IS_ERR_OR_NULL(bs)) { - EVP_MD_CTX mdctx; - apk_blob_t blob; - - EVP_DigestInit(&mdctx, apk_checksum_evp(checksum)); - if (bs->flags & APK_BSTREAM_SINGLE_READ) - EVP_MD_CTX_set_flags(&mdctx, EVP_MD_CTX_FLAG_ONESHOT); - while (!APK_BLOB_IS_NULL(blob = bs->read(bs, APK_BLOB_NULL))) - EVP_DigestUpdate(&mdctx, (void*) blob.ptr, blob.len); - fi->csum.type = EVP_MD_CTX_size(&mdctx); - EVP_DigestFinal(&mdctx, fi->csum.data, NULL); - - bs->close(bs, NULL); + } else { + bs = apk_bstream_from_file(atfd, filename); + if (!IS_ERR_OR_NULL(bs)) { + EVP_MD_CTX mdctx; + apk_blob_t blob; + + EVP_DigestInit(&mdctx, apk_checksum_evp(checksum)); + if (bs->flags & APK_BSTREAM_SINGLE_READ) + EVP_MD_CTX_set_flags(&mdctx, EVP_MD_CTX_FLAG_ONESHOT); + while (!APK_BLOB_IS_NULL(blob = bs->read(bs, APK_BLOB_NULL))) + EVP_DigestUpdate(&mdctx, (void*) blob.ptr, blob.len); + fi->csum.type = EVP_MD_CTX_size(&mdctx); + EVP_DigestFinal(&mdctx, fi->csum.data, NULL); + + bs->close(bs, NULL); + } } return 0; -- cgit v1.2.3