Commit 83ab0223 authored by Timo Teräs's avatar Timo Teräs

audit xattrs

ref #3027
parent 944eae4b
...@@ -149,6 +149,8 @@ apk_blob_t apk_blob_from_file(int atfd, const char *file); ...@@ -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); 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_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, int apk_fileinfo_get(int atfd, const char *filename, unsigned int flags,
struct apk_file_info *fi); struct apk_file_info *fi);
void apk_fileinfo_hash_xattr(struct apk_file_info *fi); void apk_fileinfo_hash_xattr(struct apk_file_info *fi);
......
...@@ -93,30 +93,36 @@ static int audit_file(struct audit_ctx *actx, ...@@ -93,30 +93,36 @@ static int audit_file(struct audit_ctx *actx,
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 == NULL) if (dbf == NULL)
return 'A'; return 'A';
dbf->audited = 1; 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; return -EPERM;
if (dbf->csum.type != APK_CHECKSUM_NONE && if (dbf->csum.type != APK_CHECKSUM_NONE &&
apk_checksum_compare(&fi.csum, &dbf->csum) != 0) apk_checksum_compare(&fi.csum, &dbf->csum) != 0)
return 'U'; rv = 'U';
else if (apk_checksum_compare(&fi.xattr_csum, &dbf->acl->xattr_csum) != 0)
if (S_ISLNK(fi.mode) && dbf->csum.type == APK_CHECKSUM_NONE) rv = 'X';
return 'U'; else if (S_ISLNK(fi.mode) && dbf->csum.type == APK_CHECKSUM_NONE)
rv = 'U';
if (actx->check_permissions) { else if (actx->check_permissions) {
if ((fi.mode & 07777) != (dbf->acl->mode & 07777)) if ((fi.mode & 07777) != (dbf->acl->mode & 07777))
return 'M'; rv = 'M';
if (fi.uid != dbf->acl->uid || fi.gid != dbf->acl->gid) else if (fi.uid != dbf->acl->uid || fi.gid != dbf->acl->gid)
return 'M'; rv = 'M';
} }
apk_fileinfo_free(&fi);
return 0; return rv;
} }
static int audit_directory(struct audit_ctx *actx, static int audit_directory(struct audit_ctx *actx,
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/xattr.h>
#include <pwd.h> #include <pwd.h>
#include <grp.h> #include <grp.h>
...@@ -543,26 +544,30 @@ static void hash_len_data(EVP_MD_CTX *ctx, uint32_t len, const void *ptr) ...@@ -543,26 +544,30 @@ static void hash_len_data(EVP_MD_CTX *ctx, uint32_t len, const void *ptr)
EVP_DigestUpdate(ctx, ptr, len); 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; struct apk_xattr *xattr;
const EVP_MD *md = apk_checksum_default();
EVP_MD_CTX mdctx; EVP_MD_CTX mdctx;
if (!fi->xattrs || fi->xattrs->num == 0) { if (!xattrs || xattrs->num == 0) {
fi->xattr_csum.type = APK_CHECKSUM_NONE; csum->type = APK_CHECKSUM_NONE;
return; 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); 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, strlen(xattr->name), xattr->name);
hash_len_data(&mdctx, xattr->value.len, xattr->value.ptr); hash_len_data(&mdctx, xattr->value.len, xattr->value.ptr);
} }
fi->xattr_csum.type = EVP_MD_CTX_size(&mdctx); csum->type = EVP_MD_CTX_size(&mdctx);
EVP_DigestFinal(&mdctx, fi->xattr_csum.data, NULL); 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, 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, ...@@ -570,7 +575,9 @@ int apk_fileinfo_get(int atfd, const char *filename, unsigned int flags,
{ {
struct stat64 st; struct stat64 st;
struct apk_bstream *bs; 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) if (flags & APK_FI_NOFOLLOW)
atflags |= AT_SYMLINK_NOFOLLOW; atflags |= AT_SYMLINK_NOFOLLOW;
...@@ -587,9 +594,47 @@ int apk_fileinfo_get(int atfd, const char *filename, unsigned int flags, ...@@ -587,9 +594,47 @@ int apk_fileinfo_get(int atfd, const char *filename, unsigned int flags,
.device = st.st_dev, .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; return 0;
/* Checksum file content */
if ((flags & APK_FI_NOFOLLOW) && S_ISLNK(st.st_mode)) { if ((flags & APK_FI_NOFOLLOW) && S_ISLNK(st.st_mode)) {
char *target = alloca(st.st_size); char *target = alloca(st.st_size);
if (target == NULL) if (target == NULL)
...@@ -600,23 +645,22 @@ int apk_fileinfo_get(int atfd, const char *filename, unsigned int flags, ...@@ -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, EVP_Digest(target, st.st_size, fi->csum.data, NULL,
apk_checksum_evp(checksum), NULL); apk_checksum_evp(checksum), NULL);
fi->csum.type = checksum; fi->csum.type = checksum;
return 0; } else {
} bs = apk_bstream_from_file(atfd, filename);
if (!IS_ERR_OR_NULL(bs)) {
bs = apk_bstream_from_file(atfd, filename); EVP_MD_CTX mdctx;
if (!IS_ERR_OR_NULL(bs)) { apk_blob_t blob;
EVP_MD_CTX mdctx;
apk_blob_t blob; EVP_DigestInit(&mdctx, apk_checksum_evp(checksum));
if (bs->flags & APK_BSTREAM_SINGLE_READ)
EVP_DigestInit(&mdctx, apk_checksum_evp(checksum)); EVP_MD_CTX_set_flags(&mdctx, EVP_MD_CTX_FLAG_ONESHOT);
if (bs->flags & APK_BSTREAM_SINGLE_READ) while (!APK_BLOB_IS_NULL(blob = bs->read(bs, APK_BLOB_NULL)))
EVP_MD_CTX_set_flags(&mdctx, EVP_MD_CTX_FLAG_ONESHOT); EVP_DigestUpdate(&mdctx, (void*) blob.ptr, blob.len);
while (!APK_BLOB_IS_NULL(blob = bs->read(bs, APK_BLOB_NULL))) fi->csum.type = EVP_MD_CTX_size(&mdctx);
EVP_DigestUpdate(&mdctx, (void*) blob.ptr, blob.len); EVP_DigestFinal(&mdctx, fi->csum.data, NULL);
fi->csum.type = EVP_MD_CTX_size(&mdctx);
EVP_DigestFinal(&mdctx, fi->csum.data, NULL); bs->close(bs, NULL);
}
bs->close(bs, NULL);
} }
return 0; return 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment