From 2b71629168c837a70bd7f06e168abccc457e80bf Mon Sep 17 00:00:00 2001 From: Anakin Zhang Date: Tue, 28 Jul 2020 20:33:46 +0800 Subject: [PATCH] convert tabs to spaces --- CHANGES | 46 +- Makefile.am | 20 +- docs/Makefile.am | 24 +- docs/gen_digest_lists.txt | 8 +- docs/manage_digest_lists.txt | 26 +- generators/Makefile.am | 6 +- generators/compact.c | 988 ++++++++-------- generators/copy.c | 88 +- generators/rpm.c | 1272 ++++++++++----------- generators/unknown.c | 982 ++++++++-------- include/Makefile.am | 22 +- include/compact_list.h | 86 +- include/crypto.h | 12 +- include/evm.h | 8 +- include/ima_list.h | 2 +- include/kernel_lib.h | 142 +-- include/lib.h | 36 +- include/list.h | 106 +- include/parser_lib.h | 18 +- include/pgp.h | 222 ++-- include/xattr.h | 10 +- initrd/dracut/load_digest_lists.sh | 34 +- initrd/dracut/upload_meta_digest_lists.sh | 2 +- lib/cap.c | 244 ++-- lib/compact_list.c | 1242 ++++++++++---------- lib/crypto.c | 576 +++++----- lib/evm.c | 96 +- lib/ima_list.c | 222 ++-- lib/kernel_lib.c | 308 ++--- lib/lib.c | 448 ++++---- lib/parser_lib.c | 392 +++---- lib/pgp.c | 840 +++++++------- lib/selinux.c | 48 +- lib/xattr.c | 226 ++-- parsers/compact_tlv.c | 498 ++++---- parsers/rpm.c | 492 ++++---- src/gen_digest_lists.c | 594 +++++----- src/manage_digest_lists.c | 356 +++--- src/rpm_parser.c | 516 ++++----- src/upload_digest_lists.c | 244 ++-- src/verify_digest_lists.c | 88 +- src/write_rpm_pgp_sig.c | 80 +- tests/compact_tlv.c | 376 +++--- tests/gen.c | 84 +- tests/lib.c | 44 +- tests/rpm.c | 226 ++-- 46 files changed, 6200 insertions(+), 6200 deletions(-) diff --git a/CHANGES b/CHANGES index 7c4adfa..568e8a3 100644 --- a/CHANGES +++ b/CHANGES @@ -1,36 +1,36 @@ 2020-07-14 Roberto Sassu - version 0.3.93 - * Add support for PGP signatures - * Add support for user space parsers - * Bug fixes + version 0.3.93 + * Add support for PGP signatures + * Add support for user space parsers + * Bug fixes 2020-07-02 Roberto Sassu - version 0.3.92 - * Bug fixes - * Change format of file list for compact/unknown generators + version 0.3.92 + * Bug fixes + * Change format of file list for compact/unknown generators 2020-06-02 Roberto Sassu - version 0.3.91 - * Bug fixes + version 0.3.91 + * Bug fixes 2020-04-17 Roberto Sassu - version 0.3.90 - * TLV compact list - * unknown generator - * digest list of metadata + version 0.3.90 + * TLV compact list + * unknown generator + * digest list of metadata 2019-03-19 Roberto Sassu - version 0.3 - * refactored code - * tests + version 0.3 + * refactored code + * tests 2018-04-05 Roberto Sassu - version 0.2 - * PGP signatures - * Multiple digest algorithms - * User space digest list parser - * DEB package format + version 0.2 + * PGP signatures + * Multiple digest algorithms + * User space digest list parser + * DEB package format 2017-11-15 Roberto Sassu - version 0.1 - * first public release + version 0.1 + * first public release diff --git a/Makefile.am b/Makefile.am index a0cb8b1..3b544d5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,16 +1,16 @@ SUBDIRS = docs \ - include \ - initrd \ - lib \ - generators \ - parsers \ - scripts \ - src \ - systemd \ - tests + include \ + initrd \ + lib \ + generators \ + parsers \ + scripts \ + src \ + systemd \ + tests EXTRA_DIST = AUTHORS \ - CHANGES + CHANGES dist_pkgdata_DATA = README.md diff --git a/docs/Makefile.am b/docs/Makefile.am index 69d2527..7f27950 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -1,15 +1,15 @@ dist_pkgdata_DATA = gen_digest_lists.txt \ - setup_ima_digest_lists.txt \ - setup_ima_digest_lists_demo.txt \ - manage_digest_lists.txt \ - upload_digest_lists.txt \ - verify_digest_lists.txt \ - write_rpm_pgp_sig.txt + setup_ima_digest_lists.txt \ + setup_ima_digest_lists_demo.txt \ + manage_digest_lists.txt \ + upload_digest_lists.txt \ + verify_digest_lists.txt \ + write_rpm_pgp_sig.txt man1_MANS = gen_digest_lists.1 \ - setup_ima_digest_lists.1 \ - setup_ima_digest_lists_demo.1 \ - manage_digest_lists.1 \ - upload_digest_lists.1 \ - verify_digest_lists.1 \ - write_rpm_pgp_sig.1 + setup_ima_digest_lists.1 \ + setup_ima_digest_lists_demo.1 \ + manage_digest_lists.1 \ + upload_digest_lists.1 \ + verify_digest_lists.1 \ + write_rpm_pgp_sig.1 diff --git a/docs/gen_digest_lists.txt b/docs/gen_digest_lists.txt index f6b55ed..ead469d 100644 --- a/docs/gen_digest_lists.txt +++ b/docs/gen_digest_lists.txt @@ -19,10 +19,10 @@ OPTIONS -i : path of the input file -o : operation to do: - - add: insert a new digest list at the position specified - - append: add a new digest list after the existing ones - - remove: remove a digest list at the position specified - - sign: sign a digest list + - add: insert a new digest list at the position specified + - append: add a new digest list after the existing ones + - remove: remove a digest list at the position specified + - sign: sign a digest list -p : position of the file in the directory to add/remove diff --git a/docs/manage_digest_lists.txt b/docs/manage_digest_lists.txt index 88898bc..324bee8 100644 --- a/docs/manage_digest_lists.txt +++ b/docs/manage_digest_lists.txt @@ -19,18 +19,18 @@ OPTIONS -o : write converted digest list to a file -p : specify parser operation: - add-digest: add IMA digest to output file - add-meta-digest: add EVM digest to output file - add-ima-xattr: set IMA xattr for files in the digest lists - rm-ima-xattr: remove IMA xattr for files in the digest lists - add-evm-xattr: set EVM xattr for files in the digest lists - rm-evm-xattr: remove EVM xattr for files in the digest lists - rm-infoflow-xattr: remove Infoflow xattr for files in the digest lists - dump: display content of digest lists - gen-ima-list: generate IMA digest list with digest list measurement - check-meta: compare metadata between digest lists and filesystem - repair-meta: set metadata from the digest lists to the filesystem - repair-meta-digest-lists: set digest lists metadata + add-digest: add IMA digest to output file + add-meta-digest: add EVM digest to output file + add-ima-xattr: set IMA xattr for files in the digest lists + rm-ima-xattr: remove IMA xattr for files in the digest lists + add-evm-xattr: set EVM xattr for files in the digest lists + rm-evm-xattr: remove EVM xattr for files in the digest lists + rm-infoflow-xattr: remove Infoflow xattr for files in the digest lists + dump: display content of digest lists + gen-ima-list: generate IMA digest list with digest list measurement + check-meta: compare metadata between digest lists and filesystem + repair-meta: set metadata from the digest lists to the filesystem + repair-meta-digest-lists: set digest lists metadata -v: verbose mode @@ -42,7 +42,7 @@ Convert all digest lists in /etc/ima/digest_lists to the compact format and save the converted lists to converted_lists. # manage_digest_lists -d /etc/ima/digest_lists -p add-digest \ - -o converted_lists + -o converted_lists AUTHOR diff --git a/generators/Makefile.am b/generators/Makefile.am index 46d6c66..726522d 100644 --- a/generators/Makefile.am +++ b/generators/Makefile.am @@ -1,7 +1,7 @@ digestlistdir=$(libdir)/digestlist digestlist_LTLIBRARIES=libgenerator-copy.la libgenerator-compact.la \ - libgenerator-unknown.la + libgenerator-unknown.la libgenerator_LDFLAGS=-no-undefined -avoid-version -L$(top_srcdir)/lib/.libs libgenerator_LIBADD=$(top_srcdir)/lib/libdigestlist-base.la @@ -32,10 +32,10 @@ libgenerator_unknown_la_SOURCES=unknown.c if CMOCKA check_LTLIBRARIES=libgenerator-copy-test.la libgenerator-compact-test.la \ - libgenerator-unknown-test.la + libgenerator-unknown-test.la libgenerator_test_LDFLAGS=-no-undefined -avoid-version \ - -L$(top_srcdir)/lib/.libs -rpath /dev/null + -L$(top_srcdir)/lib/.libs -rpath /dev/null libgenerator_test_LIBADD=$(top_srcdir)/lib/libdigestlist-base-test.la -lcmocka libgenerator_test_CFLAGS=-I$(top_srcdir)/include -DUNIT_TESTING diff --git a/generators/compact.c b/generators/compact.c index 84609d2..a8a56a2 100644 --- a/generators/compact.c +++ b/generators/compact.c @@ -34,509 +34,509 @@ #define FORMAT_TLV "compact_tlv" static int add_file(int dirfd, int fd, char *path, u16 type, u16 modifiers, - struct stat *st, struct list_struct *list, - struct list_struct *list_file, enum hash_algo algo, - enum hash_algo ima_algo, bool tlv, bool gen_list, - bool include_lsm_label, bool root_cred, bool set_ima_xattr, - bool set_evm_xattr, char *alt_root, char *caps, - char *file_digest) + struct stat *st, struct list_struct *list, + struct list_struct *list_file, enum hash_algo algo, + enum hash_algo ima_algo, bool tlv, bool gen_list, + bool include_lsm_label, bool root_cred, bool set_ima_xattr, + bool set_evm_xattr, char *alt_root, char *caps, + char *file_digest) { - cap_t c; - u8 ima_xattr[2048]; - struct vfs_cap_data rawvfscap; - u8 ima_digest[SHA512_DIGEST_SIZE]; - u8 evm_digest[SHA512_DIGEST_SIZE]; - u8 *digest = ima_digest; - char *obj_label = NULL; - u8 *caps_bin = NULL; - LIST_HEAD(items); - struct stat s; - int gen_ima_xattr = 1; - int ret, ima_xattr_len, obj_label_len = 0, caps_bin_len = 0; - - if (!S_ISREG(st->st_mode)) - return -ENOENT; - - if (gen_list) { - ret = write_check(fd, path, strlen(path)); - if (!ret) - ret = write_check(fd, "\n", 1); - - return ret; - } - - if (root_cred) { - memcpy(&s, st, sizeof(s)); - s.st_uid = 0; - s.st_gid = 0; - st = &s; - } - - if (((st->st_mode & S_IXUGO) || !(st->st_mode & S_IWUGO)) && - st->st_size) - modifiers |= (1 << COMPACT_MOD_IMMUTABLE); - - if (!file_digest) { - ret = calc_file_digest(digest, -1, path, algo); - if (ret < 0) { - printf("Cannot calculate digest of %s\n", path); - goto out; - } - } else { - hex2bin(digest, file_digest, hash_digest_size[algo]); - } - - if (type == COMPACT_METADATA || tlv) { - ima_xattr_len = getxattr(path, XATTR_NAME_IMA, NULL, 0); - if (!gen_ima_xattr && - ima_xattr_len > 0 && ima_xattr_len < sizeof(ima_xattr)) { - ima_xattr_len = getxattr(path, XATTR_NAME_IMA, - ima_xattr, ima_xattr_len); - if (ima_xattr_len) - gen_ima_xattr = 0; - } - - if (gen_ima_xattr) { - ret = gen_write_ima_xattr(ima_xattr, &ima_xattr_len, - path, algo, ima_digest, - (modifiers & (1 << COMPACT_MOD_IMMUTABLE)), - set_ima_xattr); - if (ret < 0) - return ret; - } - - if (set_evm_xattr) { - ret = write_evm_xattr(path, algo); - if (ret < 0) - return ret; - } - - if (include_lsm_label == 1) - obj_label_len = getxattr(path, XATTR_NAME_SELINUX, - NULL, 0); - if (obj_label_len > 0) { - obj_label = malloc(obj_label_len); - if (!obj_label) - return -ENOMEM; - - obj_label_len = getxattr(path, XATTR_NAME_SELINUX, - obj_label, obj_label_len); - if (obj_label_len <= 0) { - ret = -EACCES; - goto out; - } - } else { - obj_label_len = 0; - } - - if (include_lsm_label == 2) { - ret = get_selinux_label(path, alt_root, &obj_label, - st->st_mode); - if (!ret && obj_label) - obj_label_len = strlen(obj_label) + 1; - } - - if (caps && strlen(caps)) { - c = cap_from_text(caps); - if (!c) { - ret = -ENOMEM; - goto out; - } - - ret = _fcaps_save(&rawvfscap, c, &caps_bin_len); - if (!ret) { - caps_bin = malloc(caps_bin_len); - if (!caps_bin) { - ret = -ENOMEM; - goto out; - } - - memcpy(caps_bin, (u8 *)&rawvfscap, - caps_bin_len); - } - - cap_free(c); - } else { - caps_bin_len = getxattr(path, XATTR_NAME_CAPS, NULL, 0); - if (caps_bin_len > 0) { - caps_bin = malloc(caps_bin_len); - if (!caps_bin) { - ret = -ENOMEM; - goto out; - } - - caps_bin_len = getxattr(path, XATTR_NAME_CAPS, - caps_bin, caps_bin_len); - if (caps_bin_len <= 0) { - ret = -EACCES; - goto out; - } - } else { - caps_bin_len = 0; - } - } - - ret = evm_calc_hmac_or_hash(algo, evm_digest, - obj_label_len, obj_label, - ima_xattr_len, ima_xattr, - caps_bin_len, caps_bin, - st->st_uid, st->st_gid, - st->st_mode); - if (ret < 0) - goto out; - - if (type == COMPACT_METADATA) - digest = evm_digest; - } - - if (!tlv) { - if (type == COMPACT_METADATA && list_file) { - ret = compact_list_add_digest(fd, list_file, - ima_digest); - if (ret < 0) - goto out; - } - - ret = compact_list_add_digest(fd, list, digest); - goto out; - } - - if (type == COMPACT_METADATA) { - ret = compact_list_tlv_add_digest(fd, list, &items, evm_digest, - ID_EVM_DIGEST); - if (ret < 0) - goto out_free_items; - } - - ret = compact_list_tlv_add_digest(fd, list, &items, ima_digest, - ID_DIGEST); - if (ret < 0) - goto out_free_items; - - ret = compact_list_tlv_add_metadata(fd, list, &items, path, alt_root, - st, obj_label, obj_label_len, - caps_bin, caps_bin_len); - if (ret < 0) - goto out_free_items; - - ret = compact_list_tlv_add_items(fd, list, &items); - - if (ret < 0) { - printf("Cannot add digest to compact list\n"); - goto out_free_items; - } - - if (algo != ima_algo && getuid() == 0) { - ret = write_ima_xattr(-1, path, NULL, 0, NULL, 0, algo); - if (ret < 0) { - printf("Cannot write xattr to %s\n", path); - goto out_free_items; - } - } + cap_t c; + u8 ima_xattr[2048]; + struct vfs_cap_data rawvfscap; + u8 ima_digest[SHA512_DIGEST_SIZE]; + u8 evm_digest[SHA512_DIGEST_SIZE]; + u8 *digest = ima_digest; + char *obj_label = NULL; + u8 *caps_bin = NULL; + LIST_HEAD(items); + struct stat s; + int gen_ima_xattr = 1; + int ret, ima_xattr_len, obj_label_len = 0, caps_bin_len = 0; + + if (!S_ISREG(st->st_mode)) + return -ENOENT; + + if (gen_list) { + ret = write_check(fd, path, strlen(path)); + if (!ret) + ret = write_check(fd, "\n", 1); + + return ret; + } + + if (root_cred) { + memcpy(&s, st, sizeof(s)); + s.st_uid = 0; + s.st_gid = 0; + st = &s; + } + + if (((st->st_mode & S_IXUGO) || !(st->st_mode & S_IWUGO)) && + st->st_size) + modifiers |= (1 << COMPACT_MOD_IMMUTABLE); + + if (!file_digest) { + ret = calc_file_digest(digest, -1, path, algo); + if (ret < 0) { + printf("Cannot calculate digest of %s\n", path); + goto out; + } + } else { + hex2bin(digest, file_digest, hash_digest_size[algo]); + } + + if (type == COMPACT_METADATA || tlv) { + ima_xattr_len = getxattr(path, XATTR_NAME_IMA, NULL, 0); + if (!gen_ima_xattr && + ima_xattr_len > 0 && ima_xattr_len < sizeof(ima_xattr)) { + ima_xattr_len = getxattr(path, XATTR_NAME_IMA, + ima_xattr, ima_xattr_len); + if (ima_xattr_len) + gen_ima_xattr = 0; + } + + if (gen_ima_xattr) { + ret = gen_write_ima_xattr(ima_xattr, &ima_xattr_len, + path, algo, ima_digest, + (modifiers & (1 << COMPACT_MOD_IMMUTABLE)), + set_ima_xattr); + if (ret < 0) + return ret; + } + + if (set_evm_xattr) { + ret = write_evm_xattr(path, algo); + if (ret < 0) + return ret; + } + + if (include_lsm_label == 1) + obj_label_len = getxattr(path, XATTR_NAME_SELINUX, + NULL, 0); + if (obj_label_len > 0) { + obj_label = malloc(obj_label_len); + if (!obj_label) + return -ENOMEM; + + obj_label_len = getxattr(path, XATTR_NAME_SELINUX, + obj_label, obj_label_len); + if (obj_label_len <= 0) { + ret = -EACCES; + goto out; + } + } else { + obj_label_len = 0; + } + + if (include_lsm_label == 2) { + ret = get_selinux_label(path, alt_root, &obj_label, + st->st_mode); + if (!ret && obj_label) + obj_label_len = strlen(obj_label) + 1; + } + + if (caps && strlen(caps)) { + c = cap_from_text(caps); + if (!c) { + ret = -ENOMEM; + goto out; + } + + ret = _fcaps_save(&rawvfscap, c, &caps_bin_len); + if (!ret) { + caps_bin = malloc(caps_bin_len); + if (!caps_bin) { + ret = -ENOMEM; + goto out; + } + + memcpy(caps_bin, (u8 *)&rawvfscap, + caps_bin_len); + } + + cap_free(c); + } else { + caps_bin_len = getxattr(path, XATTR_NAME_CAPS, NULL, 0); + if (caps_bin_len > 0) { + caps_bin = malloc(caps_bin_len); + if (!caps_bin) { + ret = -ENOMEM; + goto out; + } + + caps_bin_len = getxattr(path, XATTR_NAME_CAPS, + caps_bin, caps_bin_len); + if (caps_bin_len <= 0) { + ret = -EACCES; + goto out; + } + } else { + caps_bin_len = 0; + } + } + + ret = evm_calc_hmac_or_hash(algo, evm_digest, + obj_label_len, obj_label, + ima_xattr_len, ima_xattr, + caps_bin_len, caps_bin, + st->st_uid, st->st_gid, + st->st_mode); + if (ret < 0) + goto out; + + if (type == COMPACT_METADATA) + digest = evm_digest; + } + + if (!tlv) { + if (type == COMPACT_METADATA && list_file) { + ret = compact_list_add_digest(fd, list_file, + ima_digest); + if (ret < 0) + goto out; + } + + ret = compact_list_add_digest(fd, list, digest); + goto out; + } + + if (type == COMPACT_METADATA) { + ret = compact_list_tlv_add_digest(fd, list, &items, evm_digest, + ID_EVM_DIGEST); + if (ret < 0) + goto out_free_items; + } + + ret = compact_list_tlv_add_digest(fd, list, &items, ima_digest, + ID_DIGEST); + if (ret < 0) + goto out_free_items; + + ret = compact_list_tlv_add_metadata(fd, list, &items, path, alt_root, + st, obj_label, obj_label_len, + caps_bin, caps_bin_len); + if (ret < 0) + goto out_free_items; + + ret = compact_list_tlv_add_items(fd, list, &items); + + if (ret < 0) { + printf("Cannot add digest to compact list\n"); + goto out_free_items; + } + + if (algo != ima_algo && getuid() == 0) { + ret = write_ima_xattr(-1, path, NULL, 0, NULL, 0, algo); + if (ret < 0) { + printf("Cannot write xattr to %s\n", path); + goto out_free_items; + } + } out_free_items: - compact_list_tlv_free_items(&items); + compact_list_tlv_free_items(&items); out: - free(obj_label); - free(caps_bin); - return ret; + free(obj_label); + free(caps_bin); + return ret; } int generator(int dirfd, int pos, struct list_head *head_in, - struct list_head *head_out, enum compact_types type, - u16 modifiers, enum hash_algo algo, enum hash_algo ima_algo, - bool tlv, char *alt_root) + struct list_head *head_out, enum compact_types type, + u16 modifiers, enum hash_algo algo, enum hash_algo ima_algo, + bool tlv, char *alt_root) { - char filename[NAME_MAX + 1], *basename = NULL, *link = NULL; - char path[PATH_MAX], *path_list = NULL, *data_ptr, *line_ptr; - char *path_ptr = NULL, *gen_list_path = NULL, *real_path; - struct list_struct *list = NULL, *list_file = NULL; - struct path_struct *cur, *cur_i, *cur_e; - LIST_HEAD(list_head); - FTS *fts = NULL; - FTSENT *ftsent; - struct stat st, *statp; - void *data; - loff_t size; - bool unlink = true; - char *paths[2] = { NULL, NULL }; - char *attrs[ATTR__LAST]; - struct passwd *pwd; - struct group *grp; - enum hash_algo list_algo; - int fts_flags = (FTS_PHYSICAL | FTS_COMFOLLOW | FTS_NOCHDIR | FTS_XDEV); - int include_ima_digests = 0, only_executables = 0, set_ima_xattr = 0; - int ret = 0, fd, prefix_len, include_lsm_label = 0, include_file = 0; - int path_list_ext = 0, set_evm_xattr = 0, alt_root_len; - int use_path_list_filename = 0, root_cred = 0, include_path = 0; - - list_for_each_entry(cur, head_in, list) { - if (cur->path[1] != ':') { - pr_err("Options must be in the format :\n"); - return -EINVAL; - } - - if (cur->path[0] == 'i') - include_ima_digests = 1; - if (cur->path[0] == 'L') - path_list = &cur->path[2]; - if (cur->path[0] == 'M') - path_list_ext = 1; - if (cur->path[0] == 'G') - gen_list_path = &cur->path[2]; - if (cur->path[0] == 'l') { - if (!strcmp(&cur->path[2], "policy")) - include_lsm_label = 2; - else - include_lsm_label = 1; - } - if (cur->path[0] == 'e') - only_executables = 1; - if (cur->path[0] == 'u') - use_path_list_filename = 1; - if (cur->path[0] == 'r') - root_cred = 1; - if (cur->path[0] == 'F') - include_path = 1; - if (cur->path[0] == 'x') { - if (!strcmp(&cur->path[2], "evm")) - set_evm_xattr = 1; - else - set_ima_xattr = 1; - } - } - - if (path_list) { - ret = read_file_from_path(-1, path_list, &data, &size); - if (ret < 0) - return ret; - - data_ptr = (char *)data; - - while ((line_ptr = strsep(&data_ptr, "\n"))) { - if (!strlen(line_ptr)) - continue; - - if (path_list_ext) { - parse_file_attrs(line_ptr, attrs); - line_ptr = attrs[ATTR_PATH]; - } - - if (!line_ptr || stat(line_ptr, &st) == -1 || - !S_ISREG(st.st_mode)) - continue; - - snprintf(path, sizeof(path), "I:%s", line_ptr); - ret = add_path_struct(path, attrs, head_in); - if (ret < 0) - return ret; - } - - path_ptr = path_list; - } - - list_for_each_entry(cur, head_in, list) { - if (cur->path[0] != 'I') - continue; - - if (!use_path_list_filename || !path_list) - path_ptr = &cur->path[2]; - break; - } - - if (!path_ptr) { - printf("Input path not specified\n"); - return -EINVAL; - } - - if (!gen_list_path) { - basename = strrchr(path_ptr, '/'); - if (!basename) - basename = path_ptr; - else - basename++; - - prefix_len = gen_filename_prefix(filename, sizeof(filename), - pos, tlv ? FORMAT_TLV : FORMAT, type); - snprintf(filename + prefix_len, sizeof(filename) - prefix_len, - "%s", basename); - } - - if (type == COMPACT_METADATA && include_lsm_label) { - ret = selinux_init_setup(); - if (ret) - return ret; - } - - if (!gen_list_path) - fd = openat(dirfd, filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); - else - fd = openat(-1, gen_list_path, O_WRONLY | O_CREAT | O_TRUNC, 0644); - if (fd < 0) { - printf("Cannot open %s\n", filename); - ret = -EACCES; - goto out_selinux; - } - - list = compact_list_init(&list_head, type, modifiers, algo, tlv); - if (!list) - goto out_close; - - if (type == COMPACT_METADATA && include_ima_digests) { - list_file = compact_list_init(&list_head, COMPACT_FILE, - modifiers, algo, tlv); - if (!list_file) - goto out_close; - } - - list_for_each_entry(cur, head_in, list) { - if (cur->path[0] != 'I') - continue; - - if (path_list_ext) { - pwd = NULL; - grp = NULL; - list_algo = algo; - - if (cur->attrs[ATTR_MODE]) - st.st_mode = strtol(cur->attrs[ATTR_MODE], - NULL, 10); - st.st_uid = 0; - if (cur->attrs[ATTR_UNAME]) - pwd = getpwnam(cur->attrs[ATTR_UNAME]); - if (pwd) - st.st_uid = pwd->pw_uid; - st.st_gid = 0; - if (cur->attrs[ATTR_GNAME]) - grp = getgrnam(cur->attrs[ATTR_GNAME]); - if (grp) - st.st_gid = grp->gr_gid; - if (cur->attrs[ATTR_DIGESTALGO]) - list_algo = strtol(cur->attrs[ATTR_DIGESTALGO], - NULL, 10); - if (cur->attrs[ATTR_DIGESTALGOPGP]) { - list_algo = pgp_algo_mapping[strtol( - cur->attrs[ATTR_DIGESTALGOPGP], - NULL, 10)]; - } - if (list_algo != algo) - continue; - } - - paths[0] = &cur->path[2]; - - fts = fts_open(paths, fts_flags, NULL); - if (!fts) { - ret = -EACCES; - goto out_close; - } - - while ((ftsent = fts_read(fts)) != NULL) { - switch (ftsent->fts_info) { - case FTS_F: - real_path = ftsent->fts_path; - alt_root_len = alt_root ? strlen(alt_root) : 0; - - if (alt_root && - alt_root_len < strlen(real_path)) - real_path += alt_root_len; - - include_file = 0; - statp = ftsent->fts_statp; - if (path_list_ext) { - st.st_size = statp->st_size; - statp = &st; - } - - if (include_path && only_executables) { - list_for_each_entry(cur_i, head_in, - list) { - if (cur_i->path[0] != 'F') - continue; - - if (!strncmp(real_path, - &cur_i->path[2], - strlen(&cur_i->path[2]))) { - include_file = 1; - break; - } - } - } else { - if (!only_executables) - include_file = 1; - } - - if (only_executables && - (statp->st_mode & S_IXUGO)) - include_file = 1; - - if (!include_file) - continue; - - include_file = 1; - - list_for_each_entry(cur_e, head_in, list) { - if (cur_e->path[0] == 'E' && - !strncmp(&cur_e->path[2], - real_path, - strlen(&cur_e->path[2]))) { - include_file = 0; - break; - } - } - - if (!include_file) - continue; - - ret = add_file(dirfd, fd, ftsent->fts_path, - type, modifiers, statp, list, - list_file, algo, ima_algo, tlv, - gen_list_path != NULL, - include_lsm_label, root_cred, - set_ima_xattr, set_evm_xattr, - alt_root, cur->attrs[ATTR_CAPS], - cur->attrs[ATTR_DIGEST]); - if (!ret) - unlink = false; - if (ret < 0 && ret != -ENOENT && - ret != -ENODATA) - goto out_fts_close; - - break; - default: - break; - } - } - - fts_close(fts); - fts = NULL; - } - - ret = compact_list_flush_all(fd, &list_head); - if (ret < 0) { - printf("Cannot write digest list to %s\n", filename); - goto out_close; - } - - if (!unlink && !gen_list_path) - ret = add_path_struct(filename, NULL, head_out); + char filename[NAME_MAX + 1], *basename = NULL, *link = NULL; + char path[PATH_MAX], *path_list = NULL, *data_ptr, *line_ptr; + char *path_ptr = NULL, *gen_list_path = NULL, *real_path; + struct list_struct *list = NULL, *list_file = NULL; + struct path_struct *cur, *cur_i, *cur_e; + LIST_HEAD(list_head); + FTS *fts = NULL; + FTSENT *ftsent; + struct stat st, *statp; + void *data; + loff_t size; + bool unlink = true; + char *paths[2] = { NULL, NULL }; + char *attrs[ATTR__LAST]; + struct passwd *pwd; + struct group *grp; + enum hash_algo list_algo; + int fts_flags = (FTS_PHYSICAL | FTS_COMFOLLOW | FTS_NOCHDIR | FTS_XDEV); + int include_ima_digests = 0, only_executables = 0, set_ima_xattr = 0; + int ret = 0, fd, prefix_len, include_lsm_label = 0, include_file = 0; + int path_list_ext = 0, set_evm_xattr = 0, alt_root_len; + int use_path_list_filename = 0, root_cred = 0, include_path = 0; + + list_for_each_entry(cur, head_in, list) { + if (cur->path[1] != ':') { + pr_err("Options must be in the format :\n"); + return -EINVAL; + } + + if (cur->path[0] == 'i') + include_ima_digests = 1; + if (cur->path[0] == 'L') + path_list = &cur->path[2]; + if (cur->path[0] == 'M') + path_list_ext = 1; + if (cur->path[0] == 'G') + gen_list_path = &cur->path[2]; + if (cur->path[0] == 'l') { + if (!strcmp(&cur->path[2], "policy")) + include_lsm_label = 2; + else + include_lsm_label = 1; + } + if (cur->path[0] == 'e') + only_executables = 1; + if (cur->path[0] == 'u') + use_path_list_filename = 1; + if (cur->path[0] == 'r') + root_cred = 1; + if (cur->path[0] == 'F') + include_path = 1; + if (cur->path[0] == 'x') { + if (!strcmp(&cur->path[2], "evm")) + set_evm_xattr = 1; + else + set_ima_xattr = 1; + } + } + + if (path_list) { + ret = read_file_from_path(-1, path_list, &data, &size); + if (ret < 0) + return ret; + + data_ptr = (char *)data; + + while ((line_ptr = strsep(&data_ptr, "\n"))) { + if (!strlen(line_ptr)) + continue; + + if (path_list_ext) { + parse_file_attrs(line_ptr, attrs); + line_ptr = attrs[ATTR_PATH]; + } + + if (!line_ptr || stat(line_ptr, &st) == -1 || + !S_ISREG(st.st_mode)) + continue; + + snprintf(path, sizeof(path), "I:%s", line_ptr); + ret = add_path_struct(path, attrs, head_in); + if (ret < 0) + return ret; + } + + path_ptr = path_list; + } + + list_for_each_entry(cur, head_in, list) { + if (cur->path[0] != 'I') + continue; + + if (!use_path_list_filename || !path_list) + path_ptr = &cur->path[2]; + break; + } + + if (!path_ptr) { + printf("Input path not specified\n"); + return -EINVAL; + } + + if (!gen_list_path) { + basename = strrchr(path_ptr, '/'); + if (!basename) + basename = path_ptr; + else + basename++; + + prefix_len = gen_filename_prefix(filename, sizeof(filename), + pos, tlv ? FORMAT_TLV : FORMAT, type); + snprintf(filename + prefix_len, sizeof(filename) - prefix_len, + "%s", basename); + } + + if (type == COMPACT_METADATA && include_lsm_label) { + ret = selinux_init_setup(); + if (ret) + return ret; + } + + if (!gen_list_path) + fd = openat(dirfd, filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); + else + fd = openat(-1, gen_list_path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd < 0) { + printf("Cannot open %s\n", filename); + ret = -EACCES; + goto out_selinux; + } + + list = compact_list_init(&list_head, type, modifiers, algo, tlv); + if (!list) + goto out_close; + + if (type == COMPACT_METADATA && include_ima_digests) { + list_file = compact_list_init(&list_head, COMPACT_FILE, + modifiers, algo, tlv); + if (!list_file) + goto out_close; + } + + list_for_each_entry(cur, head_in, list) { + if (cur->path[0] != 'I') + continue; + + if (path_list_ext) { + pwd = NULL; + grp = NULL; + list_algo = algo; + + if (cur->attrs[ATTR_MODE]) + st.st_mode = strtol(cur->attrs[ATTR_MODE], + NULL, 10); + st.st_uid = 0; + if (cur->attrs[ATTR_UNAME]) + pwd = getpwnam(cur->attrs[ATTR_UNAME]); + if (pwd) + st.st_uid = pwd->pw_uid; + st.st_gid = 0; + if (cur->attrs[ATTR_GNAME]) + grp = getgrnam(cur->attrs[ATTR_GNAME]); + if (grp) + st.st_gid = grp->gr_gid; + if (cur->attrs[ATTR_DIGESTALGO]) + list_algo = strtol(cur->attrs[ATTR_DIGESTALGO], + NULL, 10); + if (cur->attrs[ATTR_DIGESTALGOPGP]) { + list_algo = pgp_algo_mapping[strtol( + cur->attrs[ATTR_DIGESTALGOPGP], + NULL, 10)]; + } + if (list_algo != algo) + continue; + } + + paths[0] = &cur->path[2]; + + fts = fts_open(paths, fts_flags, NULL); + if (!fts) { + ret = -EACCES; + goto out_close; + } + + while ((ftsent = fts_read(fts)) != NULL) { + switch (ftsent->fts_info) { + case FTS_F: + real_path = ftsent->fts_path; + alt_root_len = alt_root ? strlen(alt_root) : 0; + + if (alt_root && + alt_root_len < strlen(real_path)) + real_path += alt_root_len; + + include_file = 0; + statp = ftsent->fts_statp; + if (path_list_ext) { + st.st_size = statp->st_size; + statp = &st; + } + + if (include_path && only_executables) { + list_for_each_entry(cur_i, head_in, + list) { + if (cur_i->path[0] != 'F') + continue; + + if (!strncmp(real_path, + &cur_i->path[2], + strlen(&cur_i->path[2]))) { + include_file = 1; + break; + } + } + } else { + if (!only_executables) + include_file = 1; + } + + if (only_executables && + (statp->st_mode & S_IXUGO)) + include_file = 1; + + if (!include_file) + continue; + + include_file = 1; + + list_for_each_entry(cur_e, head_in, list) { + if (cur_e->path[0] == 'E' && + !strncmp(&cur_e->path[2], + real_path, + strlen(&cur_e->path[2]))) { + include_file = 0; + break; + } + } + + if (!include_file) + continue; + + ret = add_file(dirfd, fd, ftsent->fts_path, + type, modifiers, statp, list, + list_file, algo, ima_algo, tlv, + gen_list_path != NULL, + include_lsm_label, root_cred, + set_ima_xattr, set_evm_xattr, + alt_root, cur->attrs[ATTR_CAPS], + cur->attrs[ATTR_DIGEST]); + if (!ret) + unlink = false; + if (ret < 0 && ret != -ENOENT && + ret != -ENODATA) + goto out_fts_close; + + break; + default: + break; + } + } + + fts_close(fts); + fts = NULL; + } + + ret = compact_list_flush_all(fd, &list_head); + if (ret < 0) { + printf("Cannot write digest list to %s\n", filename); + goto out_close; + } + + if (!unlink && !gen_list_path) + ret = add_path_struct(filename, NULL, head_out); out_fts_close: - if (fts) - fts_close(fts); + if (fts) + fts_close(fts); out_close: - close(fd); - - if (ret < 0 || unlink) { - unlinkat(dirfd, filename, 0); - } else if (!gen_list_path) { - if (!tlv && !strcmp(basename, "manage_digest_lists")) { - link = strchr(strchr(filename, '-') + 1, '-') + 1; - unlinkat(dirfd, link, 0); - ret = symlinkat(filename, dirfd, link); - } - } + close(fd); + + if (ret < 0 || unlink) { + unlinkat(dirfd, filename, 0); + } else if (!gen_list_path) { + if (!tlv && !strcmp(basename, "manage_digest_lists")) { + link = strchr(strchr(filename, '-') + 1, '-') + 1; + unlinkat(dirfd, link, 0); + ret = symlinkat(filename, dirfd, link); + } + } out_selinux: - if (type == COMPACT_METADATA && include_lsm_label) - selinux_end_setup(); + if (type == COMPACT_METADATA && include_lsm_label) + selinux_end_setup(); - return ret; + return ret; } diff --git a/generators/copy.c b/generators/copy.c index bc88e96..926f6f8 100644 --- a/generators/copy.c +++ b/generators/copy.c @@ -21,60 +21,60 @@ int generator(int dirfd, int pos, struct list_head *head_in, - struct list_head *head_out, enum compact_types type, - u16 modifiers, enum hash_algo algo, enum hash_algo ima_algo, - bool tlv, char *alt_root) + struct list_head *head_out, enum compact_types type, + u16 modifiers, enum hash_algo algo, enum hash_algo ima_algo, + bool tlv, char *alt_root) { - struct path_struct *cur; - char filename[NAME_MAX + 1]; - char *basename; - void *buf; - loff_t size; - int ret = 0, fd; + struct path_struct *cur; + char filename[NAME_MAX + 1]; + char *basename; + void *buf; + loff_t size; + int ret = 0, fd; - if (list_empty(head_in)) { - printf("Input path not specified\n"); - return -EINVAL; - } + if (list_empty(head_in)) { + printf("Input path not specified\n"); + return -EINVAL; + } - list_for_each_entry(cur, head_in, list) { - basename = strrchr(cur->path, '/'); - if (!basename) - basename = cur->path; - else - basename++; + list_for_each_entry(cur, head_in, list) { + basename = strrchr(cur->path, '/'); + if (!basename) + basename = cur->path; + else + basename++; - snprintf(filename, sizeof(filename), "%d-%s_list-%s", pos, - compact_types_str[type], basename); + snprintf(filename, sizeof(filename), "%d-%s_list-%s", pos, + compact_types_str[type], basename); - ret = read_file_from_path(-1, cur->path, &buf, &size); - if (ret < 0) - goto out; + ret = read_file_from_path(-1, cur->path, &buf, &size); + if (ret < 0) + goto out; - fd = openat(dirfd, filename, O_WRONLY | O_CREAT, 0644); - if (fd < 0) { - munmap(buf, size); - ret = fd; - goto out; - } + fd = openat(dirfd, filename, O_WRONLY | O_CREAT, 0644); + if (fd < 0) { + munmap(buf, size); + ret = fd; + goto out; + } - ret = write_check(fd, buf, size); - munmap(buf, size); - close(fd); + ret = write_check(fd, buf, size); + munmap(buf, size); + close(fd); - if (ret < 0) - goto out; + if (ret < 0) + goto out; - ret = add_path_struct(filename, NULL, head_out); - if (ret < 0) - goto out; + ret = add_path_struct(filename, NULL, head_out); + if (ret < 0) + goto out; - if (pos >= 0) - pos++; - } + if (pos >= 0) + pos++; + } out: - if (ret < 0) - unlinkat(dirfd, filename, 0); + if (ret < 0) + unlinkat(dirfd, filename, 0); - return ret; + return ret; } diff --git a/generators/rpm.c b/generators/rpm.c index 0b357c3..8f7701c 100644 --- a/generators/rpm.c +++ b/generators/rpm.c @@ -36,701 +36,701 @@ #define FORMAT "rpm" const unsigned char rpm_header_magic[8] = { - 0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00 + 0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00 }; static int add_file(int dirfd, char *filename, Header *hdr, u16 type, - u16 modifiers, struct list_head *head_in, - struct list_head *head_out, enum hash_algo algo, - enum hash_algo ima_algo, bool tlv, bool include_ima_digests, - bool include_lsm_label, bool only_executables, - bool include_path, bool set_ima_xattr, int set_evm_xattr, - char *alt_root) + u16 modifiers, struct list_head *head_in, + struct list_head *head_out, enum hash_algo algo, + enum hash_algo ima_algo, bool tlv, bool include_ima_digests, + bool include_lsm_label, bool only_executables, + bool include_path, bool set_ima_xattr, int set_evm_xattr, + char *alt_root) { - const char *ima_digest_str, *filecaps_str, *basename, *dirname; - enum pgp_hash_algo pgp_algo; - char file_path[PATH_MAX]; - u8 ima_xattr[2048]; - u8 ima_digest[SHA512_DIGEST_SIZE]; - u8 evm_digest[SHA512_DIGEST_SIZE]; - LIST_HEAD(list_head); - u8 *digest; - char *obj_label = NULL; - LIST_HEAD(items); - int ret = 0, ima_xattr_len, obj_label_len = 0, include_file = 0; - rpmtd filedigestalgo, filedigests, filemodes, filesizes, filecaps; - rpmtd basenames, dirnames, dirindexes; - struct path_struct *cur; - uint16_t mode; - uint32_t size, dirindex; - u16 file_modifiers; - cap_t c; - struct vfs_cap_data rawvfscap; - int rawvfscap_len, fd; - struct list_struct *list = NULL, *list_file = NULL; - struct stat s; - - fd = openat(dirfd, filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); - if (fd < 0) - return -EACCES; - - filedigestalgo = rpmtdNew(); - headerGet(*hdr, RPMTAG_FILEDIGESTALGO, filedigestalgo, 0); - filedigests = rpmtdNew(); - headerGet(*hdr, RPMTAG_FILEDIGESTS, filedigests, 0); - filemodes = rpmtdNew(); - headerGet(*hdr, RPMTAG_FILEMODES, filemodes, 0); - filesizes = rpmtdNew(); - headerGet(*hdr, RPMTAG_FILESIZES, filesizes, 0); - filecaps = rpmtdNew(); - headerGet(*hdr, RPMTAG_FILECAPS, filecaps, 0); - basenames = rpmtdNew(); - headerGet(*hdr, RPMTAG_BASENAMES, basenames, 0); - dirnames = rpmtdNew(); - headerGet(*hdr, RPMTAG_DIRNAMES, dirnames, 0); - dirindexes = rpmtdNew(); - headerGet(*hdr, RPMTAG_DIRINDEXES, dirindexes, 0); - - pgp_algo = PGP_HASH_MD5; - if (rpmtdGetUint32(filedigestalgo)) - pgp_algo = *rpmtdGetUint32(filedigestalgo); - - if (pgp_algo >= PGP_HASH__LAST) { - ret = -EINVAL; - goto out_close; - } - - algo = pgp_algo_mapping[pgp_algo]; - list = compact_list_init(&list_head, type, modifiers, algo, tlv); - if (!list) - goto out_close; - - if (type == COMPACT_METADATA && include_ima_digests) { - list_file = compact_list_init(&list_head, COMPACT_FILE, - modifiers, algo, tlv); - if (!list_file) - goto out_close; - } - - while ((ima_digest_str = rpmtdNextString(filedigests))) { - include_file = 0; - ret = 0; - - rpmtdNext(filemodes); - mode = *rpmtdGetUint16(filemodes); - size = *rpmtdNextUint32(filesizes); - filecaps_str = rpmtdNextString(filecaps); - basename = rpmtdNextString(basenames); - dirindex = *rpmtdNextUint32(dirindexes); - - rpmtdSetIndex(dirnames, dirindex); - dirname = rpmtdGetString(dirnames); - - snprintf(file_path, sizeof(file_path), "%s%s", dirname, - basename); - - if (!strlen(ima_digest_str)) - continue; - - hex2bin(ima_digest, ima_digest_str, hash_digest_size[algo]); - digest = ima_digest; - - if (!S_ISREG(mode)) - continue; - - if (include_path && only_executables) { - list_for_each_entry(cur, head_in, list) { - if (cur->path[0] != 'F') - continue; - - if (!strncmp(file_path, &cur->path[2], - strlen(&cur->path[2]))) { - include_file = 1; - break; - } - } - } else { - if (!only_executables) - include_file = 1; - } - - if (only_executables && (mode & (S_IXUGO | S_ISUID | S_ISVTX))) - include_file = 1; - - if (!include_file) - continue; - - if (type == COMPACT_METADATA) { - file_modifiers = modifiers; - if (((mode & S_IXUGO) || - !(mode & S_IWUGO)) && size) - file_modifiers |= (1 << COMPACT_MOD_IMMUTABLE); - - ret = gen_write_ima_xattr(ima_xattr, &ima_xattr_len, - file_path, algo, ima_digest, - (file_modifiers & (1 << COMPACT_MOD_IMMUTABLE)), - set_ima_xattr); - if (ret < 0) - goto out_close; - - if (set_evm_xattr) { - ret = write_evm_xattr(file_path, algo); - if (ret < 0) - return ret; - } - - if (include_lsm_label) { - ret = get_selinux_label(file_path, alt_root, - &obj_label, mode); - if (ret < 0) - goto out_close; - - obj_label_len = strlen(obj_label) + 1; - } - - if (filecaps_str && strlen(filecaps_str)) { - c = cap_from_text(filecaps_str); - if (!c) { - ret = -EINVAL; - goto out_close; - } - - ret = _fcaps_save(&rawvfscap, c, - &rawvfscap_len); - cap_free(c); - - if (ret < 0) - goto out_close; - } else { - rawvfscap_len = 0; - } - - ret = evm_calc_hmac_or_hash(algo, - evm_digest, obj_label_len, obj_label, - ima_xattr_len, ima_xattr, - rawvfscap_len, (u8 *)&rawvfscap, - 0, 0, mode); - if (ret < 0) - goto out_close; - - digest = evm_digest; - - s.st_uid = 0; - s.st_gid = 0; - s.st_mode = mode; - s.st_size = size; - } - - if (!tlv) { - if (type == COMPACT_METADATA && include_ima_digests) { - ret = compact_list_add_digest(fd, list_file, - ima_digest); - if (ret < 0) - goto out_free_items; - } - - ret = compact_list_add_digest(fd, list, digest); - if (ret < 0) - goto out_free_items; - - continue; - } - - if (type == COMPACT_METADATA) { - ret = compact_list_tlv_add_digest(fd, list, &items, - evm_digest, - ID_EVM_DIGEST); - if (ret < 0) - goto out_free_items; - } - - ret = compact_list_tlv_add_digest(fd, list, &items, ima_digest, - ID_DIGEST); - if (ret < 0) - goto out_free_items; - - ret = compact_list_tlv_add_metadata(fd, list, &items, file_path, - alt_root, &s, obj_label, - obj_label_len, - (u8 *)&rawvfscap, - rawvfscap_len); - if (ret < 0) - goto out_free_items; - - ret = compact_list_tlv_add_items(fd, list, &items); - if (ret < 0) { - printf("Cannot add digest to compact list\n"); - goto out_free_items; - } + const char *ima_digest_str, *filecaps_str, *basename, *dirname; + enum pgp_hash_algo pgp_algo; + char file_path[PATH_MAX]; + u8 ima_xattr[2048]; + u8 ima_digest[SHA512_DIGEST_SIZE]; + u8 evm_digest[SHA512_DIGEST_SIZE]; + LIST_HEAD(list_head); + u8 *digest; + char *obj_label = NULL; + LIST_HEAD(items); + int ret = 0, ima_xattr_len, obj_label_len = 0, include_file = 0; + rpmtd filedigestalgo, filedigests, filemodes, filesizes, filecaps; + rpmtd basenames, dirnames, dirindexes; + struct path_struct *cur; + uint16_t mode; + uint32_t size, dirindex; + u16 file_modifiers; + cap_t c; + struct vfs_cap_data rawvfscap; + int rawvfscap_len, fd; + struct list_struct *list = NULL, *list_file = NULL; + struct stat s; + + fd = openat(dirfd, filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd < 0) + return -EACCES; + + filedigestalgo = rpmtdNew(); + headerGet(*hdr, RPMTAG_FILEDIGESTALGO, filedigestalgo, 0); + filedigests = rpmtdNew(); + headerGet(*hdr, RPMTAG_FILEDIGESTS, filedigests, 0); + filemodes = rpmtdNew(); + headerGet(*hdr, RPMTAG_FILEMODES, filemodes, 0); + filesizes = rpmtdNew(); + headerGet(*hdr, RPMTAG_FILESIZES, filesizes, 0); + filecaps = rpmtdNew(); + headerGet(*hdr, RPMTAG_FILECAPS, filecaps, 0); + basenames = rpmtdNew(); + headerGet(*hdr, RPMTAG_BASENAMES, basenames, 0); + dirnames = rpmtdNew(); + headerGet(*hdr, RPMTAG_DIRNAMES, dirnames, 0); + dirindexes = rpmtdNew(); + headerGet(*hdr, RPMTAG_DIRINDEXES, dirindexes, 0); + + pgp_algo = PGP_HASH_MD5; + if (rpmtdGetUint32(filedigestalgo)) + pgp_algo = *rpmtdGetUint32(filedigestalgo); + + if (pgp_algo >= PGP_HASH__LAST) { + ret = -EINVAL; + goto out_close; + } + + algo = pgp_algo_mapping[pgp_algo]; + list = compact_list_init(&list_head, type, modifiers, algo, tlv); + if (!list) + goto out_close; + + if (type == COMPACT_METADATA && include_ima_digests) { + list_file = compact_list_init(&list_head, COMPACT_FILE, + modifiers, algo, tlv); + if (!list_file) + goto out_close; + } + + while ((ima_digest_str = rpmtdNextString(filedigests))) { + include_file = 0; + ret = 0; + + rpmtdNext(filemodes); + mode = *rpmtdGetUint16(filemodes); + size = *rpmtdNextUint32(filesizes); + filecaps_str = rpmtdNextString(filecaps); + basename = rpmtdNextString(basenames); + dirindex = *rpmtdNextUint32(dirindexes); + + rpmtdSetIndex(dirnames, dirindex); + dirname = rpmtdGetString(dirnames); + + snprintf(file_path, sizeof(file_path), "%s%s", dirname, + basename); + + if (!strlen(ima_digest_str)) + continue; + + hex2bin(ima_digest, ima_digest_str, hash_digest_size[algo]); + digest = ima_digest; + + if (!S_ISREG(mode)) + continue; + + if (include_path && only_executables) { + list_for_each_entry(cur, head_in, list) { + if (cur->path[0] != 'F') + continue; + + if (!strncmp(file_path, &cur->path[2], + strlen(&cur->path[2]))) { + include_file = 1; + break; + } + } + } else { + if (!only_executables) + include_file = 1; + } + + if (only_executables && (mode & (S_IXUGO | S_ISUID | S_ISVTX))) + include_file = 1; + + if (!include_file) + continue; + + if (type == COMPACT_METADATA) { + file_modifiers = modifiers; + if (((mode & S_IXUGO) || + !(mode & S_IWUGO)) && size) + file_modifiers |= (1 << COMPACT_MOD_IMMUTABLE); + + ret = gen_write_ima_xattr(ima_xattr, &ima_xattr_len, + file_path, algo, ima_digest, + (file_modifiers & (1 << COMPACT_MOD_IMMUTABLE)), + set_ima_xattr); + if (ret < 0) + goto out_close; + + if (set_evm_xattr) { + ret = write_evm_xattr(file_path, algo); + if (ret < 0) + return ret; + } + + if (include_lsm_label) { + ret = get_selinux_label(file_path, alt_root, + &obj_label, mode); + if (ret < 0) + goto out_close; + + obj_label_len = strlen(obj_label) + 1; + } + + if (filecaps_str && strlen(filecaps_str)) { + c = cap_from_text(filecaps_str); + if (!c) { + ret = -EINVAL; + goto out_close; + } + + ret = _fcaps_save(&rawvfscap, c, + &rawvfscap_len); + cap_free(c); + + if (ret < 0) + goto out_close; + } else { + rawvfscap_len = 0; + } + + ret = evm_calc_hmac_or_hash(algo, + evm_digest, obj_label_len, obj_label, + ima_xattr_len, ima_xattr, + rawvfscap_len, (u8 *)&rawvfscap, + 0, 0, mode); + if (ret < 0) + goto out_close; + + digest = evm_digest; + + s.st_uid = 0; + s.st_gid = 0; + s.st_mode = mode; + s.st_size = size; + } + + if (!tlv) { + if (type == COMPACT_METADATA && include_ima_digests) { + ret = compact_list_add_digest(fd, list_file, + ima_digest); + if (ret < 0) + goto out_free_items; + } + + ret = compact_list_add_digest(fd, list, digest); + if (ret < 0) + goto out_free_items; + + continue; + } + + if (type == COMPACT_METADATA) { + ret = compact_list_tlv_add_digest(fd, list, &items, + evm_digest, + ID_EVM_DIGEST); + if (ret < 0) + goto out_free_items; + } + + ret = compact_list_tlv_add_digest(fd, list, &items, ima_digest, + ID_DIGEST); + if (ret < 0) + goto out_free_items; + + ret = compact_list_tlv_add_metadata(fd, list, &items, file_path, + alt_root, &s, obj_label, + obj_label_len, + (u8 *)&rawvfscap, + rawvfscap_len); + if (ret < 0) + goto out_free_items; + + ret = compact_list_tlv_add_items(fd, list, &items); + if (ret < 0) { + printf("Cannot add digest to compact list\n"); + goto out_free_items; + } out_free_items: - compact_list_tlv_free_items(&items); - } - - if (!ret) { - ret = compact_list_flush_all(fd, &list_head); - if (ret < 0) - printf("Cannot write digest list to %s\n", filename); - } + compact_list_tlv_free_items(&items); + } + + if (!ret) { + ret = compact_list_flush_all(fd, &list_head); + if (ret < 0) + printf("Cannot write digest list to %s\n", filename); + } out_close: - fstat(fd, &s); - close(fd); - - compact_list_tlv_free_items(&items); - rpmtdFree(filedigestalgo); - rpmtdFree(filedigests); - rpmtdFree(filemodes); - rpmtdFree(filesizes); - rpmtdFree(filecaps); - rpmtdFree(basenames); - rpmtdFree(dirnames); - rpmtdFree(dirindexes); - free(obj_label); - - if (!s.st_size) - ret = -ENODATA; - - if (ret < 0) - unlinkat(dirfd, filename, 0); - else - ret = add_path_struct(filename, NULL, head_out); - - return ret; + fstat(fd, &s); + close(fd); + + compact_list_tlv_free_items(&items); + rpmtdFree(filedigestalgo); + rpmtdFree(filedigests); + rpmtdFree(filemodes); + rpmtdFree(filesizes); + rpmtdFree(filecaps); + rpmtdFree(basenames); + rpmtdFree(dirnames); + rpmtdFree(dirindexes); + free(obj_label); + + if (!s.st_size) + ret = -ENODATA; + + if (ret < 0) + unlinkat(dirfd, filename, 0); + else + ret = add_path_struct(filename, NULL, head_out); + + return ret; } static void gen_filename(Header rpm, int pos, enum compact_types type, - char *filename, int filename_len, char *output_format) + char *filename, int filename_len, char *output_format) { - rpmtd name = rpmtdNew(), version = rpmtdNew(); - rpmtd release = rpmtdNew(), arch = rpmtdNew(); - int prefix_len; - - headerGet(rpm, RPMTAG_NAME, name, 0); - headerGet(rpm, RPMTAG_VERSION, version, 0); - headerGet(rpm, RPMTAG_RELEASE, release, 0); - headerGet(rpm, RPMTAG_ARCH, arch, 0); - - prefix_len = gen_filename_prefix(filename, filename_len, pos, - output_format, type); - - snprintf(filename + prefix_len, filename_len - prefix_len, - "%s-%s-%s.%s", rpmtdGetString(name), rpmtdGetString(version), - rpmtdGetString(release), rpmtdGetString(arch)); - - rpmtdFree(name); - rpmtdFree(version); - rpmtdFree(release); - rpmtdFree(arch); + rpmtd name = rpmtdNew(), version = rpmtdNew(); + rpmtd release = rpmtdNew(), arch = rpmtdNew(); + int prefix_len; + + headerGet(rpm, RPMTAG_NAME, name, 0); + headerGet(rpm, RPMTAG_VERSION, version, 0); + headerGet(rpm, RPMTAG_RELEASE, release, 0); + headerGet(rpm, RPMTAG_ARCH, arch, 0); + + prefix_len = gen_filename_prefix(filename, filename_len, pos, + output_format, type); + + snprintf(filename + prefix_len, filename_len - prefix_len, + "%s-%s-%s.%s", rpmtdGetString(name), rpmtdGetString(version), + rpmtdGetString(release), rpmtdGetString(arch)); + + rpmtdFree(name); + rpmtdFree(version); + rpmtdFree(release); + rpmtdFree(arch); } static int find_package(Header rpm, char *package) { - rpmtd name = rpmtdNew(); - int found = 0; + rpmtd name = rpmtdNew(); + int found = 0; - headerGet(rpm, RPMTAG_NAME, name, 0); - if (!strncmp(rpmtdGetString(name), package, strlen(package))) - found = 1; + headerGet(rpm, RPMTAG_NAME, name, 0); + if (!strncmp(rpmtdGetString(name), package, strlen(package))) + found = 1; - rpmtdFree(name); - return found; + rpmtdFree(name); + return found; } static int gen_rpm_digest_list(Header rpm, int dirfd, char *filename, - struct list_head *head_out) + struct list_head *head_out) { - rpmtd immutable; - ssize_t ret; - int fd; - - fd = openat(dirfd, filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); - if (fd < 0) - return -EACCES; - - ret = write_check(fd, rpm_header_magic, sizeof(rpm_header_magic)); - if (ret < 0) - goto out; - - immutable = rpmtdNew(); - headerGet(rpm, RPMTAG_HEADERIMMUTABLE, immutable, 0); - ret = write_check(fd, immutable->data, immutable->count); - rpmtdFree(immutable); + rpmtd immutable; + ssize_t ret; + int fd; + + fd = openat(dirfd, filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd < 0) + return -EACCES; + + ret = write_check(fd, rpm_header_magic, sizeof(rpm_header_magic)); + if (ret < 0) + goto out; + + immutable = rpmtdNew(); + headerGet(rpm, RPMTAG_HEADERIMMUTABLE, immutable, 0); + ret = write_check(fd, immutable->data, immutable->count); + rpmtdFree(immutable); out: - close(fd); + close(fd); - if (ret < 0) - unlinkat(dirfd, filename, 0); - else - ret = add_path_struct(filename, NULL, head_out); + if (ret < 0) + unlinkat(dirfd, filename, 0); + else + ret = add_path_struct(filename, NULL, head_out); - return ret; + return ret; } static int write_rpm_header_signature(Header rpm, int dirfd, char *filename) { - rpmtd signature = rpmtdNew(); - u8 *data = NULL, *sig = NULL, *issuer = NULL; - size_t data_len, sig_len; - u16 algo; - int ret, fd; - - headerGet(rpm, RPMTAG_RSAHEADER, signature, 0); - ret = pgp_get_signature_data(signature->data, signature->count, &data, - &data_len, &sig, &sig_len, &issuer, &algo); - rpmtdFree(signature); - - if (ret < 0) - return ret; - - write_ima_xattr(dirfd, filename, issuer, sizeof(uint32_t), sig, sig_len, - pgp_algo_mapping[algo]); - - fd = openat(dirfd, filename, O_WRONLY | O_APPEND, 0644); - if (fd < 0) { - ret = -EACCES; - goto out; - } - - ret = write_check(fd, data, data_len); - close(fd); + rpmtd signature = rpmtdNew(); + u8 *data = NULL, *sig = NULL, *issuer = NULL; + size_t data_len, sig_len; + u16 algo; + int ret, fd; + + headerGet(rpm, RPMTAG_RSAHEADER, signature, 0); + ret = pgp_get_signature_data(signature->data, signature->count, &data, + &data_len, &sig, &sig_len, &issuer, &algo); + rpmtdFree(signature); + + if (ret < 0) + return ret; + + write_ima_xattr(dirfd, filename, issuer, sizeof(uint32_t), sig, sig_len, + pgp_algo_mapping[algo]); + + fd = openat(dirfd, filename, O_WRONLY | O_APPEND, 0644); + if (fd < 0) { + ret = -EACCES; + goto out; + } + + ret = write_check(fd, data, data_len); + close(fd); out: - free(data); - free(sig); - free(issuer); - return ret; + free(data); + free(sig); + free(issuer); + return ret; } static int find_file(struct list_head *head, char *filename) { - struct path_struct *cur; - char *filename_ptr, *cur_path_ptr; + struct path_struct *cur; + char *filename_ptr, *cur_path_ptr; - if (list_empty(head)) - return 0; + if (list_empty(head)) + return 0; - list_for_each_entry(cur, head, list) { - cur_path_ptr = strchr(cur->path, '-') + 1; - cur_path_ptr = strchr(cur_path_ptr, '-') + 1; + list_for_each_entry(cur, head, list) { + cur_path_ptr = strchr(cur->path, '-') + 1; + cur_path_ptr = strchr(cur_path_ptr, '-') + 1; - filename_ptr = strchr(filename, '-') + 1; - filename_ptr = strchr(filename_ptr, '-') + 1; + filename_ptr = strchr(filename, '-') + 1; + filename_ptr = strchr(filename_ptr, '-') + 1; - if (!strcmp(cur_path_ptr, filename)) - return 1; - } + if (!strcmp(cur_path_ptr, filename)) + return 1; + } - return 0; + return 0; } static int parse_options(struct list_head *head_in, bool tlv, - int *include_ima_digests, int *include_lsm_label, - int *only_executables, int *include_path, - char **output_format, char **package, - int *set_ima_xattr, int *set_evm_xattr) + int *include_ima_digests, int *include_lsm_label, + int *only_executables, int *include_path, + char **output_format, char **package, + int *set_ima_xattr, int *set_evm_xattr) { - struct path_struct *cur; - - list_for_each_entry(cur, head_in, list) { - if (cur->path[1] != ':') { - pr_err("Options must be in the format :\n"); - return -EINVAL; - } - - if (cur->path[0] == 'i') - *include_ima_digests = 1; - if (cur->path[0] == 'F') - *include_path = 1; - if (cur->path[0] == 'l') - *include_lsm_label = 1; - if (cur->path[0] == 'e') - *only_executables = 1; - if (cur->path[0] == 'f') - *output_format = &cur->path[2]; - if (cur->path[0] == 'p') - *package = &cur->path[2]; - if (cur->path[0] == 'x') { - if (!strcmp(&cur->path[2], "evm")) - *set_evm_xattr = 1; - else - *set_ima_xattr = 1; - } - } - - if (!strcmp(*output_format, "compact") && tlv) { - pr_err("Compact TLV must be selected\n"); - return -EINVAL; - } - - return 0; + struct path_struct *cur; + + list_for_each_entry(cur, head_in, list) { + if (cur->path[1] != ':') { + pr_err("Options must be in the format :\n"); + return -EINVAL; + } + + if (cur->path[0] == 'i') + *include_ima_digests = 1; + if (cur->path[0] == 'F') + *include_path = 1; + if (cur->path[0] == 'l') + *include_lsm_label = 1; + if (cur->path[0] == 'e') + *only_executables = 1; + if (cur->path[0] == 'f') + *output_format = &cur->path[2]; + if (cur->path[0] == 'p') + *package = &cur->path[2]; + if (cur->path[0] == 'x') { + if (!strcmp(&cur->path[2], "evm")) + *set_evm_xattr = 1; + else + *set_ima_xattr = 1; + } + } + + if (!strcmp(*output_format, "compact") && tlv) { + pr_err("Compact TLV must be selected\n"); + return -EINVAL; + } + + return 0; } int db_generator(int dirfd, int pos, struct list_head *head_in, - struct list_head *head_out, enum compact_types type, - u16 modifiers, enum hash_algo algo, enum hash_algo ima_algo, - bool tlv, char *alt_root) + struct list_head *head_out, enum compact_types type, + u16 modifiers, enum hash_algo algo, enum hash_algo ima_algo, + bool tlv, char *alt_root) { - char filename[NAME_MAX + 1]; - rpmts ts = NULL; - Header hdr; - rpmdbMatchIterator mi; - LIST_HEAD(digest_list_head); - int include_ima_digests = 0, include_lsm_label = 0, set_evm_xattr = 0; - int only_executables = 0, include_path = 0, set_ima_xattr = 0; - char *output_format = FORMAT; - char *package = NULL; - int ret; - - ret = parse_options(head_in, tlv, &include_ima_digests, - &include_lsm_label, &only_executables, - &include_path, &output_format, &package, - &set_ima_xattr, &set_evm_xattr); - if (ret < 0) - return ret; - - ret = get_digest_lists(dirfd, type, &digest_list_head); - if (ret < 0) - goto out; - - ts = rpmtsCreate(); - if (!ts) { - rpmlog(RPMLOG_NOTICE, "rpmtsCreate() error..\n"); - ret = -EACCES; - goto out; - } - - ret = rpmReadConfigFiles(NULL, NULL); - if (ret != RPMRC_OK) { - rpmlog(RPMLOG_NOTICE, "Unable to read RPM configuration.\n"); - ret = -EACCES; - goto out; - } - - if (!strncmp(output_format, "compact", 7)) { - if (include_lsm_label) { - ret = selinux_init_setup(); - if (ret) - return ret; - } - - if (!strcmp(output_format, "compact_tlv")) - tlv = true; - } - - mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, NULL, 0); - while ((hdr = rpmdbNextIterator(mi)) != NULL) { - gen_filename(hdr, pos, type, filename, sizeof(filename), - output_format); - - if (strstr(filename, "gpg-pubkey") != NULL) - continue; - - if (find_file(&digest_list_head, filename)) - continue; - - if (package && !find_package(hdr, package)) - continue; - - if (!strncmp(output_format, "compact", 7)) - ret = add_file(dirfd, filename, &hdr, type, modifiers, - head_in, head_out, algo, ima_algo, tlv, - include_ima_digests, include_lsm_label, - only_executables, include_path, - set_ima_xattr, set_evm_xattr, alt_root); - else { - ret = gen_rpm_digest_list(hdr, dirfd, filename, - head_out); - if (ret < 0) - break; - - ret = write_rpm_header_signature(hdr, dirfd, filename); - if (ret < 0) { - printf("Warning: signature not found in %s\n", - filename); - ret = 0; - } - } - - if (ret < 0 && ret != -ENODATA) { - printf("Cannot generate %s digest list\n", filename); - break; - } - - if (!ret && pos >= 0) - pos++; - } - - if (ret == -ENODATA) - ret = 0; - - rpmdbFreeIterator(mi); - rpmFreeRpmrc(); - rpmtsFree(ts); + char filename[NAME_MAX + 1]; + rpmts ts = NULL; + Header hdr; + rpmdbMatchIterator mi; + LIST_HEAD(digest_list_head); + int include_ima_digests = 0, include_lsm_label = 0, set_evm_xattr = 0; + int only_executables = 0, include_path = 0, set_ima_xattr = 0; + char *output_format = FORMAT; + char *package = NULL; + int ret; + + ret = parse_options(head_in, tlv, &include_ima_digests, + &include_lsm_label, &only_executables, + &include_path, &output_format, &package, + &set_ima_xattr, &set_evm_xattr); + if (ret < 0) + return ret; + + ret = get_digest_lists(dirfd, type, &digest_list_head); + if (ret < 0) + goto out; + + ts = rpmtsCreate(); + if (!ts) { + rpmlog(RPMLOG_NOTICE, "rpmtsCreate() error..\n"); + ret = -EACCES; + goto out; + } + + ret = rpmReadConfigFiles(NULL, NULL); + if (ret != RPMRC_OK) { + rpmlog(RPMLOG_NOTICE, "Unable to read RPM configuration.\n"); + ret = -EACCES; + goto out; + } + + if (!strncmp(output_format, "compact", 7)) { + if (include_lsm_label) { + ret = selinux_init_setup(); + if (ret) + return ret; + } + + if (!strcmp(output_format, "compact_tlv")) + tlv = true; + } + + mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, NULL, 0); + while ((hdr = rpmdbNextIterator(mi)) != NULL) { + gen_filename(hdr, pos, type, filename, sizeof(filename), + output_format); + + if (strstr(filename, "gpg-pubkey") != NULL) + continue; + + if (find_file(&digest_list_head, filename)) + continue; + + if (package && !find_package(hdr, package)) + continue; + + if (!strncmp(output_format, "compact", 7)) + ret = add_file(dirfd, filename, &hdr, type, modifiers, + head_in, head_out, algo, ima_algo, tlv, + include_ima_digests, include_lsm_label, + only_executables, include_path, + set_ima_xattr, set_evm_xattr, alt_root); + else { + ret = gen_rpm_digest_list(hdr, dirfd, filename, + head_out); + if (ret < 0) + break; + + ret = write_rpm_header_signature(hdr, dirfd, filename); + if (ret < 0) { + printf("Warning: signature not found in %s\n", + filename); + ret = 0; + } + } + + if (ret < 0 && ret != -ENODATA) { + printf("Cannot generate %s digest list\n", filename); + break; + } + + if (!ret && pos >= 0) + pos++; + } + + if (ret == -ENODATA) + ret = 0; + + rpmdbFreeIterator(mi); + rpmFreeRpmrc(); + rpmtsFree(ts); out: - if (!strncmp(output_format, "compact", 7) && include_lsm_label) - selinux_end_setup(); + if (!strncmp(output_format, "compact", 7) && include_lsm_label) + selinux_end_setup(); - free_path_structs(&digest_list_head); - return ret; + free_path_structs(&digest_list_head); + return ret; } static int _pkg_generator(int dirfd, int pos, char *path, - struct list_head *head_in, struct list_head *head_out, - enum compact_types type, int modifiers, - enum hash_algo algo, enum hash_algo ima_algo, - bool tlv, char *output_format, - int include_ima_digests, int include_lsm_label, - int only_executables, int include_path, - int set_ima_xattr, int set_evm_xattr, char *alt_root) + struct list_head *head_in, struct list_head *head_out, + enum compact_types type, int modifiers, + enum hash_algo algo, enum hash_algo ima_algo, + bool tlv, char *output_format, + int include_ima_digests, int include_lsm_label, + int only_executables, int include_path, + int set_ima_xattr, int set_evm_xattr, char *alt_root) { - char filename[NAME_MAX + 1]; - Header hdr; - rpmts ts = NULL; - FD_t fd; - int ret; - rpmVSFlags vsflags = 0; - - ts = rpmtsCreate(); - if (!ts) { - rpmlog(RPMLOG_NOTICE, "rpmtsCreate() error..\n"); - return -EACCES; - } - - ret = rpmReadConfigFiles(NULL, NULL); - if (ret != RPMRC_OK) { - rpmlog(RPMLOG_NOTICE, "Unable to read RPM configuration.\n"); - ret = -EACCES; - goto out_ts; - } - - vsflags |= _RPMVSF_NODIGESTS; - vsflags |= _RPMVSF_NOSIGNATURES; - rpmtsSetVSFlags(ts, vsflags); - - fd = Fopen(path, "r.ufdio"); - if ((!fd) || Ferror(fd)) { - rpmlog(RPMLOG_NOTICE, "Failed to open package file %s, %s\n", - path, Fstrerror(fd)); - ret = -EACCES; - goto out_ts; - } - - ret = rpmReadPackageFile(ts, fd, "rpm", &hdr); - if (ret != RPMRC_OK) { - rpmlog(RPMLOG_NOTICE, "Could not read package file %s\n", path); - goto out_fd; - } - - gen_filename(hdr, pos, type, filename, sizeof(filename), output_format); - - if (!strncmp(output_format, "compact", 7)) - ret = add_file(dirfd, filename, &hdr, type, modifiers, - head_in, head_out, algo, ima_algo, tlv, - include_ima_digests, include_lsm_label, - only_executables, include_path, set_ima_xattr, - set_evm_xattr, alt_root); - else { - ret = gen_rpm_digest_list(hdr, dirfd, filename, head_out); - if (ret < 0 && ret != -ENODATA) { - printf("Cannot generate %s digest list\n", filename); - goto out_fd; - } - - ret = write_rpm_header_signature(hdr, dirfd, filename); - if (ret < 0) { - printf("Warning: signature not found in %s\n", - filename); - ret = 0; - } - } + char filename[NAME_MAX + 1]; + Header hdr; + rpmts ts = NULL; + FD_t fd; + int ret; + rpmVSFlags vsflags = 0; + + ts = rpmtsCreate(); + if (!ts) { + rpmlog(RPMLOG_NOTICE, "rpmtsCreate() error..\n"); + return -EACCES; + } + + ret = rpmReadConfigFiles(NULL, NULL); + if (ret != RPMRC_OK) { + rpmlog(RPMLOG_NOTICE, "Unable to read RPM configuration.\n"); + ret = -EACCES; + goto out_ts; + } + + vsflags |= _RPMVSF_NODIGESTS; + vsflags |= _RPMVSF_NOSIGNATURES; + rpmtsSetVSFlags(ts, vsflags); + + fd = Fopen(path, "r.ufdio"); + if ((!fd) || Ferror(fd)) { + rpmlog(RPMLOG_NOTICE, "Failed to open package file %s, %s\n", + path, Fstrerror(fd)); + ret = -EACCES; + goto out_ts; + } + + ret = rpmReadPackageFile(ts, fd, "rpm", &hdr); + if (ret != RPMRC_OK) { + rpmlog(RPMLOG_NOTICE, "Could not read package file %s\n", path); + goto out_fd; + } + + gen_filename(hdr, pos, type, filename, sizeof(filename), output_format); + + if (!strncmp(output_format, "compact", 7)) + ret = add_file(dirfd, filename, &hdr, type, modifiers, + head_in, head_out, algo, ima_algo, tlv, + include_ima_digests, include_lsm_label, + only_executables, include_path, set_ima_xattr, + set_evm_xattr, alt_root); + else { + ret = gen_rpm_digest_list(hdr, dirfd, filename, head_out); + if (ret < 0 && ret != -ENODATA) { + printf("Cannot generate %s digest list\n", filename); + goto out_fd; + } + + ret = write_rpm_header_signature(hdr, dirfd, filename); + if (ret < 0) { + printf("Warning: signature not found in %s\n", + filename); + ret = 0; + } + } out_fd: - Fclose(fd); + Fclose(fd); out_ts: - rpmtsFree(ts); - return ret; + rpmtsFree(ts); + return ret; } int pkg_generator(int dirfd, int pos, struct list_head *head_in, - struct list_head *head_out, enum compact_types type, - u16 modifiers, enum hash_algo algo, enum hash_algo ima_algo, - bool tlv, char *alt_root) + struct list_head *head_out, enum compact_types type, + u16 modifiers, enum hash_algo algo, enum hash_algo ima_algo, + bool tlv, char *alt_root) { - struct path_struct *cur; - int include_ima_digests = 0, include_lsm_label = 0, set_evm_xattr = 0; - int only_executables = 0, include_path = 0, set_ima_xattr = 0; - char *output_format = FORMAT; - char *package = NULL; - FTS *fts; - FTSENT *ftsent; - char *paths[2] = { NULL, NULL }; - int fts_flags = (FTS_PHYSICAL | FTS_COMFOLLOW | FTS_NOCHDIR | FTS_XDEV); - int ret = 0; - - if (list_empty(head_in)) { - printf("Input path not specified\n"); - return -EINVAL; - } - - ret = parse_options(head_in, tlv, &include_ima_digests, - &include_lsm_label, &only_executables, - &include_path, &output_format, &package, - &set_ima_xattr, &set_evm_xattr); - if (ret < 0) - return ret; - - if (!strncmp(output_format, "compact", 7)) { - if (include_lsm_label) { - ret = selinux_init_setup(); - if (ret) - return ret; - } - - if (!strcmp(output_format, "compact_tlv")) - tlv = true; - } - - list_for_each_entry(cur, head_in, list) { - if (cur->path[0] != 'I') - continue; - - paths[0] = &cur->path[2]; - - fts = fts_open(paths, fts_flags, NULL); - if (!fts) - return -EACCES; - - while ((ftsent = fts_read(fts)) != NULL) { - switch (ftsent->fts_info) { - case FTS_F: - ret = _pkg_generator(dirfd, pos, - ftsent->fts_path, head_in, head_out, - type, modifiers, algo, ima_algo, tlv, - output_format, include_ima_digests, - include_lsm_label, only_executables, - include_path, set_ima_xattr, - set_evm_xattr, alt_root); - if (ret < 0 && ret != -ENOENT && - ret != -ENODATA) - goto out_fts_close; - - if (!ret && pos >= 0) - pos++; - break; - default: - break; - } - } - - fts_close(fts); - fts = NULL; - } + struct path_struct *cur; + int include_ima_digests = 0, include_lsm_label = 0, set_evm_xattr = 0; + int only_executables = 0, include_path = 0, set_ima_xattr = 0; + char *output_format = FORMAT; + char *package = NULL; + FTS *fts; + FTSENT *ftsent; + char *paths[2] = { NULL, NULL }; + int fts_flags = (FTS_PHYSICAL | FTS_COMFOLLOW | FTS_NOCHDIR | FTS_XDEV); + int ret = 0; + + if (list_empty(head_in)) { + printf("Input path not specified\n"); + return -EINVAL; + } + + ret = parse_options(head_in, tlv, &include_ima_digests, + &include_lsm_label, &only_executables, + &include_path, &output_format, &package, + &set_ima_xattr, &set_evm_xattr); + if (ret < 0) + return ret; + + if (!strncmp(output_format, "compact", 7)) { + if (include_lsm_label) { + ret = selinux_init_setup(); + if (ret) + return ret; + } + + if (!strcmp(output_format, "compact_tlv")) + tlv = true; + } + + list_for_each_entry(cur, head_in, list) { + if (cur->path[0] != 'I') + continue; + + paths[0] = &cur->path[2]; + + fts = fts_open(paths, fts_flags, NULL); + if (!fts) + return -EACCES; + + while ((ftsent = fts_read(fts)) != NULL) { + switch (ftsent->fts_info) { + case FTS_F: + ret = _pkg_generator(dirfd, pos, + ftsent->fts_path, head_in, head_out, + type, modifiers, algo, ima_algo, tlv, + output_format, include_ima_digests, + include_lsm_label, only_executables, + include_path, set_ima_xattr, + set_evm_xattr, alt_root); + if (ret < 0 && ret != -ENOENT && + ret != -ENODATA) + goto out_fts_close; + + if (!ret && pos >= 0) + pos++; + break; + default: + break; + } + } + + fts_close(fts); + fts = NULL; + } out_fts_close: - if (fts) - fts_close(fts); + if (fts) + fts_close(fts); - if (ret == -ENOENT || ret == -ENODATA) - ret = 0; + if (ret == -ENOENT || ret == -ENODATA) + ret = 0; - if (!strncmp(output_format, "compact", 7) && include_lsm_label) - selinux_end_setup(); + if (!strncmp(output_format, "compact", 7) && include_lsm_label) + selinux_end_setup(); - return ret; + return ret; } diff --git a/generators/unknown.c b/generators/unknown.c index bc33ceb..8e9b15c 100644 --- a/generators/unknown.c +++ b/generators/unknown.c @@ -35,507 +35,507 @@ #define FORMAT_TLV "compact_tlv" static int add_file(int dirfd, int fd, char *path, u16 type, u16 modifiers, - struct stat *st, struct list_struct *list, - struct list_struct *list_file, enum hash_algo algo, - enum hash_algo ima_algo, bool tlv, bool gen_list, - bool include_lsm_label, bool root_cred, bool set_ima_xattr, - bool set_evm_xattr, char *alt_root, char *caps, - char *file_digest) + struct stat *st, struct list_struct *list, + struct list_struct *list_file, enum hash_algo algo, + enum hash_algo ima_algo, bool tlv, bool gen_list, + bool include_lsm_label, bool root_cred, bool set_ima_xattr, + bool set_evm_xattr, char *alt_root, char *caps, + char *file_digest) { - cap_t c; - struct ima_digest *found_digest; - struct vfs_cap_data rawvfscap; - u8 ima_xattr[2 + SHA512_DIGEST_SIZE]; - u8 ima_digest[SHA512_DIGEST_SIZE]; - u8 evm_digest[SHA512_DIGEST_SIZE]; - u8 *digest = ima_digest; - char *obj_label = NULL; - u8 *caps_bin = NULL; - struct stat s; - LIST_HEAD(items); - int gen_ima_xattr = 1; - int ret, ima_xattr_len, obj_label_len = 0, caps_bin_len = 0; - - if (!S_ISREG(st->st_mode)) - return -ENOENT; - - if (root_cred) { - memcpy(&s, st, sizeof(s)); - s.st_uid = 0; - s.st_gid = 0; - st = &s; - } - - if (((st->st_mode & S_IXUGO) || !(st->st_mode & S_IWUGO)) && - st->st_size) - modifiers |= (1 << COMPACT_MOD_IMMUTABLE); - - if (!file_digest) { - ret = calc_file_digest(digest, -1, path, algo); - if (ret < 0) { - printf("Cannot calculate digest of %s\n", path); - goto out; - } - } else { - hex2bin(digest, file_digest, hash_digest_size[algo]); - } - - if (type == COMPACT_METADATA || tlv) { - ima_xattr_len = getxattr(path, XATTR_NAME_IMA, NULL, 0); - if (!gen_ima_xattr && - ima_xattr_len > 0 && ima_xattr_len < sizeof(ima_xattr)) { - ima_xattr_len = getxattr(path, XATTR_NAME_IMA, - ima_xattr, ima_xattr_len); - if (ima_xattr_len) - gen_ima_xattr = 0; - } - - if (gen_ima_xattr) { - ret = gen_write_ima_xattr(ima_xattr, &ima_xattr_len, - path, algo, ima_digest, - (modifiers & (1 << COMPACT_MOD_IMMUTABLE)), - set_ima_xattr); - if (ret < 0) - return ret; - } - - if (set_evm_xattr) { - ret = write_evm_xattr(path, algo); - if (ret < 0) - return ret; - } - - if (include_lsm_label) - obj_label_len = getxattr(path, XATTR_NAME_SELINUX, - NULL, 0); - if (obj_label_len > 0) { - obj_label = malloc(obj_label_len); - if (!obj_label) - return -ENOMEM; - - obj_label_len = getxattr(path, XATTR_NAME_SELINUX, - obj_label, obj_label_len); - if (obj_label_len <= 0) { - ret = -EACCES; - goto out; - } - } else { - obj_label_len = 0; - } - - if (include_lsm_label == 2) { - ret = get_selinux_label(path, alt_root, &obj_label, - st->st_mode); - if (!ret && obj_label) - obj_label_len = strlen(obj_label) + 1; - } - - if (caps && strlen(caps)) { - c = cap_from_text(caps); - if (!c) { - ret = -ENOMEM; - goto out; - } - - ret = _fcaps_save(&rawvfscap, c, &caps_bin_len); - if (!ret) { - caps_bin = malloc(caps_bin_len); - if (!caps_bin) { - ret = -ENOMEM; - goto out; - } - - memcpy(caps_bin, (u8 *)&rawvfscap, - caps_bin_len); - } - - cap_free(c); - } else { - caps_bin_len = getxattr(path, XATTR_NAME_CAPS, NULL, 0); - if (caps_bin_len > 0) { - caps_bin = malloc(caps_bin_len); - if (!caps_bin) { - ret = -ENOMEM; - goto out; - } - - caps_bin_len = getxattr(path, XATTR_NAME_CAPS, - caps_bin, caps_bin_len); - if (caps_bin_len <= 0) { - ret = -EACCES; - goto out; - } - } else { - caps_bin_len = 0; - } - } - - ret = evm_calc_hmac_or_hash(algo, evm_digest, - obj_label_len, obj_label, - ima_xattr_len, ima_xattr, - caps_bin_len, caps_bin, - st->st_uid, st->st_gid, - st->st_mode); - if (ret < 0) - goto out; - - if (type == COMPACT_METADATA) - digest = evm_digest; - } - - found_digest = ima_lookup_digest(digest, algo); - if (found_digest) { - ret = -EEXIST; - goto out; - } - - if (gen_list) { - ret = write_check(fd, path, strlen(path)); - if (!ret) - ret = write_check(fd, "\n", 1); - - return ret; - } - - if (!tlv) { - if (type == COMPACT_METADATA && list_file) { - ret = compact_list_add_digest(fd, list_file, - ima_digest); - if (ret < 0) - goto out; - } - - ret = compact_list_add_digest(fd, list, digest); - goto out; - } - - if (type == COMPACT_METADATA) { - ret = compact_list_tlv_add_digest(fd, list, &items, evm_digest, - ID_EVM_DIGEST); - if (ret < 0) - goto out_free_items; - } - - ret = compact_list_tlv_add_digest(fd, list, &items, ima_digest, - ID_DIGEST); - if (ret < 0) - goto out_free_items; - - ret = compact_list_tlv_add_metadata(fd, list, &items, path, alt_root, - st, obj_label, obj_label_len, - caps_bin, caps_bin_len); - if (ret < 0) - goto out_free_items; - - ret = compact_list_tlv_add_items(fd, list, &items); + cap_t c; + struct ima_digest *found_digest; + struct vfs_cap_data rawvfscap; + u8 ima_xattr[2 + SHA512_DIGEST_SIZE]; + u8 ima_digest[SHA512_DIGEST_SIZE]; + u8 evm_digest[SHA512_DIGEST_SIZE]; + u8 *digest = ima_digest; + char *obj_label = NULL; + u8 *caps_bin = NULL; + struct stat s; + LIST_HEAD(items); + int gen_ima_xattr = 1; + int ret, ima_xattr_len, obj_label_len = 0, caps_bin_len = 0; + + if (!S_ISREG(st->st_mode)) + return -ENOENT; + + if (root_cred) { + memcpy(&s, st, sizeof(s)); + s.st_uid = 0; + s.st_gid = 0; + st = &s; + } + + if (((st->st_mode & S_IXUGO) || !(st->st_mode & S_IWUGO)) && + st->st_size) + modifiers |= (1 << COMPACT_MOD_IMMUTABLE); + + if (!file_digest) { + ret = calc_file_digest(digest, -1, path, algo); + if (ret < 0) { + printf("Cannot calculate digest of %s\n", path); + goto out; + } + } else { + hex2bin(digest, file_digest, hash_digest_size[algo]); + } + + if (type == COMPACT_METADATA || tlv) { + ima_xattr_len = getxattr(path, XATTR_NAME_IMA, NULL, 0); + if (!gen_ima_xattr && + ima_xattr_len > 0 && ima_xattr_len < sizeof(ima_xattr)) { + ima_xattr_len = getxattr(path, XATTR_NAME_IMA, + ima_xattr, ima_xattr_len); + if (ima_xattr_len) + gen_ima_xattr = 0; + } + + if (gen_ima_xattr) { + ret = gen_write_ima_xattr(ima_xattr, &ima_xattr_len, + path, algo, ima_digest, + (modifiers & (1 << COMPACT_MOD_IMMUTABLE)), + set_ima_xattr); + if (ret < 0) + return ret; + } + + if (set_evm_xattr) { + ret = write_evm_xattr(path, algo); + if (ret < 0) + return ret; + } + + if (include_lsm_label) + obj_label_len = getxattr(path, XATTR_NAME_SELINUX, + NULL, 0); + if (obj_label_len > 0) { + obj_label = malloc(obj_label_len); + if (!obj_label) + return -ENOMEM; + + obj_label_len = getxattr(path, XATTR_NAME_SELINUX, + obj_label, obj_label_len); + if (obj_label_len <= 0) { + ret = -EACCES; + goto out; + } + } else { + obj_label_len = 0; + } + + if (include_lsm_label == 2) { + ret = get_selinux_label(path, alt_root, &obj_label, + st->st_mode); + if (!ret && obj_label) + obj_label_len = strlen(obj_label) + 1; + } + + if (caps && strlen(caps)) { + c = cap_from_text(caps); + if (!c) { + ret = -ENOMEM; + goto out; + } + + ret = _fcaps_save(&rawvfscap, c, &caps_bin_len); + if (!ret) { + caps_bin = malloc(caps_bin_len); + if (!caps_bin) { + ret = -ENOMEM; + goto out; + } + + memcpy(caps_bin, (u8 *)&rawvfscap, + caps_bin_len); + } + + cap_free(c); + } else { + caps_bin_len = getxattr(path, XATTR_NAME_CAPS, NULL, 0); + if (caps_bin_len > 0) { + caps_bin = malloc(caps_bin_len); + if (!caps_bin) { + ret = -ENOMEM; + goto out; + } + + caps_bin_len = getxattr(path, XATTR_NAME_CAPS, + caps_bin, caps_bin_len); + if (caps_bin_len <= 0) { + ret = -EACCES; + goto out; + } + } else { + caps_bin_len = 0; + } + } + + ret = evm_calc_hmac_or_hash(algo, evm_digest, + obj_label_len, obj_label, + ima_xattr_len, ima_xattr, + caps_bin_len, caps_bin, + st->st_uid, st->st_gid, + st->st_mode); + if (ret < 0) + goto out; + + if (type == COMPACT_METADATA) + digest = evm_digest; + } + + found_digest = ima_lookup_digest(digest, algo); + if (found_digest) { + ret = -EEXIST; + goto out; + } + + if (gen_list) { + ret = write_check(fd, path, strlen(path)); + if (!ret) + ret = write_check(fd, "\n", 1); + + return ret; + } + + if (!tlv) { + if (type == COMPACT_METADATA && list_file) { + ret = compact_list_add_digest(fd, list_file, + ima_digest); + if (ret < 0) + goto out; + } + + ret = compact_list_add_digest(fd, list, digest); + goto out; + } + + if (type == COMPACT_METADATA) { + ret = compact_list_tlv_add_digest(fd, list, &items, evm_digest, + ID_EVM_DIGEST); + if (ret < 0) + goto out_free_items; + } + + ret = compact_list_tlv_add_digest(fd, list, &items, ima_digest, + ID_DIGEST); + if (ret < 0) + goto out_free_items; + + ret = compact_list_tlv_add_metadata(fd, list, &items, path, alt_root, + st, obj_label, obj_label_len, + caps_bin, caps_bin_len); + if (ret < 0) + goto out_free_items; + + ret = compact_list_tlv_add_items(fd, list, &items); out_free_items: - compact_list_tlv_free_items(&items); + compact_list_tlv_free_items(&items); out: - free(obj_label); - free(caps_bin); - return ret; + free(obj_label); + free(caps_bin); + return ret; } int generator(int dirfd, int pos, struct list_head *head_in, - struct list_head *head_out, enum compact_types type, - u16 modifiers, enum hash_algo algo, enum hash_algo ima_algo, - bool tlv, char *alt_root) + struct list_head *head_out, enum compact_types type, + u16 modifiers, enum hash_algo algo, enum hash_algo ima_algo, + bool tlv, char *alt_root) { - struct path_struct *cur, *cur_i, *cur_e; - FTS *fts = NULL; - FTSENT *ftsent; - char *paths[2] = { "/", NULL }; - struct list_struct *list = NULL, *list_file = NULL; - char filename[NAME_MAX + 1]; - char path[PATH_MAX]; - char *digest_lists_dir = NULL, *path_list = NULL, *gen_list_path = NULL; - char *data_ptr, *line_ptr, *real_path; - void *data; - loff_t size; - time_t t = time(NULL); - bool unlink = true; - struct tm tm; - struct stat st, *statp; - LIST_HEAD(list_head); - char *attrs[ATTR__LAST]; - struct passwd *pwd; - struct group *grp; - enum hash_algo list_algo; - int include_ima_digests = 0, only_executables = 0, root_cred = 0; - int include_path = 0, include_file = 0, set_ima_xattr = 0; - int path_list_ext = 0, set_evm_xattr = 0, alt_root_len; - int fts_flags = (FTS_PHYSICAL | FTS_COMFOLLOW | FTS_NOCHDIR | FTS_XDEV); - int ret, i, digest_lists_dirfd, fd, prefix_len, include_lsm_label = 0; - - if (pos == -1) - pos = 0; - - list_for_each_entry(cur, head_in, list) { - if (cur->path[1] != ':') { - pr_err("Options must be in the format :\n"); - return -EINVAL; - } - - if (cur->path[0] == 'i') - include_ima_digests = 1; - if (cur->path[0] == 'D') - digest_lists_dir = &cur->path[2]; - if (cur->path[0] == 'L') - path_list = &cur->path[2]; - if (cur->path[0] == 'M') - path_list_ext = 1; - if (cur->path[0] == 'G') - gen_list_path = &cur->path[2]; - if (cur->path[0] == 'l') { - if (!strcmp(&cur->path[2], "policy")) - include_lsm_label = 2; - else - include_lsm_label = 1; - } - if (cur->path[0] == 'e') - only_executables = 1; - if (cur->path[0] == 'r') - root_cred = 1; - if (cur->path[0] == 'F') - include_path = 1; - if (cur->path[0] == 'x') { - if (!strcmp(&cur->path[2], "evm")) - set_evm_xattr = 1; - else - set_ima_xattr = 1; - } - } - - if (!digest_lists_dir) { - pr_err("Digest lists directory not specified\n"); - return -EINVAL; - } - - if (path_list) { - ret = read_file_from_path(-1, path_list, &data, &size); - if (ret < 0) - return ret; - - data_ptr = (char *)data; - - while ((line_ptr = strsep(&data_ptr, "\n"))) { - if (!strlen(line_ptr)) - continue; - - if (path_list_ext) { - parse_file_attrs(line_ptr, attrs); - line_ptr = attrs[ATTR_PATH]; - } - - if (!line_ptr || stat(line_ptr, &st) == -1 || - !S_ISREG(st.st_mode)) - continue; - - snprintf(path, sizeof(path), "I:%s", line_ptr); - ret = add_path_struct(path, attrs, head_in); - if (ret < 0) - return ret; - } - } - - digest_lists_dirfd = open(digest_lists_dir, O_RDONLY | O_DIRECTORY); - if (digest_lists_dirfd < 0) { - pr_err("Unable to open %s, ret: %d\n", digest_lists_dir, - digest_lists_dirfd); - return digest_lists_dirfd; - } - - if (type == COMPACT_METADATA && include_lsm_label) { - ret = selinux_init_setup(); - if (ret) - goto out; - } - - for (i = 0; i < COMPACT__LAST; i++) { - ret = process_lists(digest_lists_dirfd, -1, 0, 0, &list_head, i, - (type == COMPACT_METADATA) ? - PARSER_OP_ADD_META_DIGEST_TO_HTABLE : - PARSER_OP_ADD_DIGEST_TO_HTABLE, - digest_lists_dir, filename); - if (ret < 0) - goto out_selinux; - } - - compact_list_flush_all(-1, &list_head); - - if (!gen_list_path) { - tm = *localtime(&t); - - prefix_len = gen_filename_prefix(filename, sizeof(filename), - pos, tlv ? FORMAT_TLV : FORMAT, type); - snprintf(filename + prefix_len, sizeof(filename) - prefix_len, - "%04d%02d%02d_%02d%02d%02d", tm.tm_year + 1900, - tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, - tm.tm_sec); - - fd = openat(dirfd, filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); - } else { - fd = openat(-1, gen_list_path, O_WRONLY | O_CREAT | O_TRUNC, 0644); - } - - if (fd < 0) { - pr_err("Cannot open %s\n", filename); - ret = -EACCES; - goto out_selinux; - } - - list = compact_list_init(&list_head, type, modifiers, algo, tlv); - if (!list) - goto out_close; - - if (type == COMPACT_METADATA && include_ima_digests) { - list_file = compact_list_init(&list_head, COMPACT_FILE, - modifiers, algo, tlv); - if (!list_file) - goto out_close; - } - - list_for_each_entry(cur, head_in, list) { - if (cur->path[0] != 'I') - continue; - - if (path_list_ext) { - pwd = NULL; - grp = NULL; - list_algo = algo; - - if (cur->attrs[ATTR_MODE]) - st.st_mode = strtol(cur->attrs[ATTR_MODE], - NULL, 10); - st.st_uid = 0; - if (cur->attrs[ATTR_UNAME]) - pwd = getpwnam(cur->attrs[ATTR_UNAME]); - if (pwd) - st.st_uid = pwd->pw_uid; - st.st_gid = 0; - if (cur->attrs[ATTR_GNAME]) - grp = getgrnam(cur->attrs[ATTR_GNAME]); - if (grp) - st.st_gid = grp->gr_gid; - if (cur->attrs[ATTR_DIGESTALGO]) - list_algo = strtol(cur->attrs[ATTR_DIGESTALGO], - NULL, 10); - if (cur->attrs[ATTR_DIGESTALGOPGP]) { - list_algo = pgp_algo_mapping[strtol( - cur->attrs[ATTR_DIGESTALGOPGP], - NULL, 10)]; - } - if (list_algo != algo) - continue; - } - - paths[0] = &cur->path[2]; - - fts = fts_open(paths, fts_flags, NULL); - if (!fts) - goto out_close; - - while ((ftsent = fts_read(fts)) != NULL) { - switch (ftsent->fts_info) { - case FTS_F: - real_path = ftsent->fts_path; - alt_root_len = alt_root ? strlen(alt_root) : 0; - - if (alt_root && - alt_root_len < strlen(real_path)) - real_path += alt_root_len; - - include_file = 0; - statp = ftsent->fts_statp; - if (path_list_ext) { - st.st_size = statp->st_size; - statp = &st; - } - - if (include_path && only_executables) { - list_for_each_entry(cur_i, head_in, - list) { - if (cur_i->path[0] != 'F') - continue; - - if (!strncmp(real_path, - &cur_i->path[2], - strlen(&cur_i->path[2]))) { - include_file = 1; - break; - } - } - } else { - if (!only_executables) - include_file = 1; - } - - if (only_executables && - (statp->st_mode & S_IXUGO)) - include_file = 1; - - if (!include_file) - continue; - - include_file = 1; - - list_for_each_entry(cur_e, head_in, list) { - if (cur_e->path[0] == 'E' && - !strncmp(&cur_e->path[2], - real_path, - strlen(&cur_e->path[2]))) { - include_file = 0; - break; - } - } - - if (!include_file) - continue; - - ret = add_file(dirfd, fd, ftsent->fts_path, - type, modifiers, statp, - list, list_file, algo, ima_algo, tlv, - gen_list_path != NULL, - include_lsm_label, root_cred, - set_ima_xattr, set_evm_xattr, alt_root, - cur->attrs[ATTR_CAPS], - cur->attrs[ATTR_DIGEST]); - if (!ret) - unlink = false; - else if (ret < 0 && ret != -EEXIST && - ret != -ENOENT && ret != -ENODATA) - goto out_fts_close; - - break; - default: - break; - } - } - - fts_close(fts); - fts = NULL; - } - - ret = compact_list_flush_all(fd, &list_head); - if (ret < 0) { - pr_err("Cannot write digest list to %s\n", filename); - goto out_fts_close; - } - - if (!unlink && !gen_list_path) - ret = add_path_struct(filename, NULL, head_out); + struct path_struct *cur, *cur_i, *cur_e; + FTS *fts = NULL; + FTSENT *ftsent; + char *paths[2] = { "/", NULL }; + struct list_struct *list = NULL, *list_file = NULL; + char filename[NAME_MAX + 1]; + char path[PATH_MAX]; + char *digest_lists_dir = NULL, *path_list = NULL, *gen_list_path = NULL; + char *data_ptr, *line_ptr, *real_path; + void *data; + loff_t size; + time_t t = time(NULL); + bool unlink = true; + struct tm tm; + struct stat st, *statp; + LIST_HEAD(list_head); + char *attrs[ATTR__LAST]; + struct passwd *pwd; + struct group *grp; + enum hash_algo list_algo; + int include_ima_digests = 0, only_executables = 0, root_cred = 0; + int include_path = 0, include_file = 0, set_ima_xattr = 0; + int path_list_ext = 0, set_evm_xattr = 0, alt_root_len; + int fts_flags = (FTS_PHYSICAL | FTS_COMFOLLOW | FTS_NOCHDIR | FTS_XDEV); + int ret, i, digest_lists_dirfd, fd, prefix_len, include_lsm_label = 0; + + if (pos == -1) + pos = 0; + + list_for_each_entry(cur, head_in, list) { + if (cur->path[1] != ':') { + pr_err("Options must be in the format :\n"); + return -EINVAL; + } + + if (cur->path[0] == 'i') + include_ima_digests = 1; + if (cur->path[0] == 'D') + digest_lists_dir = &cur->path[2]; + if (cur->path[0] == 'L') + path_list = &cur->path[2]; + if (cur->path[0] == 'M') + path_list_ext = 1; + if (cur->path[0] == 'G') + gen_list_path = &cur->path[2]; + if (cur->path[0] == 'l') { + if (!strcmp(&cur->path[2], "policy")) + include_lsm_label = 2; + else + include_lsm_label = 1; + } + if (cur->path[0] == 'e') + only_executables = 1; + if (cur->path[0] == 'r') + root_cred = 1; + if (cur->path[0] == 'F') + include_path = 1; + if (cur->path[0] == 'x') { + if (!strcmp(&cur->path[2], "evm")) + set_evm_xattr = 1; + else + set_ima_xattr = 1; + } + } + + if (!digest_lists_dir) { + pr_err("Digest lists directory not specified\n"); + return -EINVAL; + } + + if (path_list) { + ret = read_file_from_path(-1, path_list, &data, &size); + if (ret < 0) + return ret; + + data_ptr = (char *)data; + + while ((line_ptr = strsep(&data_ptr, "\n"))) { + if (!strlen(line_ptr)) + continue; + + if (path_list_ext) { + parse_file_attrs(line_ptr, attrs); + line_ptr = attrs[ATTR_PATH]; + } + + if (!line_ptr || stat(line_ptr, &st) == -1 || + !S_ISREG(st.st_mode)) + continue; + + snprintf(path, sizeof(path), "I:%s", line_ptr); + ret = add_path_struct(path, attrs, head_in); + if (ret < 0) + return ret; + } + } + + digest_lists_dirfd = open(digest_lists_dir, O_RDONLY | O_DIRECTORY); + if (digest_lists_dirfd < 0) { + pr_err("Unable to open %s, ret: %d\n", digest_lists_dir, + digest_lists_dirfd); + return digest_lists_dirfd; + } + + if (type == COMPACT_METADATA && include_lsm_label) { + ret = selinux_init_setup(); + if (ret) + goto out; + } + + for (i = 0; i < COMPACT__LAST; i++) { + ret = process_lists(digest_lists_dirfd, -1, 0, 0, &list_head, i, + (type == COMPACT_METADATA) ? + PARSER_OP_ADD_META_DIGEST_TO_HTABLE : + PARSER_OP_ADD_DIGEST_TO_HTABLE, + digest_lists_dir, filename); + if (ret < 0) + goto out_selinux; + } + + compact_list_flush_all(-1, &list_head); + + if (!gen_list_path) { + tm = *localtime(&t); + + prefix_len = gen_filename_prefix(filename, sizeof(filename), + pos, tlv ? FORMAT_TLV : FORMAT, type); + snprintf(filename + prefix_len, sizeof(filename) - prefix_len, + "%04d%02d%02d_%02d%02d%02d", tm.tm_year + 1900, + tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, + tm.tm_sec); + + fd = openat(dirfd, filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); + } else { + fd = openat(-1, gen_list_path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + } + + if (fd < 0) { + pr_err("Cannot open %s\n", filename); + ret = -EACCES; + goto out_selinux; + } + + list = compact_list_init(&list_head, type, modifiers, algo, tlv); + if (!list) + goto out_close; + + if (type == COMPACT_METADATA && include_ima_digests) { + list_file = compact_list_init(&list_head, COMPACT_FILE, + modifiers, algo, tlv); + if (!list_file) + goto out_close; + } + + list_for_each_entry(cur, head_in, list) { + if (cur->path[0] != 'I') + continue; + + if (path_list_ext) { + pwd = NULL; + grp = NULL; + list_algo = algo; + + if (cur->attrs[ATTR_MODE]) + st.st_mode = strtol(cur->attrs[ATTR_MODE], + NULL, 10); + st.st_uid = 0; + if (cur->attrs[ATTR_UNAME]) + pwd = getpwnam(cur->attrs[ATTR_UNAME]); + if (pwd) + st.st_uid = pwd->pw_uid; + st.st_gid = 0; + if (cur->attrs[ATTR_GNAME]) + grp = getgrnam(cur->attrs[ATTR_GNAME]); + if (grp) + st.st_gid = grp->gr_gid; + if (cur->attrs[ATTR_DIGESTALGO]) + list_algo = strtol(cur->attrs[ATTR_DIGESTALGO], + NULL, 10); + if (cur->attrs[ATTR_DIGESTALGOPGP]) { + list_algo = pgp_algo_mapping[strtol( + cur->attrs[ATTR_DIGESTALGOPGP], + NULL, 10)]; + } + if (list_algo != algo) + continue; + } + + paths[0] = &cur->path[2]; + + fts = fts_open(paths, fts_flags, NULL); + if (!fts) + goto out_close; + + while ((ftsent = fts_read(fts)) != NULL) { + switch (ftsent->fts_info) { + case FTS_F: + real_path = ftsent->fts_path; + alt_root_len = alt_root ? strlen(alt_root) : 0; + + if (alt_root && + alt_root_len < strlen(real_path)) + real_path += alt_root_len; + + include_file = 0; + statp = ftsent->fts_statp; + if (path_list_ext) { + st.st_size = statp->st_size; + statp = &st; + } + + if (include_path && only_executables) { + list_for_each_entry(cur_i, head_in, + list) { + if (cur_i->path[0] != 'F') + continue; + + if (!strncmp(real_path, + &cur_i->path[2], + strlen(&cur_i->path[2]))) { + include_file = 1; + break; + } + } + } else { + if (!only_executables) + include_file = 1; + } + + if (only_executables && + (statp->st_mode & S_IXUGO)) + include_file = 1; + + if (!include_file) + continue; + + include_file = 1; + + list_for_each_entry(cur_e, head_in, list) { + if (cur_e->path[0] == 'E' && + !strncmp(&cur_e->path[2], + real_path, + strlen(&cur_e->path[2]))) { + include_file = 0; + break; + } + } + + if (!include_file) + continue; + + ret = add_file(dirfd, fd, ftsent->fts_path, + type, modifiers, statp, + list, list_file, algo, ima_algo, tlv, + gen_list_path != NULL, + include_lsm_label, root_cred, + set_ima_xattr, set_evm_xattr, alt_root, + cur->attrs[ATTR_CAPS], + cur->attrs[ATTR_DIGEST]); + if (!ret) + unlink = false; + else if (ret < 0 && ret != -EEXIST && + ret != -ENOENT && ret != -ENODATA) + goto out_fts_close; + + break; + default: + break; + } + } + + fts_close(fts); + fts = NULL; + } + + ret = compact_list_flush_all(fd, &list_head); + if (ret < 0) { + pr_err("Cannot write digest list to %s\n", filename); + goto out_fts_close; + } + + if (!unlink && !gen_list_path) + ret = add_path_struct(filename, NULL, head_out); out_fts_close: - if (fts) - fts_close(fts); + if (fts) + fts_close(fts); out_close: - close(fd); + close(fd); - if (ret < 0 || unlink) - unlinkat(dirfd, filename, 0); + if (ret < 0 || unlink) + unlinkat(dirfd, filename, 0); out_selinux: - if (type == COMPACT_METADATA && include_lsm_label) - selinux_end_setup(); + if (type == COMPACT_METADATA && include_lsm_label) + selinux_end_setup(); out: - close(digest_lists_dirfd); - return ret; + close(digest_lists_dirfd); + return ret; } diff --git a/include/Makefile.am b/include/Makefile.am index c9e7de9..f8f2fbe 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,13 +1,13 @@ digest_lists_includedir=$(includedir)/digestlist digest_lists_include_HEADERS = kernel_lib.h \ - list.h \ - lib.h \ - compact_list.h \ - crypto.h \ - xattr.h \ - evm.h \ - selinux.h \ - cap.h \ - ima_list.h \ - parser_lib.h \ - pgp.h + list.h \ + lib.h \ + compact_list.h \ + crypto.h \ + xattr.h \ + evm.h \ + selinux.h \ + cap.h \ + ima_list.h \ + parser_lib.h \ + pgp.h diff --git a/include/compact_list.h b/include/compact_list.h index 11c0145..2ed2f4c 100644 --- a/include/compact_list.h +++ b/include/compact_list.h @@ -21,56 +21,56 @@ #define IMA_KEY_PATH "/etc/keys/x509_ima.der" enum parser_ops { PARSER_OP_ADD_DIGEST, PARSER_OP_ADD_DIGEST_TO_HTABLE, - PARSER_OP_ADD_META_DIGEST, - PARSER_OP_ADD_META_DIGEST_TO_HTABLE, - PARSER_OP_ADD_IMA_XATTR, PARSER_OP_REMOVE_IMA_XATTR, - PARSER_OP_ADD_EVM_XATTR, PARSER_OP_REMOVE_EVM_XATTR, - PARSER_OP_REMOVE_INFOFLOW_XATTR, PARSER_OP_VERIFY, - PARSER_OP_DUMP, PARSER_OP_GEN_IMA_LIST, PARSER_OP_CHECK_META, - PARSER_OP_REPAIR_META, PARSER_OP_REPAIR_META_DIGEST_LISTS, - PARSER_OP__LAST }; + PARSER_OP_ADD_META_DIGEST, + PARSER_OP_ADD_META_DIGEST_TO_HTABLE, + PARSER_OP_ADD_IMA_XATTR, PARSER_OP_REMOVE_IMA_XATTR, + PARSER_OP_ADD_EVM_XATTR, PARSER_OP_REMOVE_EVM_XATTR, + PARSER_OP_REMOVE_INFOFLOW_XATTR, PARSER_OP_VERIFY, + PARSER_OP_DUMP, PARSER_OP_GEN_IMA_LIST, PARSER_OP_CHECK_META, + PARSER_OP_REPAIR_META, PARSER_OP_REPAIR_META_DIGEST_LISTS, + PARSER_OP__LAST }; enum tlv_ids { ID_DIGEST, ID_EVM_DIGEST, ID_PATH, ID_INODE_UID, ID_INODE_GID, - ID_INODE_MODE, ID_INODE_SIZE, ID_FSMAGIC, ID_OBJ_LABEL, ID_CAPS, - ID__LAST }; + ID_INODE_MODE, ID_INODE_SIZE, ID_FSMAGIC, ID_OBJ_LABEL, ID_CAPS, + ID__LAST }; struct _tlv_item { - u8 id; - u32 len; - u8 data[]; + u8 id; + u32 len; + u8 data[]; } __attribute__((packed)); struct tlv_item { - struct list_head list; - struct _tlv_item *item; + struct list_head list; + struct _tlv_item *item; }; extern char *compact_types_str[COMPACT__LAST]; extern char *compact_modifiers_str[COMPACT_MOD__LAST]; struct list_struct { - struct list_head list; - struct compact_list_hdr *hdr; + struct list_head list; + struct compact_list_hdr *hdr; }; struct list_struct *compact_list_init(struct list_head *head, - enum compact_types type, u16 modifiers, - enum hash_algo algo, bool tlv); + enum compact_types type, u16 modifiers, + enum hash_algo algo, bool tlv); int compact_list_add_digest(int fd, struct list_struct *list, u8 *digest); int compact_list_tlv_add_digest(int fd, struct list_struct *list, - struct list_head *head, u8 *digest, - enum tlv_ids id); + struct list_head *head, u8 *digest, + enum tlv_ids id); int compact_list_tlv_add_metadata(int fd, struct list_struct *list, - struct list_head *head, char *path, - char *alt_root, struct stat *stat, - char *obj_label, int obj_label_len, - u8 *caps_bin, int caps_bin_len); + struct list_head *head, char *path, + char *alt_root, struct stat *stat, + char *obj_label, int obj_label_len, + u8 *caps_bin, int caps_bin_len); int compact_list_tlv_add_item(int fd, struct list_struct *list, - struct list_head *head, enum tlv_ids id, - size_t len, u8 *data); + struct list_head *head, enum tlv_ids id, + size_t len, u8 *data); int compact_list_tlv_add_items(int fd, struct list_struct *list, - struct list_head *head); + struct list_head *head); void compact_list_tlv_dump_items(struct _tlv_item **items); void compact_list_tlv_free_items(struct list_head *head); @@ -78,34 +78,34 @@ int compact_list_upload(int fd, struct list_struct *list); int compact_list_flush_all(int fd, struct list_head *list_head); typedef int (*generator_func)(int dirfd, int pos, struct list_head *head_in, - struct list_head *head_out, - enum compact_types type, u16 modifiers, - enum hash_algo algo, enum hash_algo ima_algo, - bool tlv, char *alt_root); + struct list_head *head_out, + enum compact_types type, u16 modifiers, + enum hash_algo algo, enum hash_algo ima_algo, + bool tlv, char *alt_root); typedef int (*parser_func)(int imafd, struct list_head *head, - loff_t size, void *buf, enum parser_ops op); + loff_t size, void *buf, enum parser_ops op); int gen_filename_prefix(char *filename, int filename_len, int pos, - const char *format, enum compact_types type); + const char *format, enum compact_types type); typedef int (*filter_lists)(const struct dirent *file); int filter_parser_list_symlink(const struct dirent *file); extern filter_lists filter[COMPACT__LAST]; int get_digest_lists(int dirfd, enum compact_types type, - struct list_head *head); + struct list_head *head); int compare_lists(const struct dirent **e1, const struct dirent **e2); int digest_list_add_metadata(int dirfd, int fd, char *digest_list_filename, - char *digest_list_dir, struct list_head *head, - u8 *digest_list_buf, size_t digest_list_buf_len); + char *digest_list_dir, struct list_head *head, + u8 *digest_list_buf, size_t digest_list_buf_len); int digest_list_upload(int dirfd, int fd, struct list_head *head, - struct list_head *parser_lib_head, - char *digest_list_filename, enum parser_ops op, - char *digest_lists_dir); + struct list_head *parser_lib_head, + char *digest_list_filename, enum parser_ops op, + char *digest_lists_dir); int process_lists(int dirfd, int fd, int save, int verbose, - struct list_head *head, enum compact_types type, - enum parser_ops op, char *digest_lists_dir, - char *filename); + struct list_head *head, enum compact_types type, + enum parser_ops op, char *digest_lists_dir, + char *filename); #endif /*_COMPACT_LIST_H*/ diff --git a/include/crypto.h b/include/crypto.h index 615f11e..e84b665 100644 --- a/include/crypto.h +++ b/include/crypto.h @@ -35,19 +35,19 @@ int calc_digest(u8 *digest, void *data, u64 len, enum hash_algo algo); int calc_file_digest(u8 *digest, int dirfd, char *path, enum hash_algo algo); int sign_files(int dirfd, struct list_head *head, char *key_path, - char *keypass, enum hash_algo algo); + char *keypass, enum hash_algo algo); struct key_struct { - struct list_head list; - RSA *key; - u8 keyid[4]; + struct list_head list; + RSA *key; + u8 keyid[4]; }; void free_keys(struct list_head *head); struct key_struct *new_key(struct list_head *head, int dirfd, char *key_path, - char *keypass, bool private); + char *keypass, bool private); struct key_struct *lookup_key(struct list_head *head, int dirfd, char *key_path, - u8 *keyid); + u8 *keyid); int verify_file(struct list_head *head, int dirfd, char *filename); int verify_sig(struct list_head *head, int dirfd, u8 *sig, int sig_len, u8 *digest, enum hash_algo algo); diff --git a/include/evm.h b/include/evm.h index 5335507..198e402 100644 --- a/include/evm.h +++ b/include/evm.h @@ -19,9 +19,9 @@ #include "compact_list.h" int evm_calc_hmac_or_hash(enum hash_algo algo, u8 *digest, - int lsm_label_len, char *lsm_label, - int ima_digest_len, u8 *ima_digest, - int caps_bin_len, u8 *caps_bin, - uid_t uid, gid_t gid, mode_t mode); + int lsm_label_len, char *lsm_label, + int ima_digest_len, u8 *ima_digest, + int caps_bin_len, u8 *caps_bin, + uid_t uid, gid_t gid, mode_t mode); #endif /*_EVM_H*/ diff --git a/include/ima_list.h b/include/ima_list.h index 2db68c9..5dbc515 100644 --- a/include/ima_list.h +++ b/include/ima_list.h @@ -17,6 +17,6 @@ int ima_copy_boot_aggregate(int fd); int ima_generate_entry(int dirfd, int fd, char *digest_list_dir, - char *digest_list_filename); + char *digest_list_filename); #endif /*_IMA_LIST_H*/ diff --git a/include/kernel_lib.h b/include/kernel_lib.h index 1ee2814..4cc9e94 100644 --- a/include/kernel_lib.h +++ b/include/kernel_lib.h @@ -48,7 +48,7 @@ typedef unsigned long atomic_long_t; static inline void atomic_long_inc(atomic_long_t *x) { - (*x)++; + (*x)++; } #define true 1 @@ -114,25 +114,25 @@ static inline void pr_debug(const char *__restrict __format, ...) #define SM3256_DIGEST_SIZE 32 enum hash_algo { - HASH_ALGO_MD4, - HASH_ALGO_MD5, - HASH_ALGO_SHA1, - HASH_ALGO_RIPE_MD_160, - HASH_ALGO_SHA256, - HASH_ALGO_SHA384, - HASH_ALGO_SHA512, - HASH_ALGO_SHA224, - HASH_ALGO_RIPE_MD_128, - HASH_ALGO_RIPE_MD_256, - HASH_ALGO_RIPE_MD_320, - HASH_ALGO_WP_256, - HASH_ALGO_WP_384, - HASH_ALGO_WP_512, - HASH_ALGO_TGR_128, - HASH_ALGO_TGR_160, - HASH_ALGO_TGR_192, - HASH_ALGO_SM3_256, - HASH_ALGO__LAST + HASH_ALGO_MD4, + HASH_ALGO_MD5, + HASH_ALGO_SHA1, + HASH_ALGO_RIPE_MD_160, + HASH_ALGO_SHA256, + HASH_ALGO_SHA384, + HASH_ALGO_SHA512, + HASH_ALGO_SHA224, + HASH_ALGO_RIPE_MD_128, + HASH_ALGO_RIPE_MD_256, + HASH_ALGO_RIPE_MD_320, + HASH_ALGO_WP_256, + HASH_ALGO_WP_384, + HASH_ALGO_WP_512, + HASH_ALGO_TGR_128, + HASH_ALGO_TGR_160, + HASH_ALGO_TGR_192, + HASH_ALGO_SM3_256, + HASH_ALGO__LAST }; /* from crypto/hash_info.c */ @@ -158,7 +158,7 @@ extern const int hash_digest_size[HASH_ALGO__LAST]; #endif static inline u32 __hash_32_generic(u32 val) { - return val * GOLDEN_RATIO_32; + return val * GOLDEN_RATIO_32; } #ifndef HAVE_ARCH_HASH_32 @@ -166,8 +166,8 @@ static inline u32 __hash_32_generic(u32 val) #endif static inline u32 hash_32_generic(u32 val, unsigned int bits) { - /* High bits are more random, so use them. */ - return __hash_32(val) >> (32 - bits); + /* High bits are more random, so use them. */ + return __hash_32(val) >> (32 - bits); } #ifndef HAVE_ARCH_HASH_64 @@ -176,28 +176,28 @@ static inline u32 hash_32_generic(u32 val, unsigned int bits) static __always_inline u32 hash_64_generic(u64 val, unsigned int bits) { #if BITS_PER_LONG == 64 - /* 64x64-bit multiply is efficient on all 64-bit processors */ - return val * GOLDEN_RATIO_64 >> (64 - bits); + /* 64x64-bit multiply is efficient on all 64-bit processors */ + return val * GOLDEN_RATIO_64 >> (64 - bits); #else - /* Hash 64 bits using only 32x32-bit multiply. */ - return hash_32((u32)val ^ __hash_32(val >> 32), bits); + /* Hash 64 bits using only 32x32-bit multiply. */ + return hash_32((u32)val ^ __hash_32(val >> 32), bits); #endif } static inline u32 hash_ptr(const void *ptr, unsigned int bits) { - return hash_long((unsigned long)ptr, bits); + return hash_long((unsigned long)ptr, bits); } /* This really should be called fold32_ptr; it does no hashing to speak of. */ static inline u32 hash32_ptr(const void *ptr) { - unsigned long val = (unsigned long)ptr; + unsigned long val = (unsigned long)ptr; #if __BITS_PER_LONG == 64 - val ^= (val >> 32); + val ^= (val >> 32); #endif - return (u32)val; + return (u32)val; } /* from kernel.h */ @@ -215,83 +215,83 @@ extern bool ima_canonical_fmt; static inline unsigned long ima_hash_key(u8 *digest) { - return hash_long(*digest, IMA_HASH_BITS); + return hash_long(*digest, IMA_HASH_BITS); } struct ima_h_table { - atomic_long_t len; /* number of stored measurements in the list */ - atomic_long_t violations; - struct hlist_head queue[IMA_MEASURE_HTABLE_SIZE]; + atomic_long_t len; /* number of stored measurements in the list */ + atomic_long_t violations; + struct hlist_head queue[IMA_MEASURE_HTABLE_SIZE]; }; /* from integrity.h */ enum evm_ima_xattr_type { - IMA_XATTR_DIGEST = 0x01, - EVM_XATTR_HMAC, - EVM_IMA_XATTR_DIGSIG, - IMA_XATTR_DIGEST_NG, - EVM_XATTR_PORTABLE_DIGSIG, - EVM_IMA_XATTR_DIGEST_LIST, - IMA_XATTR_LAST + IMA_XATTR_DIGEST = 0x01, + EVM_XATTR_HMAC, + EVM_IMA_XATTR_DIGSIG, + IMA_XATTR_DIGEST_NG, + EVM_XATTR_PORTABLE_DIGSIG, + EVM_IMA_XATTR_DIGEST_LIST, + IMA_XATTR_LAST }; enum evm_ima_sig_fmt { - SIG_FMT_IMA, - SIG_FMT_PGP, - SIG_FMT__LAST, + SIG_FMT_IMA, + SIG_FMT_PGP, + SIG_FMT__LAST, }; struct signature_v2_hdr { - uint8_t type; /* xattr type */ - uint8_t version; /* signature format version */ - uint8_t hash_algo; /* Digest algorithm [enum hash_algo] */ - __be32 keyid; /* IMA key identifier - not X509/PGP specific */ - __be16 sig_size; /* signature size */ - uint8_t sig[0]; /* signature payload */ + uint8_t type; /* xattr type */ + uint8_t version; /* signature format version */ + uint8_t hash_algo; /* Digest algorithm [enum hash_algo] */ + __be32 keyid; /* IMA key identifier - not X509/PGP specific */ + __be16 sig_size; /* signature size */ + uint8_t sig[0]; /* signature payload */ } __attribute__((packed)); struct evm_ima_xattr_data { - uint8_t type; - uint8_t digest[SHA512_DIGEST_SIZE + 1]; + uint8_t type; + uint8_t digest[SHA512_DIGEST_SIZE + 1]; } __attribute__((packed)); /* from integrity.h */ enum compact_types { COMPACT_KEY, COMPACT_PARSER, COMPACT_FILE, - COMPACT_METADATA, COMPACT__LAST }; + COMPACT_METADATA, COMPACT__LAST }; enum compact_modifiers { COMPACT_MOD_IMMUTABLE, COMPACT_MOD__LAST }; struct ima_digest { - struct hlist_node hnext; - struct list_head list; - enum hash_algo algo; - enum compact_types type; - u16 modifiers; - u8 digest[0]; + struct hlist_node hnext; + struct list_head list; + enum hash_algo algo; + enum compact_types type; + u16 modifiers; + u8 digest[0]; }; /* from ima_digest_list.c */ struct compact_list_hdr { - u8 version; - u8 _reserved; - u16 type; - u16 modifiers; - u16 algo; - u32 count; - u32 datalen; + u8 version; + u8 _reserved; + u16 type; + u16 modifiers; + u16 algo; + u32 count; + u32 datalen; } __attribute__((packed)); typedef int (*add_digest_func)(u8 *digest, enum hash_algo algo, - enum compact_types type, u16 modifiers); + enum compact_types type, u16 modifiers); int default_func(u8 *digest, enum hash_algo algo, enum compact_types type, u16 modifiers); int ima_parse_compact_list(loff_t size, void *buf, - add_digest_func ima_add_digest_data_entry, - enum hash_algo *algo); + add_digest_func ima_add_digest_data_entry, + enum hash_algo *algo); struct ima_digest *ima_lookup_digest(u8 *digest, enum hash_algo algo); int ima_add_digest_data_entry_kernel(u8 *digest, enum hash_algo algo, - enum compact_types type, u16 modifiers); + enum compact_types type, u16 modifiers); #endif /* _KERNEL_LIB_H */ diff --git a/include/lib.h b/include/lib.h index ef3ada3..52e453e 100644 --- a/include/lib.h +++ b/include/lib.h @@ -34,42 +34,42 @@ #define IMA_SECURITYFS_PATH SECURITYFS_PATH "/ima" enum pgp_hash_algo { - PGP_HASH_MD5 = 1, - PGP_HASH_SHA1 = 2, - PGP_HASH_RIPE_MD_160 = 3, - PGP_HASH_SHA256 = 8, - PGP_HASH_SHA384 = 9, - PGP_HASH_SHA512 = 10, - PGP_HASH_SHA224 = 11, - PGP_HASH__LAST + PGP_HASH_MD5 = 1, + PGP_HASH_SHA1 = 2, + PGP_HASH_RIPE_MD_160 = 3, + PGP_HASH_SHA256 = 8, + PGP_HASH_SHA384 = 9, + PGP_HASH_SHA512 = 10, + PGP_HASH_SHA224 = 11, + PGP_HASH__LAST }; enum hash_algo pgp_algo_mapping[PGP_HASH__LAST]; int read_file_from_path(int dirfd, const char *path, void **buf, loff_t *size); int read_write_file_from_path(int dirfd, const char *path, void **buf, - loff_t *size); + loff_t *size); ssize_t write_check(int fd, const void *buf, size_t count); int copy_file(char *src, char *dest); struct lib { - struct list_head list; - char *format; - void *handle; - void *func; + struct list_head list; + char *format; + void *handle; + void *func; }; struct lib *lookup_lib(struct list_head *head, const char *lib_type, - const char *format, int format_len); + const char *format, int format_len); void free_libs(struct list_head *head); enum file_attrs { ATTR_PATH, ATTR_DIGESTALGO, ATTR_DIGESTALGOPGP, ATTR_DIGEST, - ATTR_MODE, ATTR_UNAME, ATTR_GNAME, ATTR_CAPS, ATTR__LAST }; + ATTR_MODE, ATTR_UNAME, ATTR_GNAME, ATTR_CAPS, ATTR__LAST }; struct path_struct { - struct list_head list; - char *attrs[ATTR__LAST]; - char *path; + struct list_head list; + char *attrs[ATTR__LAST]; + char *path; }; int add_path_struct(char *path, char **attrs, struct list_head *head); diff --git a/include/list.h b/include/list.h index 381505a..7b725dc 100644 --- a/include/list.h +++ b/include/list.h @@ -27,34 +27,34 @@ * */ #define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ - struct list_head name = LIST_HEAD_INIT(name) + struct list_head name = LIST_HEAD_INIT(name) #define HLIST_HEAD_INIT { .first = NULL } #define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } #define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) struct list_head { - struct list_head *next, *prev; + struct list_head *next, *prev; }; struct hlist_head { - struct hlist_node *first; + struct hlist_node *first; }; struct hlist_node { - struct hlist_node *next, **pprev; + struct hlist_node *next, **pprev; }; static inline void INIT_LIST_HEAD(struct list_head *list) { - list->next = list; - list->prev = list; + list->next = list; + list->prev = list; } /* @@ -64,13 +64,13 @@ static inline void INIT_LIST_HEAD(struct list_head *list) * the prev/next entries already! */ static inline void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next) + struct list_head *prev, + struct list_head *next) { - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; } /** @@ -83,7 +83,7 @@ static inline void __list_add(struct list_head *new, */ static inline void list_add(struct list_head *new, struct list_head *head) { - __list_add(new, head, head->next); + __list_add(new, head, head->next); } /** @@ -96,7 +96,7 @@ static inline void list_add(struct list_head *new, struct list_head *head) */ static inline void list_add_tail(struct list_head *new, struct list_head *head) { - __list_add(new, head->prev, head); + __list_add(new, head->prev, head); } /* @@ -108,8 +108,8 @@ static inline void list_add_tail(struct list_head *new, struct list_head *head) */ static inline void __list_del(struct list_head * prev, struct list_head * next) { - next->prev = prev; - prev->next = next; + next->prev = prev; + prev->next = next; } /** @@ -120,14 +120,14 @@ static inline void __list_del(struct list_head * prev, struct list_head * next) */ static inline void __list_del_entry(struct list_head *entry) { - __list_del(entry->prev, entry->next); + __list_del(entry->prev, entry->next); } static inline void list_del(struct list_head *entry) { - __list_del_entry(entry); - entry->next = LIST_POISON1; - entry->prev = LIST_POISON2; + __list_del_entry(entry); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; } /** @@ -136,7 +136,7 @@ static inline void list_del(struct list_head *entry) */ static inline int list_empty(const struct list_head *head) { - return head->next == head; + return head->next == head; } /** @@ -146,7 +146,7 @@ static inline int list_empty(const struct list_head *head) * @member: the name of the list_head within the struct. */ #define list_entry(ptr, type, member) \ - container_of(ptr, type, member) + container_of(ptr, type, member) /** * list_first_entry - get the first element from a list @@ -157,7 +157,7 @@ static inline int list_empty(const struct list_head *head) * Note, that list is expected to be not empty. */ #define list_first_entry(ptr, type, member) \ - list_entry((ptr)->next, type, member) + list_entry((ptr)->next, type, member) /** * list_last_entry - get the last element from a list @@ -168,7 +168,7 @@ static inline int list_empty(const struct list_head *head) * Note, that list is expected to be not empty. */ #define list_last_entry(ptr, type, member) \ - list_entry((ptr)->prev, type, member) + list_entry((ptr)->prev, type, member) /** * list_first_entry_or_null - get the first element from a list @@ -179,9 +179,9 @@ static inline int list_empty(const struct list_head *head) * Note that if the list is empty, it returns NULL. */ #define list_first_entry_or_null(ptr, type, member) ({ \ - struct list_head *head__ = (ptr); \ - struct list_head *pos__ = READ_ONCE(head__->next); \ - pos__ != head__ ? list_entry(pos__, type, member) : NULL; \ + struct list_head *head__ = (ptr); \ + struct list_head *pos__ = READ_ONCE(head__->next); \ + pos__ != head__ ? list_entry(pos__, type, member) : NULL; \ }) /** @@ -190,7 +190,7 @@ static inline int list_empty(const struct list_head *head) * @member: the name of the list_head within the struct. */ #define list_next_entry(pos, member) \ - list_entry((pos)->member.next, typeof(*(pos)), member) + list_entry((pos)->member.next, typeof(*(pos)), member) /** * list_prev_entry - get the prev element in list @@ -198,7 +198,7 @@ static inline int list_empty(const struct list_head *head) * @member: the name of the list_head within the struct. */ #define list_prev_entry(pos, member) \ - list_entry((pos)->member.prev, typeof(*(pos)), member) + list_entry((pos)->member.prev, typeof(*(pos)), member) /** * list_for_each_entry - iterate over list of given type @@ -207,9 +207,9 @@ static inline int list_empty(const struct list_head *head) * @member: the name of the list_head within the struct. */ #define list_for_each_entry(pos, head, member) \ - for (pos = list_first_entry(head, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_next_entry(pos, member)) + for (pos = list_first_entry(head, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_next_entry(pos, member)) /** * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry @@ -219,34 +219,34 @@ static inline int list_empty(const struct list_head *head) * @member: the name of the list_head within the struct. */ #define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_first_entry(head, typeof(*pos), member), \ - n = list_next_entry(pos, member); \ - &pos->member != (head); \ - pos = n, n = list_next_entry(n, member)) + for (pos = list_first_entry(head, typeof(*pos), member), \ + n = list_next_entry(pos, member); \ + &pos->member != (head); \ + pos = n, n = list_next_entry(n, member)) static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) { - struct hlist_node *first = h->first; - n->next = first; - if (first) - first->pprev = &n->next; - h->first = n; - n->pprev = &h->first; + struct hlist_node *first = h->first; + n->next = first; + if (first) + first->pprev = &n->next; + h->first = n; + n->pprev = &h->first; } #define hlist_entry(ptr, type, member) container_of(ptr,type,member) #define hlist_for_each(pos, head) \ - for (pos = (head)->first; pos ; pos = pos->next) + for (pos = (head)->first; pos ; pos = pos->next) #define hlist_for_each_safe(pos, n, head) \ - for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ - pos = n) + for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ + pos = n) #define hlist_entry_safe(ptr, type, member) \ - ({ typeof(ptr) ____ptr = (ptr); \ - ____ptr ? hlist_entry(____ptr, type, member) : NULL; \ - }) + ({ typeof(ptr) ____ptr = (ptr); \ + ____ptr ? hlist_entry(____ptr, type, member) : NULL; \ + }) /** * hlist_for_each_entry - iterate over list of given type @@ -255,9 +255,9 @@ static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) * @member: the name of the hlist_node within the struct. */ #define hlist_for_each_entry(pos, head, member) \ - for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\ - pos; \ - pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) + for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\ + pos; \ + pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) #define hlist_for_each_entry_rcu hlist_for_each_entry #define hlist_add_head_rcu hlist_add_head diff --git a/include/parser_lib.h b/include/parser_lib.h index 42b125f..02e6e8c 100644 --- a/include/parser_lib.h +++ b/include/parser_lib.h @@ -18,19 +18,19 @@ #include "compact_list.h" int add_digest(int fd, struct list_head *head, u16 type, u16 modifiers, - u16 algo, u8 *digest); + u16 algo, u8 *digest); int calc_metadata_digest(int fd, struct list_head *head, u16 type, - u16 modifiers, u16 algo, u8 *digest, u8 *evm_digest, - char *path, uid_t uid, gid_t gid, mode_t mode, - char *obj_label, char *caps); + u16 modifiers, u16 algo, u8 *digest, u8 *evm_digest, + char *path, uid_t uid, gid_t gid, mode_t mode, + char *obj_label, char *caps); int add_metadata_digest(int fd, struct list_head *head, u16 modifiers, - u8 *evm_digest); + u8 *evm_digest); int add_ima_xattr(int fd, struct list_head *head, u16 type, u16 modifiers, - u16 algo, u8 *digest, char *path); + u16 algo, u8 *digest, char *path); int check_repair_xattr(char *path, char *xattr_name, void *xattr_value, - int xattr_value_len, int ima_algo, int modifiers, - int repair); + int xattr_value_len, int ima_algo, int modifiers, + int repair); int check_repair_attr(char *path, uid_t uid, gid_t gid, mode_t mode, - int repair); + int repair); #endif /*_PARSER_LIB_H*/ diff --git a/include/pgp.h b/include/pgp.h index 067ec37..4db569d 100644 --- a/include/pgp.h +++ b/include/pgp.h @@ -24,101 +24,101 @@ #include "lib.h" struct pgp_key_ID { - u8 id[8]; + u8 id[8]; } __attribute__((packed)); struct pgp_time { - u8 time[4]; + u8 time[4]; } __attribute__((packed)); /* * PGP public-key algorithm identifiers [RFC4880: 9.1] */ enum pgp_pubkey_algo { - PGP_PUBKEY_RSA_ENC_OR_SIG = 1, - PGP_PUBKEY_RSA_ENC_ONLY = 2, - PGP_PUBKEY_RSA_SIG_ONLY = 3, - PGP_PUBKEY_ELGAMAL = 16, - PGP_PUBKEY_DSA = 17, - PGP_PUBKEY__LAST + PGP_PUBKEY_RSA_ENC_OR_SIG = 1, + PGP_PUBKEY_RSA_ENC_ONLY = 2, + PGP_PUBKEY_RSA_SIG_ONLY = 3, + PGP_PUBKEY_ELGAMAL = 16, + PGP_PUBKEY_DSA = 17, + PGP_PUBKEY__LAST }; /* * PGP symmetric-key algorithm identifiers [RFC4880: 9.2] */ enum pgp_symkey_algo { - PGP_SYMKEY_PLAINTEXT = 0, - PGP_SYMKEY_IDEA = 1, - PGP_SYMKEY_3DES = 2, - PGP_SYMKEY_CAST5 = 3, - PGP_SYMKEY_BLOWFISH = 4, - PGP_SYMKEY_AES_128KEY = 7, - PGP_SYMKEY_AES_192KEY = 8, - PGP_SYMKEY_AES_256KEY = 9, - PGP_SYMKEY_TWOFISH_256KEY = 10, + PGP_SYMKEY_PLAINTEXT = 0, + PGP_SYMKEY_IDEA = 1, + PGP_SYMKEY_3DES = 2, + PGP_SYMKEY_CAST5 = 3, + PGP_SYMKEY_BLOWFISH = 4, + PGP_SYMKEY_AES_128KEY = 7, + PGP_SYMKEY_AES_192KEY = 8, + PGP_SYMKEY_AES_256KEY = 9, + PGP_SYMKEY_TWOFISH_256KEY = 10, }; /* * PGP compression algorithm identifiers [RFC4880: 9.3] */ enum pgp_compr_algo { - PGP_COMPR_UNCOMPRESSED = 0, - PGP_COMPR_ZIP = 1, - PGP_COMPR_ZLIB = 2, - PGP_COMPR_BZIP2 = 3, + PGP_COMPR_UNCOMPRESSED = 0, + PGP_COMPR_ZIP = 1, + PGP_COMPR_ZLIB = 2, + PGP_COMPR_BZIP2 = 3, }; /* * PGP packet type tags [RFC4880: 4.3]. */ enum pgp_packet_tag { - PGP_PKT_RESERVED = 0, - PGP_PKT_PUBKEY_ENC_SESSION_KEY = 1, - PGP_PKT_SIGNATURE = 2, - PGP_PKT_SYMKEY_ENC_SESSION_KEY = 3, - PGP_PKT_ONEPASS_SIGNATURE = 4, - PGP_PKT_SECRET_KEY = 5, - PGP_PKT_PUBLIC_KEY = 6, - PGP_PKT_SECRET_SUBKEY = 7, - PGP_PKT_COMPRESSED_DATA = 8, - PGP_PKT_SYM_ENC_DATA = 9, - PGP_PKT_MARKER = 10, - PGP_PKT_LITERAL_DATA = 11, - PGP_PKT_TRUST = 12, - PGP_PKT_USER_ID = 13, - PGP_PKT_PUBLIC_SUBKEY = 14, - PGP_PKT_USER_ATTRIBUTE = 17, - PGP_PKT_SYM_ENC_AND_INTEG_DATA = 18, - PGP_PKT_MODIFY_DETECT_CODE = 19, - PGP_PKT_PRIVATE_0 = 60, - PGP_PKT_PRIVATE_3 = 63, - PGP_PKT__HIGHEST = 63 + PGP_PKT_RESERVED = 0, + PGP_PKT_PUBKEY_ENC_SESSION_KEY = 1, + PGP_PKT_SIGNATURE = 2, + PGP_PKT_SYMKEY_ENC_SESSION_KEY = 3, + PGP_PKT_ONEPASS_SIGNATURE = 4, + PGP_PKT_SECRET_KEY = 5, + PGP_PKT_PUBLIC_KEY = 6, + PGP_PKT_SECRET_SUBKEY = 7, + PGP_PKT_COMPRESSED_DATA = 8, + PGP_PKT_SYM_ENC_DATA = 9, + PGP_PKT_MARKER = 10, + PGP_PKT_LITERAL_DATA = 11, + PGP_PKT_TRUST = 12, + PGP_PKT_USER_ID = 13, + PGP_PKT_PUBLIC_SUBKEY = 14, + PGP_PKT_USER_ATTRIBUTE = 17, + PGP_PKT_SYM_ENC_AND_INTEG_DATA = 18, + PGP_PKT_MODIFY_DETECT_CODE = 19, + PGP_PKT_PRIVATE_0 = 60, + PGP_PKT_PRIVATE_3 = 63, + PGP_PKT__HIGHEST = 63 }; /* * Signature (tag 2) packet [RFC4880: 5.2]. */ enum pgp_signature_version { - PGP_SIG_VERSION_3 = 3, - PGP_SIG_VERSION_4 = 4, + PGP_SIG_VERSION_3 = 3, + PGP_SIG_VERSION_4 = 4, }; enum pgp_signature_type { - PGP_SIG_BINARY_DOCUMENT_SIG = 0x00, - PGP_SIG_CANONICAL_TEXT_DOCUMENT_SIG = 0x01, - PGP_SIG_STANDALONE_SIG = 0x02, - PGP_SIG_GENERAL_CERT_OF_UID_PUBKEY = 0x10, - PGP_SIG_PERSONAL_CERT_OF_UID_PUBKEY = 0x11, - PGP_SIG_CASUAL_CERT_OF_UID_PUBKEY = 0x12, - PGP_SIG_POSTITIVE_CERT_OF_UID_PUBKEY = 0x13, - PGP_SIG_SUBKEY_BINDING_SIG = 0x18, - PGP_SIG_PRIMARY_KEY_BINDING_SIG = 0x19, - PGP_SIG_DIRECTLY_ON_KEY = 0x1F, - PGP_SIG_KEY_REVOCATION_SIG = 0x20, - PGP_SIG_SUBKEY_REVOCATION_SIG = 0x28, - PGP_SIG_CERT_REVOCATION_SIG = 0x30, - PGP_SIG_TIMESTAMP_SIG = 0x40, - PGP_SIG_THIRD_PARTY_CONFIRM_SIG = 0x50, + PGP_SIG_BINARY_DOCUMENT_SIG = 0x00, + PGP_SIG_CANONICAL_TEXT_DOCUMENT_SIG = 0x01, + PGP_SIG_STANDALONE_SIG = 0x02, + PGP_SIG_GENERAL_CERT_OF_UID_PUBKEY = 0x10, + PGP_SIG_PERSONAL_CERT_OF_UID_PUBKEY = 0x11, + PGP_SIG_CASUAL_CERT_OF_UID_PUBKEY = 0x12, + PGP_SIG_POSTITIVE_CERT_OF_UID_PUBKEY = 0x13, + PGP_SIG_SUBKEY_BINDING_SIG = 0x18, + PGP_SIG_PRIMARY_KEY_BINDING_SIG = 0x19, + PGP_SIG_DIRECTLY_ON_KEY = 0x1F, + PGP_SIG_KEY_REVOCATION_SIG = 0x20, + PGP_SIG_SUBKEY_REVOCATION_SIG = 0x28, + PGP_SIG_CERT_REVOCATION_SIG = 0x30, + PGP_SIG_TIMESTAMP_SIG = 0x40, + PGP_SIG_THIRD_PARTY_CONFIRM_SIG = 0x50, }; #define PGP_SIG_SUBPKT_TYPE_CRITICAL_MASK 0x80 @@ -127,72 +127,72 @@ enum pgp_signature_type { * V4 signature subpacket types [RFC4880: 5.2.3.1]. */ enum pgp_sig_subpkt_type { - PGP_SIG_CREATION_TIME = 2, - PGP_SIG_EXPIRATION_TIME = 3, - PGP_SIG_EXPORTABLE_CERT = 4, - PGP_SIG_TRUST_SIG = 5, - PGP_SIG_REGEXP = 6, - PGP_SIG_REVOCABLE = 7, - PGP_SIG_KEY_EXPIRATION_TIME = 9, - PGP_SIG_PREF_SYM_ALGO = 11, - PGP_SIG_REVOCATION_KEY = 12, - PGP_SIG_ISSUER = 16, - PGP_SIG_NOTATION_DATA = 20, - PGP_SIG_PREF_HASH_ALGO = 21, - PGP_SIG_PREF_COMPR_ALGO = 22, - PGP_SIG_KEY_SERVER_PREFS = 23, - PGP_SIG_PREF_KEY_SERVER = 24, - PGP_SIG_PRIMARY_USER_ID = 25, - PGP_SIG_POLICY_URI = 26, - PGP_SIG_KEY_FLAGS = 27, - PGP_SIG_SIGNERS_USER_ID = 28, - PGP_SIG_REASON_FOR_REVOCATION = 29, - PGP_SIG_FEATURES = 30, - PGP_SIG_TARGET = 31, - PGP_SIG_EMBEDDED_SIG = 32, - PGP_SIG__LAST + PGP_SIG_CREATION_TIME = 2, + PGP_SIG_EXPIRATION_TIME = 3, + PGP_SIG_EXPORTABLE_CERT = 4, + PGP_SIG_TRUST_SIG = 5, + PGP_SIG_REGEXP = 6, + PGP_SIG_REVOCABLE = 7, + PGP_SIG_KEY_EXPIRATION_TIME = 9, + PGP_SIG_PREF_SYM_ALGO = 11, + PGP_SIG_REVOCATION_KEY = 12, + PGP_SIG_ISSUER = 16, + PGP_SIG_NOTATION_DATA = 20, + PGP_SIG_PREF_HASH_ALGO = 21, + PGP_SIG_PREF_COMPR_ALGO = 22, + PGP_SIG_KEY_SERVER_PREFS = 23, + PGP_SIG_PREF_KEY_SERVER = 24, + PGP_SIG_PRIMARY_USER_ID = 25, + PGP_SIG_POLICY_URI = 26, + PGP_SIG_KEY_FLAGS = 27, + PGP_SIG_SIGNERS_USER_ID = 28, + PGP_SIG_REASON_FOR_REVOCATION = 29, + PGP_SIG_FEATURES = 30, + PGP_SIG_TARGET = 31, + PGP_SIG_EMBEDDED_SIG = 32, + PGP_SIG__LAST }; struct pgp_parse_sig_context { - unsigned long types_of_interest[128 / __BITS_PER_LONG]; - int (*process_packet)(struct pgp_parse_sig_context *context, - enum pgp_sig_subpkt_type type, - const u8 *data, - size_t datalen); + unsigned long types_of_interest[128 / __BITS_PER_LONG]; + int (*process_packet)(struct pgp_parse_sig_context *context, + enum pgp_sig_subpkt_type type, + const u8 *data, + size_t datalen); }; struct pgp_sig_parameters { - enum pgp_signature_version version : 8; - enum pgp_signature_type signature_type : 8; - enum pgp_pubkey_algo pubkey_algo : 8; - enum pgp_hash_algo hash_algo : 8; - union { - struct pgp_key_ID issuer; - __be32 issuer32[2]; - }; + enum pgp_signature_version version : 8; + enum pgp_signature_type signature_type : 8; + enum pgp_pubkey_algo pubkey_algo : 8; + enum pgp_hash_algo hash_algo : 8; + union { + struct pgp_key_ID issuer; + __be32 issuer32[2]; + }; }; struct pgp_signature_v3_packet { - enum pgp_signature_version version : 8; /* == PGP_SIG_VERSION_3 */ - u8 length_of_hashed; /* == 5 */ - struct { - enum pgp_signature_type signature_type : 8; - struct pgp_time creation_time; - } __attribute__((packed)) hashed; - struct pgp_key_ID issuer; - enum pgp_pubkey_algo pubkey_algo : 8; - enum pgp_hash_algo hash_algo : 8; + enum pgp_signature_version version : 8; /* == PGP_SIG_VERSION_3 */ + u8 length_of_hashed; /* == 5 */ + struct { + enum pgp_signature_type signature_type : 8; + struct pgp_time creation_time; + } __attribute__((packed)) hashed; + struct pgp_key_ID issuer; + enum pgp_pubkey_algo pubkey_algo : 8; + enum pgp_hash_algo hash_algo : 8; } __attribute__((packed)); struct pgp_signature_v4_packet { - enum pgp_signature_version version : 8; /* == PGP_SIG_VERSION_4 */ - enum pgp_signature_type signature_type : 8; - enum pgp_pubkey_algo pubkey_algo : 8; - enum pgp_hash_algo hash_algo : 8; + enum pgp_signature_version version : 8; /* == PGP_SIG_VERSION_4 */ + enum pgp_signature_type signature_type : 8; + enum pgp_pubkey_algo pubkey_algo : 8; + enum pgp_hash_algo hash_algo : 8; } __attribute__((packed)); int pgp_get_signature_data(const u8 *signature, size_t signature_len, - u8 **data, size_t *data_len, u8 **sig, - size_t *sig_len, u8 **issuer, u16 *algo); + u8 **data, size_t *data_len, u8 **sig, + size_t *sig_len, u8 **issuer, u16 *algo); #endif /* _PGP_H */ diff --git a/include/xattr.h b/include/xattr.h index a3b21b5..66873a1 100644 --- a/include/xattr.h +++ b/include/xattr.h @@ -18,14 +18,14 @@ #include "lib.h" int write_ima_xattr(int dirfd, char *path, u8 *keyid, size_t keyid_len, - u8 *sig, size_t sig_len, enum hash_algo algo); + u8 *sig, size_t sig_len, enum hash_algo algo); int write_evm_xattr(char *path, enum hash_algo algo); int parse_ima_xattr(u8 *buf, size_t buf_len, u8 **keyid, size_t *keyid_len, - u8 **sig, size_t *sig_len, enum hash_algo *algo); + u8 **sig, size_t *sig_len, enum hash_algo *algo); int read_ima_xattr(int dirfd, char *path, u8 **buf, size_t *buf_len, - u8 **keyid, size_t *keyid_len, u8 **sig, size_t *sig_len, - enum hash_algo *algo); + u8 **keyid, size_t *keyid_len, u8 **sig, size_t *sig_len, + enum hash_algo *algo); int gen_write_ima_xattr(u8 *buf, int *buf_len, char *path, u8 algo, u8 *digest, - bool immutable, bool write); + bool immutable, bool write); #endif /*_XATTR_H*/ diff --git a/initrd/dracut/load_digest_lists.sh b/initrd/dracut/load_digest_lists.sh index 9d6e5d1..3641672 100644 --- a/initrd/dracut/load_digest_lists.sh +++ b/initrd/dracut/load_digest_lists.sh @@ -1,29 +1,29 @@ #! /bin/bash if [ ! -f /sys/kernel/security/ima/digest_list_data ]; then - exit 0 + exit 0 fi digests_count=$(cat /sys/kernel/security/ima/digests_count) if [ "$digests_count" = "0" ]; then - exit 0 + exit 0 fi for f in $(find $NEWROOT/etc/ima/digest_lists -type f); do - if [ ! -f /etc/ima/digest_lists/$(basename $f) ]; then - process_digest_list=$(getfattr -m - -e hex -d $f \ - 2> /dev/null | awk '{ if ($1 ~ /security.evm/) evm=1; - if ($1 ~ /security.ima=0x03/) ima=1; } - END{ if (evm || ima) print "1" }') - if [ -z "$process_digest_list" ]; then - continue - fi + if [ ! -f /etc/ima/digest_lists/$(basename $f) ]; then + process_digest_list=$(getfattr -m - -e hex -d $f \ + 2> /dev/null | awk '{ if ($1 ~ /security.evm/) evm=1; + if ($1 ~ /security.ima=0x03/) ima=1; } + END{ if (evm || ima) print "1" }') + if [ -z "$process_digest_list" ]; then + continue + fi - format=$(echo $f | cut -d - -f 3) - if [ "$format" = "compact" ]; then - echo $f > /sys/kernel/security/ima/digest_list_data - else - upload_digest_lists add $f - fi - fi + format=$(echo $f | cut -d - -f 3) + if [ "$format" = "compact" ]; then + echo $f > /sys/kernel/security/ima/digest_list_data + else + upload_digest_lists add $f + fi + fi done diff --git a/initrd/dracut/upload_meta_digest_lists.sh b/initrd/dracut/upload_meta_digest_lists.sh index 6bf3b20..5e4ea14 100755 --- a/initrd/dracut/upload_meta_digest_lists.sh +++ b/initrd/dracut/upload_meta_digest_lists.sh @@ -3,7 +3,7 @@ attr -S -g evm /sysroot/bin/cat &> /dev/null if [ $? -eq 0 ]; then - exit 0 + exit 0 fi manage_digest_lists -p add-meta-digest diff --git a/lib/cap.c b/lib/cap.c index f7a91fe..4868e1c 100644 --- a/lib/cap.c +++ b/lib/cap.c @@ -32,134 +32,134 @@ #define CAP_SET_SIZE (__CAP_BLKS * sizeof(__u32)) struct _cap_struct { - struct __user_cap_header_struct head; - union { - struct __user_cap_data_struct set; - __u32 flat[NUMBER_OF_CAP_SETS]; - } u[_LINUX_CAPABILITY_U32S]; + struct __user_cap_header_struct head; + union { + struct __user_cap_data_struct set; + __u32 flat[NUMBER_OF_CAP_SETS]; + } u[_LINUX_CAPABILITY_U32S]; }; cap_t _fcaps_load(struct vfs_cap_data *rawvfscap, cap_t result, int bytes) { - __u32 magic_etc; - unsigned tocopy, i; - - magic_etc = FIXUP_32BITS(rawvfscap->magic_etc); - switch (magic_etc & VFS_CAP_REVISION_MASK) { - case VFS_CAP_REVISION_1: - tocopy = VFS_CAP_U32_1; - bytes -= XATTR_CAPS_SZ_1; - break; - - case VFS_CAP_REVISION_2: - tocopy = VFS_CAP_U32_2; - bytes -= XATTR_CAPS_SZ_2; - break; - - default: - cap_free(result); - result = NULL; - return result; - } - - /* - * Verify that we loaded exactly the right number of bytes - */ - if (bytes != 0) { - cap_free(result); - result = NULL; - return result; - } - - for (i=0; i < tocopy; i++) { - result->u[i].flat[CAP_INHERITABLE] = - FIXUP_32BITS(rawvfscap->data[i].inheritable); - result->u[i].flat[CAP_PERMITTED] = - FIXUP_32BITS(rawvfscap->data[i].permitted); - if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE) { - result->u[i].flat[CAP_EFFECTIVE] = - result->u[i].flat[CAP_INHERITABLE] | - result->u[i].flat[CAP_PERMITTED]; - } - } - - while (i < __CAP_BLKS) { - result->u[i].flat[CAP_INHERITABLE] = - result->u[i].flat[CAP_PERMITTED] = - result->u[i].flat[CAP_EFFECTIVE] = 0; - i++; - } - - return result; + __u32 magic_etc; + unsigned tocopy, i; + + magic_etc = FIXUP_32BITS(rawvfscap->magic_etc); + switch (magic_etc & VFS_CAP_REVISION_MASK) { + case VFS_CAP_REVISION_1: + tocopy = VFS_CAP_U32_1; + bytes -= XATTR_CAPS_SZ_1; + break; + + case VFS_CAP_REVISION_2: + tocopy = VFS_CAP_U32_2; + bytes -= XATTR_CAPS_SZ_2; + break; + + default: + cap_free(result); + result = NULL; + return result; + } + + /* + * Verify that we loaded exactly the right number of bytes + */ + if (bytes != 0) { + cap_free(result); + result = NULL; + return result; + } + + for (i=0; i < tocopy; i++) { + result->u[i].flat[CAP_INHERITABLE] = + FIXUP_32BITS(rawvfscap->data[i].inheritable); + result->u[i].flat[CAP_PERMITTED] = + FIXUP_32BITS(rawvfscap->data[i].permitted); + if (magic_etc & VFS_CAP_FLAGS_EFFECTIVE) { + result->u[i].flat[CAP_EFFECTIVE] = + result->u[i].flat[CAP_INHERITABLE] | + result->u[i].flat[CAP_PERMITTED]; + } + } + + while (i < __CAP_BLKS) { + result->u[i].flat[CAP_INHERITABLE] = + result->u[i].flat[CAP_PERMITTED] = + result->u[i].flat[CAP_EFFECTIVE] = 0; + i++; + } + + return result; } int _fcaps_save(struct vfs_cap_data *rawvfscap, cap_t cap_d, int *bytes_p) { - __u32 eff_not_zero, magic; - unsigned tocopy, i; - - switch (cap_d->head.version) { - case _LINUX_CAPABILITY_VERSION_1: - magic = VFS_CAP_REVISION_1; - tocopy = VFS_CAP_U32_1; - *bytes_p = XATTR_CAPS_SZ_1; - break; - - case _LINUX_CAPABILITY_VERSION_2: - magic = VFS_CAP_REVISION_2; - tocopy = VFS_CAP_U32_2; - *bytes_p = XATTR_CAPS_SZ_2; - break; - - case _LINUX_CAPABILITY_VERSION_3: - magic = VFS_CAP_REVISION_2; - tocopy = VFS_CAP_U32_2; - *bytes_p = XATTR_CAPS_SZ_2; - break; - - default: - errno = EINVAL; - return -1; - } - - for (eff_not_zero = 0, i = 0; i < tocopy; i++) { - eff_not_zero |= cap_d->u[i].flat[CAP_EFFECTIVE]; - } - - while (i < __CAP_BLKS) { - if ((cap_d->u[i].flat[CAP_EFFECTIVE] || - cap_d->u[i].flat[CAP_INHERITABLE] || - cap_d->u[i].flat[CAP_PERMITTED])) { - /* - * System does not support these capabilities - */ - errno = EINVAL; - return -1; - } - i++; - } - - for (i=0; i < tocopy; i++) { - rawvfscap->data[i].permitted = - FIXUP_32BITS(cap_d->u[i].flat[CAP_PERMITTED]); - rawvfscap->data[i].inheritable = - FIXUP_32BITS(cap_d->u[i].flat[CAP_INHERITABLE]); - - if (eff_not_zero - && ((~(cap_d->u[i].flat[CAP_EFFECTIVE])) & - (cap_d->u[i].flat[CAP_PERMITTED] | - cap_d->u[i].flat[CAP_INHERITABLE]))) { - errno = EINVAL; - return -1; - } - } - - if (eff_not_zero == 0) { - rawvfscap->magic_etc = FIXUP_32BITS(magic); - } else { - rawvfscap->magic_etc = - FIXUP_32BITS(magic|VFS_CAP_FLAGS_EFFECTIVE); - } - - return 0; /* success */ + __u32 eff_not_zero, magic; + unsigned tocopy, i; + + switch (cap_d->head.version) { + case _LINUX_CAPABILITY_VERSION_1: + magic = VFS_CAP_REVISION_1; + tocopy = VFS_CAP_U32_1; + *bytes_p = XATTR_CAPS_SZ_1; + break; + + case _LINUX_CAPABILITY_VERSION_2: + magic = VFS_CAP_REVISION_2; + tocopy = VFS_CAP_U32_2; + *bytes_p = XATTR_CAPS_SZ_2; + break; + + case _LINUX_CAPABILITY_VERSION_3: + magic = VFS_CAP_REVISION_2; + tocopy = VFS_CAP_U32_2; + *bytes_p = XATTR_CAPS_SZ_2; + break; + + default: + errno = EINVAL; + return -1; + } + + for (eff_not_zero = 0, i = 0; i < tocopy; i++) { + eff_not_zero |= cap_d->u[i].flat[CAP_EFFECTIVE]; + } + + while (i < __CAP_BLKS) { + if ((cap_d->u[i].flat[CAP_EFFECTIVE] || + cap_d->u[i].flat[CAP_INHERITABLE] || + cap_d->u[i].flat[CAP_PERMITTED])) { + /* + * System does not support these capabilities + */ + errno = EINVAL; + return -1; + } + i++; + } + + for (i=0; i < tocopy; i++) { + rawvfscap->data[i].permitted = + FIXUP_32BITS(cap_d->u[i].flat[CAP_PERMITTED]); + rawvfscap->data[i].inheritable = + FIXUP_32BITS(cap_d->u[i].flat[CAP_INHERITABLE]); + + if (eff_not_zero + && ((~(cap_d->u[i].flat[CAP_EFFECTIVE])) & + (cap_d->u[i].flat[CAP_PERMITTED] | + cap_d->u[i].flat[CAP_INHERITABLE]))) { + errno = EINVAL; + return -1; + } + } + + if (eff_not_zero == 0) { + rawvfscap->magic_etc = FIXUP_32BITS(magic); + } else { + rawvfscap->magic_etc = + FIXUP_32BITS(magic|VFS_CAP_FLAGS_EFFECTIVE); + } + + return 0; /* success */ } diff --git a/lib/compact_list.c b/lib/compact_list.c index f2667f4..1f1cd23 100644 --- a/lib/compact_list.c +++ b/lib/compact_list.c @@ -41,515 +41,515 @@ #define DIGEST_LIST_ALGO HASH_ALGO_SHA256 char *compact_types_str[COMPACT__LAST] = { - [COMPACT_KEY] = "key", - [COMPACT_PARSER] = "parser", - [COMPACT_FILE] = "file", - [COMPACT_METADATA] = "metadata", + [COMPACT_KEY] = "key", + [COMPACT_PARSER] = "parser", + [COMPACT_FILE] = "file", + [COMPACT_METADATA] = "metadata", }; char *compact_modifiers_str[COMPACT_MOD__LAST] = { - [COMPACT_MOD_IMMUTABLE] = "immutable", + [COMPACT_MOD_IMMUTABLE] = "immutable", }; static char *compact_list_tlv_ids[ID__LAST] = { - [ID_DIGEST] = "IMA digest", - [ID_EVM_DIGEST] = "EVM digest", - [ID_PATH] = "path", - [ID_INODE_UID] = "inode UID", - [ID_INODE_GID] = "inode GID", - [ID_INODE_MODE] = "inode mode", - [ID_INODE_SIZE] = "inode size", - [ID_FSMAGIC] = "filesystem magic", - [ID_OBJ_LABEL] = "object label", - [ID_CAPS] = "capabilities", + [ID_DIGEST] = "IMA digest", + [ID_EVM_DIGEST] = "EVM digest", + [ID_PATH] = "path", + [ID_INODE_UID] = "inode UID", + [ID_INODE_GID] = "inode GID", + [ID_INODE_MODE] = "inode mode", + [ID_INODE_SIZE] = "inode size", + [ID_FSMAGIC] = "filesystem magic", + [ID_OBJ_LABEL] = "object label", + [ID_CAPS] = "capabilities", }; struct list_struct *compact_list_init(struct list_head *head, - enum compact_types type, u16 modifiers, - enum hash_algo algo, bool tlv) + enum compact_types type, u16 modifiers, + enum hash_algo algo, bool tlv) { - struct list_struct *list; - - list_for_each_entry(list, head, list) { - if (list->hdr->type == type && - list->hdr->modifiers == modifiers && - list->hdr->algo == algo) - return list; - } - - list = malloc(sizeof(*list)); - if (!list) - return list; - - list->hdr = mmap(NULL, COMPACT_LIST_SIZE_MAX, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); - if (list->hdr == MAP_FAILED) { - printf("Cannot allocate buffer\n"); - free(list); - return NULL; - } - - list->hdr->version = tlv ? 2 : 1; - list->hdr->type = type; - list->hdr->modifiers = modifiers; - list->hdr->algo = algo; - list->hdr->count = 0; - list->hdr->datalen = 0; - list_add_tail(&list->list, head); - - return list; + struct list_struct *list; + + list_for_each_entry(list, head, list) { + if (list->hdr->type == type && + list->hdr->modifiers == modifiers && + list->hdr->algo == algo) + return list; + } + + list = malloc(sizeof(*list)); + if (!list) + return list; + + list->hdr = mmap(NULL, COMPACT_LIST_SIZE_MAX, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); + if (list->hdr == MAP_FAILED) { + printf("Cannot allocate buffer\n"); + free(list); + return NULL; + } + + list->hdr->version = tlv ? 2 : 1; + list->hdr->type = type; + list->hdr->modifiers = modifiers; + list->hdr->algo = algo; + list->hdr->count = 0; + list->hdr->datalen = 0; + list_add_tail(&list->list, head); + + return list; } int compact_list_add_digest(int fd, struct list_struct *list, u8 *digest) { - struct compact_list_hdr *hdr = list->hdr; - int digest_len = hash_digest_size[hdr->algo]; - void *ptr; + struct compact_list_hdr *hdr = list->hdr; + int digest_len = hash_digest_size[hdr->algo]; + void *ptr; - ptr = (void *)hdr + sizeof(*hdr) + hdr->datalen; + ptr = (void *)hdr + sizeof(*hdr) + hdr->datalen; - memcpy(ptr, digest, digest_len); - hdr->datalen += digest_len; - hdr->count++; + memcpy(ptr, digest, digest_len); + hdr->datalen += digest_len; + hdr->count++; - if (hdr->datalen + digest_len < COMPACT_LIST_SIZE_MAX) - return 0; + if (hdr->datalen + digest_len < COMPACT_LIST_SIZE_MAX) + return 0; - return compact_list_upload(fd, list); + return compact_list_upload(fd, list); } int compact_list_tlv_add_digest(int fd, struct list_struct *list, - struct list_head *head, u8 *digest, - enum tlv_ids id) + struct list_head *head, u8 *digest, + enum tlv_ids id) { - struct compact_list_hdr *hdr = list->hdr; - int digest_len = hash_digest_size[hdr->algo]; + struct compact_list_hdr *hdr = list->hdr; + int digest_len = hash_digest_size[hdr->algo]; - return compact_list_tlv_add_item(fd, list, head, id, digest_len, - digest); + return compact_list_tlv_add_item(fd, list, head, id, digest_len, + digest); } int compact_list_tlv_add_metadata(int fd, struct list_struct *list, - struct list_head *head, char *path, - char *alt_root, struct stat *st, - char *obj_label, int obj_label_len, - u8 *caps_bin, int caps_bin_len) + struct list_head *head, char *path, + char *alt_root, struct stat *st, + char *obj_label, int obj_label_len, + u8 *caps_bin, int caps_bin_len) { - struct stat s; - u32 inode_metadata[4]; - u64 fs_magic; - struct statfs sfsb; - char *caps; - cap_t c, r; - int alt_root_len = alt_root ? strlen(alt_root) : 0; - int rc, i; - - sfsb.f_type = 0; - - if (!st) { - if (stat(path, &s) == -1) - return -EACCES; - - st = &s; - - if (statfs(path, &sfsb) == -1) - return -EACCES; - } - - rc = compact_list_tlv_add_item(fd, list, head, ID_PATH, - strlen(path) + 1 - alt_root_len, - (u8 *)path + alt_root_len); - if (rc < 0) - return rc; - - if (obj_label_len) { - rc = compact_list_tlv_add_item(fd, list, head, ID_OBJ_LABEL, - obj_label_len, (u8 *)obj_label); - if (rc < 0) - return rc; - } - - if (caps_bin_len) { - c = cap_init(); - - r = _fcaps_load((struct vfs_cap_data *)caps_bin, c, - caps_bin_len); - if (!r) { - cap_free(c); - return -EINVAL; - } - - caps = cap_to_text(r, NULL); - cap_free(c); - - if (!caps) - return -EINVAL; - - rc = compact_list_tlv_add_item(fd, list, head, ID_CAPS, - strlen(caps) + 1, (u8 *)caps); - - cap_free(caps); - - if (rc < 0) - return rc; - } - - inode_metadata[0] = st->st_uid; - inode_metadata[1] = st->st_gid; - inode_metadata[2] = st->st_mode; - inode_metadata[3] = st->st_size; - - for (i = 0; i < 4; i++) { - if (ima_canonical_fmt) - inode_metadata[i] = cpu_to_le32(inode_metadata[i]); - - rc = compact_list_tlv_add_item(fd, list, head, ID_INODE_UID + i, - sizeof(u32), (u8 *)&inode_metadata[i]); - if (rc < 0) - return rc; - } - - fs_magic = sfsb.f_type; - if (ima_canonical_fmt) - fs_magic = cpu_to_le64(fs_magic); - - rc = compact_list_tlv_add_item(fd, list, head, ID_FSMAGIC, sizeof(u64), - (u8 *)&fs_magic); - if (rc < 0) - return rc; - - return 0; + struct stat s; + u32 inode_metadata[4]; + u64 fs_magic; + struct statfs sfsb; + char *caps; + cap_t c, r; + int alt_root_len = alt_root ? strlen(alt_root) : 0; + int rc, i; + + sfsb.f_type = 0; + + if (!st) { + if (stat(path, &s) == -1) + return -EACCES; + + st = &s; + + if (statfs(path, &sfsb) == -1) + return -EACCES; + } + + rc = compact_list_tlv_add_item(fd, list, head, ID_PATH, + strlen(path) + 1 - alt_root_len, + (u8 *)path + alt_root_len); + if (rc < 0) + return rc; + + if (obj_label_len) { + rc = compact_list_tlv_add_item(fd, list, head, ID_OBJ_LABEL, + obj_label_len, (u8 *)obj_label); + if (rc < 0) + return rc; + } + + if (caps_bin_len) { + c = cap_init(); + + r = _fcaps_load((struct vfs_cap_data *)caps_bin, c, + caps_bin_len); + if (!r) { + cap_free(c); + return -EINVAL; + } + + caps = cap_to_text(r, NULL); + cap_free(c); + + if (!caps) + return -EINVAL; + + rc = compact_list_tlv_add_item(fd, list, head, ID_CAPS, + strlen(caps) + 1, (u8 *)caps); + + cap_free(caps); + + if (rc < 0) + return rc; + } + + inode_metadata[0] = st->st_uid; + inode_metadata[1] = st->st_gid; + inode_metadata[2] = st->st_mode; + inode_metadata[3] = st->st_size; + + for (i = 0; i < 4; i++) { + if (ima_canonical_fmt) + inode_metadata[i] = cpu_to_le32(inode_metadata[i]); + + rc = compact_list_tlv_add_item(fd, list, head, ID_INODE_UID + i, + sizeof(u32), (u8 *)&inode_metadata[i]); + if (rc < 0) + return rc; + } + + fs_magic = sfsb.f_type; + if (ima_canonical_fmt) + fs_magic = cpu_to_le64(fs_magic); + + rc = compact_list_tlv_add_item(fd, list, head, ID_FSMAGIC, sizeof(u64), + (u8 *)&fs_magic); + if (rc < 0) + return rc; + + return 0; } int compact_list_tlv_add_item(int fd, struct list_struct *list, - struct list_head *head, enum tlv_ids id, - size_t len, u8 *data) + struct list_head *head, enum tlv_ids id, + size_t len, u8 *data) { - struct tlv_item *cur, *new_item; + struct tlv_item *cur, *new_item; - list_for_each_entry(cur, head, list) - if (cur->item->id == id) - return -EEXIST; + list_for_each_entry(cur, head, list) + if (cur->item->id == id) + return -EEXIST; - new_item = malloc(sizeof(*new_item)); - if (!new_item) - return -ENOMEM; + new_item = malloc(sizeof(*new_item)); + if (!new_item) + return -ENOMEM; - new_item->item = malloc(sizeof(*new_item->item) + len); - if (!new_item->item) { - free(new_item); - return -ENOMEM; - } + new_item->item = malloc(sizeof(*new_item->item) + len); + if (!new_item->item) { + free(new_item); + return -ENOMEM; + } - new_item->item->id = id; - new_item->item->len = len; - memcpy(new_item->item->data, data, len); + new_item->item->id = id; + new_item->item->len = len; + memcpy(new_item->item->data, data, len); - list_add_tail(&new_item->list, head); - return 0; + list_add_tail(&new_item->list, head); + return 0; } int compact_list_tlv_add_items(int fd, struct list_struct *list, - struct list_head *head) + struct list_head *head) { - struct compact_list_hdr *hdr = list->hdr; - struct tlv_item *cur; - size_t items_len = 0; - u8 count = 0; - u8 *ptr; - int rc = 0; - - list_for_each_entry(cur, head, list) { - items_len += (sizeof(u8) + sizeof(u32) + cur->item->len); - count++; - } - - if (items_len > COMPACT_LIST_SIZE_MAX - sizeof(*hdr)) { - rc = -EINVAL; - goto out; - } - - ptr = (void *)hdr + sizeof(*hdr) + hdr->datalen; - if (hdr->datalen + sizeof(u8) + items_len > COMPACT_LIST_SIZE_MAX) { - rc = compact_list_upload(fd, list); - if (rc) - goto out; - - return compact_list_tlv_add_items(fd, list, head); - } - - *ptr++ = count; - - list_for_each_entry(cur, head, list) { - *ptr++ = cur->item->id; - - if (ima_canonical_fmt) - cur->item->len = cpu_to_be32(cur->item->len); - - memcpy(ptr, &cur->item->len, sizeof(cur->item->len)); - ptr += sizeof(cur->item->len); - memcpy(ptr, cur->item->data, cur->item->len); - ptr += cur->item->len; - } - - hdr->datalen += sizeof(u8) + items_len; - hdr->count++; + struct compact_list_hdr *hdr = list->hdr; + struct tlv_item *cur; + size_t items_len = 0; + u8 count = 0; + u8 *ptr; + int rc = 0; + + list_for_each_entry(cur, head, list) { + items_len += (sizeof(u8) + sizeof(u32) + cur->item->len); + count++; + } + + if (items_len > COMPACT_LIST_SIZE_MAX - sizeof(*hdr)) { + rc = -EINVAL; + goto out; + } + + ptr = (void *)hdr + sizeof(*hdr) + hdr->datalen; + if (hdr->datalen + sizeof(u8) + items_len > COMPACT_LIST_SIZE_MAX) { + rc = compact_list_upload(fd, list); + if (rc) + goto out; + + return compact_list_tlv_add_items(fd, list, head); + } + + *ptr++ = count; + + list_for_each_entry(cur, head, list) { + *ptr++ = cur->item->id; + + if (ima_canonical_fmt) + cur->item->len = cpu_to_be32(cur->item->len); + + memcpy(ptr, &cur->item->len, sizeof(cur->item->len)); + ptr += sizeof(cur->item->len); + memcpy(ptr, cur->item->data, cur->item->len); + ptr += cur->item->len; + } + + hdr->datalen += sizeof(u8) + items_len; + hdr->count++; out: - return rc; + return rc; } static void hexdump(u8 *buf, int len) { - while (--len >= 0) - printf("%02x", *buf++); + while (--len >= 0) + printf("%02x", *buf++); } void compact_list_tlv_dump_items(struct _tlv_item **items) { - u32 u32_value; - u64 u64_value; - int i; - - for (i = 0; i < ID__LAST; i++) { - if (!items[i]) - continue; - - if (i) - printf("|"); - - printf("%s: ", compact_list_tlv_ids[i]); - - switch(i) { - case ID_DIGEST: - case ID_EVM_DIGEST: - hexdump(items[i]->data, items[i]->len); - break; - case ID_PATH: - case ID_OBJ_LABEL: - case ID_CAPS: - printf("%s", (char *)items[i]->data); - break; - case ID_INODE_UID: - case ID_INODE_GID: - case ID_INODE_MODE: - case ID_INODE_SIZE: - u32_value = *(u32 *)items[i]->data; - u32_value = le32_to_cpu(u32_value); - printf("%u", u32_value); - break; - case ID_FSMAGIC: - u64_value = *(u64 *)items[i]->data; - u64_value = le64_to_cpu(u64_value); - printf("%lu", u64_value); - break; - default: - break; - } - } - - printf("\n"); + u32 u32_value; + u64 u64_value; + int i; + + for (i = 0; i < ID__LAST; i++) { + if (!items[i]) + continue; + + if (i) + printf("|"); + + printf("%s: ", compact_list_tlv_ids[i]); + + switch(i) { + case ID_DIGEST: + case ID_EVM_DIGEST: + hexdump(items[i]->data, items[i]->len); + break; + case ID_PATH: + case ID_OBJ_LABEL: + case ID_CAPS: + printf("%s", (char *)items[i]->data); + break; + case ID_INODE_UID: + case ID_INODE_GID: + case ID_INODE_MODE: + case ID_INODE_SIZE: + u32_value = *(u32 *)items[i]->data; + u32_value = le32_to_cpu(u32_value); + printf("%u", u32_value); + break; + case ID_FSMAGIC: + u64_value = *(u64 *)items[i]->data; + u64_value = le64_to_cpu(u64_value); + printf("%lu", u64_value); + break; + default: + break; + } + } + + printf("\n"); } void compact_list_tlv_free_items(struct list_head *head) { - struct tlv_item *p, *q; + struct tlv_item *p, *q; - list_for_each_entry_safe(p, q, head, list) { - list_del(&p->list); - free(p->item); - free(p); - } + list_for_each_entry_safe(p, q, head, list) { + list_del(&p->list); + free(p->item); + free(p); + } } int compact_list_upload(int fd, struct list_struct *list) { - struct compact_list_hdr *hdr = list->hdr; - struct compact_list_hdr h = { .version = hdr->version, - .type = hdr->type, - .modifiers = hdr->modifiers, - .algo = hdr->algo, - .count = 0, - .datalen = 0 }; - u32 datalen; - int ret; - - if (fd < 0) - return 0; - - hdr = list->hdr; - datalen = hdr->datalen; - - if (!datalen) - return 0; - - if (ima_canonical_fmt) { - hdr->type = cpu_to_le16(hdr->type); - hdr->modifiers = cpu_to_le16(hdr->modifiers); - hdr->algo = cpu_to_le16(hdr->algo); - hdr->count = cpu_to_le32(hdr->count); - hdr->datalen = cpu_to_le32(hdr->datalen); - } - - ret = write_check(fd, (void *)hdr, sizeof(*hdr) + datalen); - memcpy(hdr, &h, sizeof(h)); - return ret; + struct compact_list_hdr *hdr = list->hdr; + struct compact_list_hdr h = { .version = hdr->version, + .type = hdr->type, + .modifiers = hdr->modifiers, + .algo = hdr->algo, + .count = 0, + .datalen = 0 }; + u32 datalen; + int ret; + + if (fd < 0) + return 0; + + hdr = list->hdr; + datalen = hdr->datalen; + + if (!datalen) + return 0; + + if (ima_canonical_fmt) { + hdr->type = cpu_to_le16(hdr->type); + hdr->modifiers = cpu_to_le16(hdr->modifiers); + hdr->algo = cpu_to_le16(hdr->algo); + hdr->count = cpu_to_le32(hdr->count); + hdr->datalen = cpu_to_le32(hdr->datalen); + } + + ret = write_check(fd, (void *)hdr, sizeof(*hdr) + datalen); + memcpy(hdr, &h, sizeof(h)); + return ret; } int compact_list_flush_all(int fd, struct list_head *head) { - struct list_struct *p, *q; - int ret = 0; + struct list_struct *p, *q; + int ret = 0; - list_for_each_entry_safe(p, q, head, list) { - if (!ret && fd > 0) - ret = compact_list_upload(fd, p); + list_for_each_entry_safe(p, q, head, list) { + if (!ret && fd > 0) + ret = compact_list_upload(fd, p); - munmap(p->hdr, COMPACT_LIST_SIZE_MAX); - list_del(&p->list); - free(p); - } + munmap(p->hdr, COMPACT_LIST_SIZE_MAX); + list_del(&p->list); + free(p); + } - return ret; + return ret; } int gen_filename_prefix(char *filename, int filename_len, int pos, - const char *format, enum compact_types type) + const char *format, enum compact_types type) { - return snprintf(filename, filename_len, "%d-%s_list-%s-", - (pos >= 0) ? pos : 0, compact_types_str[type], format); + return snprintf(filename, filename_len, "%d-%s_list-%s-", + (pos >= 0) ? pos : 0, compact_types_str[type], format); } static int filter_lists_common(const struct dirent *file, - enum compact_types type) + enum compact_types type) { - const char *filename = file->d_name; - char id_str[NAME_MAX + 1]; - unsigned long pos; - char *ptr; + const char *filename = file->d_name; + char id_str[NAME_MAX + 1]; + unsigned long pos; + char *ptr; - pos = strtoul(filename, &ptr, 10); - if (pos < 0) - return 0; + pos = strtoul(filename, &ptr, 10); + if (pos < 0) + return 0; - snprintf(id_str, sizeof(id_str), "-%s_list-", compact_types_str[type]); + snprintf(id_str, sizeof(id_str), "-%s_list-", compact_types_str[type]); - if (strncmp(ptr, id_str, strlen(id_str))) - return 0; + if (strncmp(ptr, id_str, strlen(id_str))) + return 0; - if (!strncmp(filename + strlen(filename) - 4, ".sig", 4)) - return 0; + if (!strncmp(filename + strlen(filename) - 4, ".sig", 4)) + return 0; - return 1; + return 1; } int filter_key_lists(const struct dirent *file) { - return filter_lists_common(file, COMPACT_KEY); + return filter_lists_common(file, COMPACT_KEY); } int filter_parser_lists(const struct dirent *file) { - return filter_lists_common(file, COMPACT_PARSER); + return filter_lists_common(file, COMPACT_PARSER); } int filter_parser_list_symlink(const struct dirent *file) { - if (file->d_type == DT_LNK && - !strncmp(file->d_name, "compact-", 8)) - return 1; + if (file->d_type == DT_LNK && + !strncmp(file->d_name, "compact-", 8)) + return 1; - return 0; + return 0; } int filter_file_lists(const struct dirent *file) { - return filter_lists_common(file, COMPACT_FILE); + return filter_lists_common(file, COMPACT_FILE); } int filter_metadata_lists(const struct dirent *file) { - return filter_lists_common(file, COMPACT_METADATA); + return filter_lists_common(file, COMPACT_METADATA); } filter_lists filter[COMPACT__LAST] = { - [COMPACT_KEY] = filter_key_lists, - [COMPACT_PARSER] = filter_parser_lists, - [COMPACT_FILE] = filter_file_lists, - [COMPACT_METADATA] = filter_metadata_lists, + [COMPACT_KEY] = filter_key_lists, + [COMPACT_PARSER] = filter_parser_lists, + [COMPACT_FILE] = filter_file_lists, + [COMPACT_METADATA] = filter_metadata_lists, }; int get_digest_lists(int dirfd, enum compact_types type, struct list_head *head) { - struct dirent **digest_lists; - int ret = 0, i, n; + struct dirent **digest_lists; + int ret = 0, i, n; - n = scandirat(dirfd, ".", &digest_lists, filter[type], compare_lists); - if (n == -1) { - printf("Unable to access digest lists\n"); - return -EACCES; - } + n = scandirat(dirfd, ".", &digest_lists, filter[type], compare_lists); + if (n == -1) { + printf("Unable to access digest lists\n"); + return -EACCES; + } - for (i = 0; i < n; i++) { - if (!ret) - ret = add_path_struct(digest_lists[i]->d_name, NULL, - head); + for (i = 0; i < n; i++) { + if (!ret) + ret = add_path_struct(digest_lists[i]->d_name, NULL, + head); - free(digest_lists[i]); - } + free(digest_lists[i]); + } - free(digest_lists); - return ret; + free(digest_lists); + return ret; } int compare_lists(const struct dirent **e1, const struct dirent **e2) { - unsigned long v1 = strtoul((*e1)->d_name, NULL, 10); - unsigned long v2 = strtoul((*e2)->d_name, NULL, 10); + unsigned long v1 = strtoul((*e1)->d_name, NULL, 10); + unsigned long v2 = strtoul((*e2)->d_name, NULL, 10); - return v1 - v2; + return v1 - v2; } static int key_upload(int dirfd, char *key_filename) { - key_serial_t ima_keyring; - void *buf; - loff_t size; - int ret; - - ima_keyring = syscall(__NR_request_key, "keyring", "_ima", - NULL, KEY_SPEC_USER_KEYRING); - if (!ima_keyring) { - ima_keyring = syscall(__NR_add_key, "keyring", "_ima", - NULL, 0, KEY_SPEC_USER_KEYRING); - if (ima_keyring == -1) - return -EPERM; - } - - ret = read_file_from_path(dirfd, key_filename, &buf, &size); - if (ret) - return ret; - - return syscall(__NR_add_key, "asymmetric", NULL, buf, size, - ima_keyring); + key_serial_t ima_keyring; + void *buf; + loff_t size; + int ret; + + ima_keyring = syscall(__NR_request_key, "keyring", "_ima", + NULL, KEY_SPEC_USER_KEYRING); + if (!ima_keyring) { + ima_keyring = syscall(__NR_add_key, "keyring", "_ima", + NULL, 0, KEY_SPEC_USER_KEYRING); + if (ima_keyring == -1) + return -EPERM; + } + + ret = read_file_from_path(dirfd, key_filename, &buf, &size); + if (ret) + return ret; + + return syscall(__NR_add_key, "asymmetric", NULL, buf, size, + ima_keyring); } int digest_list_add_metadata(int dirfd, int fd, char *digest_list_filename, - char *digest_lists_dir, struct list_head *head, - u8 *digest_list_buf, size_t digest_list_buf_len) + char *digest_lists_dir, struct list_head *head, + u8 *digest_list_buf, size_t digest_list_buf_len) { - u8 ima_digest[SHA512_DIGEST_SIZE]; - u8 evm_digest[SHA512_DIGEST_SIZE]; - char path[PATH_MAX]; - struct list_struct *list; - LIST_HEAD(keys); - struct key_struct *k; - struct stat st; - enum hash_algo algo, evm_algo = HASH_ALGO_SHA256; - u8 *buf, *key_id, *sig; - char *obj_label = NULL; - size_t buf_len, keyid_len, sig_len; - int ret; + u8 ima_digest[SHA512_DIGEST_SIZE]; + u8 evm_digest[SHA512_DIGEST_SIZE]; + char path[PATH_MAX]; + struct list_struct *list; + LIST_HEAD(keys); + struct key_struct *k; + struct stat st; + enum hash_algo algo, evm_algo = HASH_ALGO_SHA256; + u8 *buf, *key_id, *sig; + char *obj_label = NULL; + size_t buf_len, keyid_len, sig_len; + int ret; fd = openat(dirfd, digest_list_filename, O_RDONLY); if (fd < 0) { @@ -559,255 +559,255 @@ int digest_list_add_metadata(int dirfd, int fd, char *digest_list_filename, ret = fgetxattr(fd, XATTR_NAME_EVM, NULL, 0); close(fd); - if (ret > 0) - return 0; - - ret = read_ima_xattr(dirfd, digest_list_filename, &buf, &buf_len, - &key_id, &keyid_len, &sig, &sig_len, &algo); - if (ret < 0) - return ret; - - if (!sig_len) - goto out; - - ret = calc_digest(ima_digest, digest_list_buf, digest_list_buf_len, - algo); - if (ret < 0) - goto out; - - k = new_key(&keys, -1, IMA_KEY_PATH, NULL, false); - if (!k) { - ret = -EINVAL; - goto out; - } - - ret = verify_sig(&keys, dirfd, buf, buf_len, ima_digest, algo); - if (ret < 0) - goto out_key; - - list = compact_list_init(head, COMPACT_METADATA, - (1 << COMPACT_MOD_IMMUTABLE), evm_algo, false); - if (!list) - goto out_key; - - snprintf(path, sizeof(path), "%s/%s", digest_lists_dir, - digest_list_filename); - - if (stat(path, &st) == -1) - goto out_key; - - ret = get_selinux_label(path, NULL, &obj_label, st.st_mode); - if (ret < 0) - goto out_key; - - ret = evm_calc_hmac_or_hash(evm_algo, evm_digest, - obj_label ? strlen(obj_label) + 1 : 0, - obj_label, buf_len, buf, 0, NULL, 0, 0, - st.st_mode); - if (ret < 0) - goto out_key; - - ret = compact_list_add_digest(fd, list, evm_digest); + if (ret > 0) + return 0; + + ret = read_ima_xattr(dirfd, digest_list_filename, &buf, &buf_len, + &key_id, &keyid_len, &sig, &sig_len, &algo); + if (ret < 0) + return ret; + + if (!sig_len) + goto out; + + ret = calc_digest(ima_digest, digest_list_buf, digest_list_buf_len, + algo); + if (ret < 0) + goto out; + + k = new_key(&keys, -1, IMA_KEY_PATH, NULL, false); + if (!k) { + ret = -EINVAL; + goto out; + } + + ret = verify_sig(&keys, dirfd, buf, buf_len, ima_digest, algo); + if (ret < 0) + goto out_key; + + list = compact_list_init(head, COMPACT_METADATA, + (1 << COMPACT_MOD_IMMUTABLE), evm_algo, false); + if (!list) + goto out_key; + + snprintf(path, sizeof(path), "%s/%s", digest_lists_dir, + digest_list_filename); + + if (stat(path, &st) == -1) + goto out_key; + + ret = get_selinux_label(path, NULL, &obj_label, st.st_mode); + if (ret < 0) + goto out_key; + + ret = evm_calc_hmac_or_hash(evm_algo, evm_digest, + obj_label ? strlen(obj_label) + 1 : 0, + obj_label, buf_len, buf, 0, NULL, 0, 0, + st.st_mode); + if (ret < 0) + goto out_key; + + ret = compact_list_add_digest(fd, list, evm_digest); out_key: - free_keys(&keys); + free_keys(&keys); out: - free(obj_label); - free(buf); - return ret; + free(obj_label); + free(buf); + return ret; } int digest_list_upload(int dirfd, int fd, struct list_head *head, - struct list_head *parser_lib_head, - char *digest_list_filename, enum parser_ops op, - char *digest_lists_dir) + struct list_head *parser_lib_head, + char *digest_list_filename, enum parser_ops op, + char *digest_lists_dir) { - char *list_id, *format_start, *format_end; - struct lib *parser; - void *buf; - loff_t size; - int ret; - - list_id = strchr(digest_list_filename, '-'); - if (!list_id++) - return -EINVAL; - - format_start = strchr(list_id, '-'); - if (!format_start++) - return -EINVAL; - - format_end = strchr(format_start + 1, '-'); - if (!format_end) - return -EINVAL; - - ret = read_file_from_path(dirfd, digest_list_filename, &buf, &size); - if (ret) - return ret; - - if (!strncmp(format_start, "compact", format_end - format_start) && - *format_end == '-') { - if (op == PARSER_OP_ADD_META_DIGEST) - goto out_add_metadata; - - if (fd >= 0) { - ret = write_check(fd, buf, size); - } else { - ret = ima_parse_compact_list(size, buf, - (op == PARSER_OP_ADD_DIGEST_TO_HTABLE || - op == PARSER_OP_ADD_META_DIGEST_TO_HTABLE) ? - ima_add_digest_data_entry_kernel : default_func, - NULL); - if (ret == size) - ret = 0; - } - goto out_add_metadata; - } - - parser = lookup_lib(parser_lib_head, "parser", - format_start, format_end - format_start); - if (!parser) { - printf("Cannot find a parser for %s\n", digest_list_filename); - ret = -ENOENT; - goto out; - } - - ret = ((parser_func)parser->func)(fd, head, size, buf, op); + char *list_id, *format_start, *format_end; + struct lib *parser; + void *buf; + loff_t size; + int ret; + + list_id = strchr(digest_list_filename, '-'); + if (!list_id++) + return -EINVAL; + + format_start = strchr(list_id, '-'); + if (!format_start++) + return -EINVAL; + + format_end = strchr(format_start + 1, '-'); + if (!format_end) + return -EINVAL; + + ret = read_file_from_path(dirfd, digest_list_filename, &buf, &size); + if (ret) + return ret; + + if (!strncmp(format_start, "compact", format_end - format_start) && + *format_end == '-') { + if (op == PARSER_OP_ADD_META_DIGEST) + goto out_add_metadata; + + if (fd >= 0) { + ret = write_check(fd, buf, size); + } else { + ret = ima_parse_compact_list(size, buf, + (op == PARSER_OP_ADD_DIGEST_TO_HTABLE || + op == PARSER_OP_ADD_META_DIGEST_TO_HTABLE) ? + ima_add_digest_data_entry_kernel : default_func, + NULL); + if (ret == size) + ret = 0; + } + goto out_add_metadata; + } + + parser = lookup_lib(parser_lib_head, "parser", + format_start, format_end - format_start); + if (!parser) { + printf("Cannot find a parser for %s\n", digest_list_filename); + ret = -ENOENT; + goto out; + } + + ret = ((parser_func)parser->func)(fd, head, size, buf, op); out_add_metadata: - if (ret < 0) - goto out; + if (ret < 0) + goto out; - if (op == PARSER_OP_ADD_META_DIGEST) - ret = digest_list_add_metadata(dirfd, fd, digest_list_filename, - digest_lists_dir, head, buf, - size); + if (op == PARSER_OP_ADD_META_DIGEST) + ret = digest_list_add_metadata(dirfd, fd, digest_list_filename, + digest_lists_dir, head, buf, + size); out: - munmap(buf, size); - return ret; + munmap(buf, size); + return ret; } int process_lists(int dirfd, int fd, int save, int verbose, - struct list_head *head, enum compact_types type, - enum parser_ops op, char *digest_lists_dir, char *filename) + struct list_head *head, enum compact_types type, + enum parser_ops op, char *digest_lists_dir, char *filename) { - struct dirent **digest_lists; - LIST_HEAD(parser_lib_head); - struct key_struct *k; - char path[PATH_MAX], path_sig[PATH_MAX]; - u8 digest[SHA512_DIGEST_SIZE]; - u8 xattr[2 + SHA512_DIGEST_SIZE]; - void *sig; - loff_t sig_len; - int ret, i, n, xattr_len; - - n = scandirat(dirfd, ".", &digest_lists, filter[type], compare_lists); - if (n == -1) { - printf("Unable to access digest lists\n"); - return -EACCES; - } - - for (i = 0; i < n; i++) { - if (filename && strcmp(digest_lists[i]->d_name, filename)) - continue; - - if (verbose) - printf("Processing: %s\n", digest_lists[i]->d_name); - - if (type == COMPACT_KEY) { - if (save) - continue; - - if (op == PARSER_OP_VERIFY) { - k = new_key(head, dirfd, - digest_lists[i]->d_name, NULL, - false); - if (!k) { - ret = -ENOMEM; - goto out; - } - - continue; - } - - ret = key_upload(dirfd, digest_lists[i]->d_name); - if (ret < 0) { - printf("Unable to add key from %s\n", - digest_lists[i]->d_name); - } - - continue; - } - - switch (op) { - case PARSER_OP_VERIFY: - ret = verify_file(head, dirfd, digest_lists[i]->d_name); - break; - case PARSER_OP_GEN_IMA_LIST: - ret = ima_generate_entry(dirfd, fd, digest_lists_dir, - digest_lists[i]->d_name); - break; - case PARSER_OP_REPAIR_META_DIGEST_LISTS: - snprintf(path, sizeof(path), "%s/%s", digest_lists_dir, - digest_lists[i]->d_name); - snprintf(path_sig, sizeof(path_sig), "%s.sig/%s.sig", - digest_lists_dir, digest_lists[i]->d_name); - - ret = read_file_from_path(-1, path_sig, &sig, &sig_len); - if (ret < 0) - break; - - ret = lsetxattr(path, XATTR_NAME_EVM, sig, sig_len, 0); - - munmap(sig, sig_len); - - if (ret < 0) { - printf("Cannot set EVM xattr to %s\n", path); - break; - } - - ret = lsetfilecon(path, DIGEST_LIST_LABEL); - if (ret < 0) { - printf("Cannot set SELinux label %s to %s\n", - DIGEST_LIST_LABEL, path); - break; - } - - ret = chmod(path, DIGEST_LIST_MODE); - if (ret < 0) { - printf("Cannot set mode %d to %s\n", - DIGEST_LIST_MODE, path); - break; - } - - ret = calc_file_digest(digest, -1, path, - DIGEST_LIST_ALGO); - if (ret < 0) { - printf("Cannot calculate digest of %s\n", path); - break; - } - - ret = gen_write_ima_xattr(xattr, &xattr_len, path, - DIGEST_LIST_ALGO, digest, - true, true); - if (ret < 0) - printf("Cannot set IMA xattr to %s\n", path); - - break; - default: - ret = digest_list_upload(dirfd, fd, head, - &parser_lib_head, - digest_lists[i]->d_name, op, - digest_lists_dir); - break; - } - - if (ret) - printf("Failed to process %s\n", - digest_lists[i]->d_name); - } + struct dirent **digest_lists; + LIST_HEAD(parser_lib_head); + struct key_struct *k; + char path[PATH_MAX], path_sig[PATH_MAX]; + u8 digest[SHA512_DIGEST_SIZE]; + u8 xattr[2 + SHA512_DIGEST_SIZE]; + void *sig; + loff_t sig_len; + int ret, i, n, xattr_len; + + n = scandirat(dirfd, ".", &digest_lists, filter[type], compare_lists); + if (n == -1) { + printf("Unable to access digest lists\n"); + return -EACCES; + } + + for (i = 0; i < n; i++) { + if (filename && strcmp(digest_lists[i]->d_name, filename)) + continue; + + if (verbose) + printf("Processing: %s\n", digest_lists[i]->d_name); + + if (type == COMPACT_KEY) { + if (save) + continue; + + if (op == PARSER_OP_VERIFY) { + k = new_key(head, dirfd, + digest_lists[i]->d_name, NULL, + false); + if (!k) { + ret = -ENOMEM; + goto out; + } + + continue; + } + + ret = key_upload(dirfd, digest_lists[i]->d_name); + if (ret < 0) { + printf("Unable to add key from %s\n", + digest_lists[i]->d_name); + } + + continue; + } + + switch (op) { + case PARSER_OP_VERIFY: + ret = verify_file(head, dirfd, digest_lists[i]->d_name); + break; + case PARSER_OP_GEN_IMA_LIST: + ret = ima_generate_entry(dirfd, fd, digest_lists_dir, + digest_lists[i]->d_name); + break; + case PARSER_OP_REPAIR_META_DIGEST_LISTS: + snprintf(path, sizeof(path), "%s/%s", digest_lists_dir, + digest_lists[i]->d_name); + snprintf(path_sig, sizeof(path_sig), "%s.sig/%s.sig", + digest_lists_dir, digest_lists[i]->d_name); + + ret = read_file_from_path(-1, path_sig, &sig, &sig_len); + if (ret < 0) + break; + + ret = lsetxattr(path, XATTR_NAME_EVM, sig, sig_len, 0); + + munmap(sig, sig_len); + + if (ret < 0) { + printf("Cannot set EVM xattr to %s\n", path); + break; + } + + ret = lsetfilecon(path, DIGEST_LIST_LABEL); + if (ret < 0) { + printf("Cannot set SELinux label %s to %s\n", + DIGEST_LIST_LABEL, path); + break; + } + + ret = chmod(path, DIGEST_LIST_MODE); + if (ret < 0) { + printf("Cannot set mode %d to %s\n", + DIGEST_LIST_MODE, path); + break; + } + + ret = calc_file_digest(digest, -1, path, + DIGEST_LIST_ALGO); + if (ret < 0) { + printf("Cannot calculate digest of %s\n", path); + break; + } + + ret = gen_write_ima_xattr(xattr, &xattr_len, path, + DIGEST_LIST_ALGO, digest, + true, true); + if (ret < 0) + printf("Cannot set IMA xattr to %s\n", path); + + break; + default: + ret = digest_list_upload(dirfd, fd, head, + &parser_lib_head, + digest_lists[i]->d_name, op, + digest_lists_dir); + break; + } + + if (ret) + printf("Failed to process %s\n", + digest_lists[i]->d_name); + } out: - free_libs(&parser_lib_head); - for (i = 0; i < n; i++) - free(digest_lists[i]); + free_libs(&parser_lib_head); + for (i = 0; i < n; i++) + free(digest_lists[i]); - free(digest_lists); - return 0; + free(digest_lists); + return 0; } diff --git a/lib/crypto.c b/lib/crypto.c index c3b72ae..ac787ee 100644 --- a/lib/crypto.c +++ b/lib/crypto.c @@ -25,373 +25,373 @@ int calc_digest(u8 *digest, void *data, u64 len, enum hash_algo algo) { - EVP_MD_CTX *mdctx; - const EVP_MD *md; - int ret = -EINVAL; + EVP_MD_CTX *mdctx; + const EVP_MD *md; + int ret = -EINVAL; - OpenSSL_add_all_algorithms(); + OpenSSL_add_all_algorithms(); - md = EVP_get_digestbyname(hash_algo_name[algo]); - if (!md) - goto out; + md = EVP_get_digestbyname(hash_algo_name[algo]); + if (!md) + goto out; - mdctx = EVP_MD_CTX_create(); - if (!mdctx) - goto out; + mdctx = EVP_MD_CTX_create(); + if (!mdctx) + goto out; - if (EVP_DigestInit_ex(mdctx, md, NULL) != 1) - goto out_mdctx; + if (EVP_DigestInit_ex(mdctx, md, NULL) != 1) + goto out_mdctx; - if (EVP_DigestUpdate(mdctx, data, len) != 1) - goto out_mdctx; + if (EVP_DigestUpdate(mdctx, data, len) != 1) + goto out_mdctx; - if (EVP_DigestFinal_ex(mdctx, digest, NULL) != 1) - goto out_mdctx; + if (EVP_DigestFinal_ex(mdctx, digest, NULL) != 1) + goto out_mdctx; - ret = 0; + ret = 0; out_mdctx: - EVP_MD_CTX_destroy(mdctx); + EVP_MD_CTX_destroy(mdctx); out: - EVP_cleanup(); - return ret; + EVP_cleanup(); + return ret; } int calc_file_digest(u8 *digest, int dirfd, char *path, enum hash_algo algo) { - void *data = MAP_FAILED; - struct stat st; - int fd, ret = 0; - - if (dirfd >= 0) { - if (fstatat(dirfd, path, &st, 0) == -1) - return -EACCES; - - fd = openat(dirfd, path, O_RDONLY); - } else { - if (stat(path, &st) == -1) - return -EACCES; - - fd = open(path, O_RDONLY); - } - - if (fd < 0) - return -EACCES; - - if (st.st_size) { - data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); - if (data == MAP_FAILED) { - ret = -ENOMEM; - goto out; - } - } - - ret = calc_digest(digest, data, st.st_size, algo); + void *data = MAP_FAILED; + struct stat st; + int fd, ret = 0; + + if (dirfd >= 0) { + if (fstatat(dirfd, path, &st, 0) == -1) + return -EACCES; + + fd = openat(dirfd, path, O_RDONLY); + } else { + if (stat(path, &st) == -1) + return -EACCES; + + fd = open(path, O_RDONLY); + } + + if (fd < 0) + return -EACCES; + + if (st.st_size) { + data = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (data == MAP_FAILED) { + ret = -ENOMEM; + goto out; + } + } + + ret = calc_digest(digest, data, st.st_size, algo); out: - if (data != MAP_FAILED) - munmap(data, st.st_size); + if (data != MAP_FAILED) + munmap(data, st.st_size); - close(fd); - return ret; + close(fd); + return ret; } struct RSA_ASN1_template { - const uint8_t *data; - size_t size; + const uint8_t *data; + size_t size; }; /* * Hash algorithm OIDs plus ASN.1 DER wrappings [RFC4880 sec 5.2.2]. */ static const uint8_t RSA_digest_info_SHA1[] = { - 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, - 0x2B, 0x0E, 0x03, 0x02, 0x1A, - 0x05, 0x00, 0x04, 0x14 + 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, + 0x2B, 0x0E, 0x03, 0x02, 0x1A, + 0x05, 0x00, 0x04, 0x14 }; static const uint8_t RSA_digest_info_SHA256[] = { - 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, - 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, - 0x05, 0x00, 0x04, 0x20 + 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, + 0x05, 0x00, 0x04, 0x20 }; static const uint8_t RSA_digest_info_SHA512[] = { - 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, - 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, - 0x05, 0x00, 0x04, 0x40 + 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, + 0x05, 0x00, 0x04, 0x40 }; const struct RSA_ASN1_template RSA_ASN1_templates[HASH_ALGO__LAST] = { #define _(X) { RSA_digest_info_##X, sizeof(RSA_digest_info_##X) } - [HASH_ALGO_SHA1] = _(SHA1), - [HASH_ALGO_SHA256] = _(SHA256), - [HASH_ALGO_SHA512] = _(SHA512), + [HASH_ALGO_SHA1] = _(SHA1), + [HASH_ALGO_SHA256] = _(SHA256), + [HASH_ALGO_SHA512] = _(SHA512), #undef _ }; static void free_key(struct key_struct *k) { - RSA_free(k->key); - free(k); + RSA_free(k->key); + free(k); } void free_keys(struct list_head *head) { - struct key_struct *cur, *tmp; + struct key_struct *cur, *tmp; - list_for_each_entry_safe(cur, tmp, head, list) { - list_del(&cur->list); - free_key(cur); - } + list_for_each_entry_safe(cur, tmp, head, list) { + list_del(&cur->list); + free_key(cur); + } } struct key_struct *new_key(struct list_head *head, int dirfd, char *key_path, - char *keypass, bool private) + char *keypass, bool private) { - u8 digest[SHA512_DIGEST_SIZE], *pkey = NULL; - struct key_struct *new = NULL; - EVP_PKEY *public_key = NULL; - X509 *crt = NULL; - FILE *fp; - int ret = -EINVAL, fd, pkey_len; - - OpenSSL_add_all_algorithms(); - - if (dirfd != -1) - fd = openat(dirfd, key_path, O_RDONLY); - else - fd = open(key_path, O_RDONLY); - - if (fd < 0) - goto out; - - fp = fdopen(fd, "r"); - if (!fp) { - ret = -EACCES; - close(fd); - goto out; - } - - new = calloc(1, sizeof(*new)); - if (!new) { - ret = -ENOMEM; - goto out_fp; - } - - if (private) - new->key = PEM_read_RSAPrivateKey(fp, NULL, NULL, - (void *)keypass); - else { - crt = d2i_X509_fp(fp, NULL); - if (!crt) { - printf("d2i_X509_fp() failed\n"); - goto out_fp; - } - public_key = X509_extract_key(crt); - if (!public_key) { - printf("X509_extract_key() failed\n"); - goto out_fp; - } - new->key = EVP_PKEY_get1_RSA(public_key); - } - - if (!new->key) { - ret = -ENOENT; - goto out_key; - } - - pkey_len = i2d_RSAPublicKey(new->key, &pkey); - if (pkey_len < 0) { - printf("Cannot extract public key\n"); - goto out_key; - } - - ret = calc_digest(digest, pkey, pkey_len, HASH_ALGO_SHA1); - - memcpy(new->keyid, digest + 16, 4); - list_add_tail(&new->list, head); - free(pkey); + u8 digest[SHA512_DIGEST_SIZE], *pkey = NULL; + struct key_struct *new = NULL; + EVP_PKEY *public_key = NULL; + X509 *crt = NULL; + FILE *fp; + int ret = -EINVAL, fd, pkey_len; + + OpenSSL_add_all_algorithms(); + + if (dirfd != -1) + fd = openat(dirfd, key_path, O_RDONLY); + else + fd = open(key_path, O_RDONLY); + + if (fd < 0) + goto out; + + fp = fdopen(fd, "r"); + if (!fp) { + ret = -EACCES; + close(fd); + goto out; + } + + new = calloc(1, sizeof(*new)); + if (!new) { + ret = -ENOMEM; + goto out_fp; + } + + if (private) + new->key = PEM_read_RSAPrivateKey(fp, NULL, NULL, + (void *)keypass); + else { + crt = d2i_X509_fp(fp, NULL); + if (!crt) { + printf("d2i_X509_fp() failed\n"); + goto out_fp; + } + public_key = X509_extract_key(crt); + if (!public_key) { + printf("X509_extract_key() failed\n"); + goto out_fp; + } + new->key = EVP_PKEY_get1_RSA(public_key); + } + + if (!new->key) { + ret = -ENOENT; + goto out_key; + } + + pkey_len = i2d_RSAPublicKey(new->key, &pkey); + if (pkey_len < 0) { + printf("Cannot extract public key\n"); + goto out_key; + } + + ret = calc_digest(digest, pkey, pkey_len, HASH_ALGO_SHA1); + + memcpy(new->keyid, digest + 16, 4); + list_add_tail(&new->list, head); + free(pkey); out_key: - if (ret < 0) { - free_key(new); - new = NULL; - } + if (ret < 0) { + free_key(new); + new = NULL; + } out_fp: - if (public_key) - EVP_PKEY_free(public_key); - if (crt) - X509_free(crt); - fclose(fp); + if (public_key) + EVP_PKEY_free(public_key); + if (crt) + X509_free(crt); + fclose(fp); out: - EVP_cleanup(); - return new; + EVP_cleanup(); + return new; } struct key_struct *lookup_key(struct list_head *head, int dirfd, char *key_path, - u8 *keyid) + u8 *keyid) { - struct key_struct *cur = NULL; + struct key_struct *cur = NULL; - list_for_each_entry(cur, head, list) - if (!memcmp(cur->keyid, keyid, sizeof(cur->keyid))) - return cur; + list_for_each_entry(cur, head, list) + if (!memcmp(cur->keyid, keyid, sizeof(cur->keyid))) + return cur; - if (key_path) - return cur; + if (key_path) + return cur; - return new_key(head, dirfd, key_path, NULL, false); + return new_key(head, dirfd, key_path, NULL, false); } static int sign_file(int dirfd, char *filename, char *key_path, char *keypass, - enum hash_algo algo) + enum hash_algo algo) { - u8 digest[SHA512_DIGEST_SIZE], sig[MAX_SIGNATURE_SIZE]; - const struct RSA_ASN1_template *asn1; - struct key_struct *k; - LIST_HEAD(key_head); - u8 *buf; - int ret = 0, digest_len, sig_len; - - k = new_key(&key_head, -1, key_path, keypass, true); - if (!k) - return -ENOENT; - - ret = calc_file_digest(digest, dirfd, filename, algo); - if (ret < 0) - goto out_key; - - digest_len = hash_digest_size[algo]; - - asn1 = &RSA_ASN1_templates[algo]; - if (!asn1) { - printf("Algorithm %s not supported\n", hash_algo_name[algo]); - goto out_key; - } - - buf = malloc(digest_len + asn1->size); - if (!buf) { - ret = -ENOMEM; - goto out_key; - } - - memcpy(buf, asn1->data, asn1->size); - memcpy(buf + asn1->size, digest, digest_len); - - sig_len = RSA_private_encrypt(digest_len + asn1->size, buf, sig, k->key, - RSA_PKCS1_PADDING); - if (sig_len < 0) { - printf("RSA_private_encrypt() failed: %d\n", sig_len); - goto out_buf; - } - - ret = write_ima_xattr(dirfd, filename, k->keyid, sizeof(k->keyid), - sig, sig_len, algo); + u8 digest[SHA512_DIGEST_SIZE], sig[MAX_SIGNATURE_SIZE]; + const struct RSA_ASN1_template *asn1; + struct key_struct *k; + LIST_HEAD(key_head); + u8 *buf; + int ret = 0, digest_len, sig_len; + + k = new_key(&key_head, -1, key_path, keypass, true); + if (!k) + return -ENOENT; + + ret = calc_file_digest(digest, dirfd, filename, algo); + if (ret < 0) + goto out_key; + + digest_len = hash_digest_size[algo]; + + asn1 = &RSA_ASN1_templates[algo]; + if (!asn1) { + printf("Algorithm %s not supported\n", hash_algo_name[algo]); + goto out_key; + } + + buf = malloc(digest_len + asn1->size); + if (!buf) { + ret = -ENOMEM; + goto out_key; + } + + memcpy(buf, asn1->data, asn1->size); + memcpy(buf + asn1->size, digest, digest_len); + + sig_len = RSA_private_encrypt(digest_len + asn1->size, buf, sig, k->key, + RSA_PKCS1_PADDING); + if (sig_len < 0) { + printf("RSA_private_encrypt() failed: %d\n", sig_len); + goto out_buf; + } + + ret = write_ima_xattr(dirfd, filename, k->keyid, sizeof(k->keyid), + sig, sig_len, algo); out_buf: - free(buf); + free(buf); out_key: - free_keys(&key_head); - return ret; + free_keys(&key_head); + return ret; } int sign_files(int dirfd, struct list_head *head, char *key_path, - char *keypass, enum hash_algo algo) + char *keypass, enum hash_algo algo) { - struct path_struct *cur; - int ret = 0; - - list_for_each_entry(cur, head, list) { - ret = sign_file(dirfd, cur->path, key_path, keypass, algo); - if (ret < 0) { - printf("Cannot sign %s\n", cur->path); - return ret; - } - } - - return ret; + struct path_struct *cur; + int ret = 0; + + list_for_each_entry(cur, head, list) { + ret = sign_file(dirfd, cur->path, key_path, keypass, algo); + if (ret < 0) { + printf("Cannot sign %s\n", cur->path); + return ret; + } + } + + return ret; } static int verify_common(struct list_head *head, int dirfd, char *filename, - u8 *sig_in, int sig_in_len, u8 *digest_in, - enum hash_algo algo_in) + u8 *sig_in, int sig_in_len, u8 *digest_in, + enum hash_algo algo_in) { - u8 *buf = NULL, *keyid, *sig; - u8 digest[SHA512_DIGEST_SIZE], out[MAX_SIGNATURE_SIZE]; - enum hash_algo algo; - struct key_struct *k; - const struct RSA_ASN1_template *asn1; - size_t buf_len, keyid_len, sig_len, len; - int ret; - - if (filename) { - ret = read_ima_xattr(dirfd, filename, &buf, &buf_len, &keyid, - &keyid_len, &sig, &sig_len, &algo); - if (ret < 0) { - printf("Cannot read security.ima xattr: %d\n", ret); - return ret; - } - - ret = calc_file_digest(digest, dirfd, filename, algo); - if (ret < 0) - goto out; - } else { - ret = parse_ima_xattr(sig_in, sig_in_len, &keyid, &keyid_len, - &sig, &sig_len, &algo); - if (ret) { - printf("Cannot parse security.ima xattr: %d\n", ret); - return ret; - } - - if (algo != algo_in) { - printf("Hash algorithm mismatch\n"); - return -EINVAL; - } - - memcpy(digest, digest_in, hash_digest_size[algo]); - } - - k = lookup_key(head, dirfd, NULL, keyid); - if (!k) { - printf("No key found for id %d\n", be32_to_cpu(keyid)); - ret = -ENOENT; - goto out; - } - - ret = RSA_public_decrypt(sig_len, sig, out, k->key, RSA_PKCS1_PADDING); - if (ret < 0) { - printf("RSA_public_decrypt() failed: %d\n", ret); - goto out; - } - - len = ret; - - asn1 = &RSA_ASN1_templates[algo]; - - if (len < asn1->size || memcmp(out, asn1->data, asn1->size)) { - printf("Verification failed: %d (asn1 mismatch)\n", ret); - goto out; - } - - len -= asn1->size; - - if (memcmp(out + asn1->size, digest, hash_digest_size[algo])) { - printf("Verification failed (digest mismatch)\n"); - ret = -EINVAL; - goto out; - } - - ret = 0; + u8 *buf = NULL, *keyid, *sig; + u8 digest[SHA512_DIGEST_SIZE], out[MAX_SIGNATURE_SIZE]; + enum hash_algo algo; + struct key_struct *k; + const struct RSA_ASN1_template *asn1; + size_t buf_len, keyid_len, sig_len, len; + int ret; + + if (filename) { + ret = read_ima_xattr(dirfd, filename, &buf, &buf_len, &keyid, + &keyid_len, &sig, &sig_len, &algo); + if (ret < 0) { + printf("Cannot read security.ima xattr: %d\n", ret); + return ret; + } + + ret = calc_file_digest(digest, dirfd, filename, algo); + if (ret < 0) + goto out; + } else { + ret = parse_ima_xattr(sig_in, sig_in_len, &keyid, &keyid_len, + &sig, &sig_len, &algo); + if (ret) { + printf("Cannot parse security.ima xattr: %d\n", ret); + return ret; + } + + if (algo != algo_in) { + printf("Hash algorithm mismatch\n"); + return -EINVAL; + } + + memcpy(digest, digest_in, hash_digest_size[algo]); + } + + k = lookup_key(head, dirfd, NULL, keyid); + if (!k) { + printf("No key found for id %d\n", be32_to_cpu(keyid)); + ret = -ENOENT; + goto out; + } + + ret = RSA_public_decrypt(sig_len, sig, out, k->key, RSA_PKCS1_PADDING); + if (ret < 0) { + printf("RSA_public_decrypt() failed: %d\n", ret); + goto out; + } + + len = ret; + + asn1 = &RSA_ASN1_templates[algo]; + + if (len < asn1->size || memcmp(out, asn1->data, asn1->size)) { + printf("Verification failed: %d (asn1 mismatch)\n", ret); + goto out; + } + + len -= asn1->size; + + if (memcmp(out + asn1->size, digest, hash_digest_size[algo])) { + printf("Verification failed (digest mismatch)\n"); + ret = -EINVAL; + goto out; + } + + ret = 0; out: - free(buf); - return ret; + free(buf); + return ret; } int verify_file(struct list_head *head, int dirfd, char *filename) { - return verify_common(head, dirfd, filename, NULL, 0, NULL, - HASH_ALGO__LAST); + return verify_common(head, dirfd, filename, NULL, 0, NULL, + HASH_ALGO__LAST); } int verify_sig(struct list_head *head, int dirfd, u8 *sig, int sig_len, - u8 *digest, enum hash_algo algo) + u8 *digest, enum hash_algo algo) { - return verify_common(head, dirfd, NULL, sig, sig_len, digest, algo); + return verify_common(head, dirfd, NULL, sig, sig_len, digest, algo); } diff --git a/lib/evm.c b/lib/evm.c index 359fc4f..f700a7e 100644 --- a/lib/evm.c +++ b/lib/evm.c @@ -31,30 +31,30 @@ * protection.) */ static int hmac_add_misc(EVP_MD_CTX *mdctx, uid_t uid, gid_t gid, mode_t mode, - u8 *digest) + u8 *digest) { - struct h_misc { - unsigned long ino; - u32 generation; - uid_t uid; - gid_t gid; - mode_t mode; - } hmac_misc; + struct h_misc { + unsigned long ino; + u32 generation; + uid_t uid; + gid_t gid; + mode_t mode; + } hmac_misc; - memset(&hmac_misc, 0, sizeof(hmac_misc)); + memset(&hmac_misc, 0, sizeof(hmac_misc)); - hmac_misc.uid = uid; - hmac_misc.gid = gid; - hmac_misc.mode = mode; + hmac_misc.uid = uid; + hmac_misc.gid = gid; + hmac_misc.mode = mode; - if (EVP_DigestUpdate(mdctx, (const u8 *)&hmac_misc, - sizeof(hmac_misc)) != 1) - return -EINVAL; + if (EVP_DigestUpdate(mdctx, (const u8 *)&hmac_misc, + sizeof(hmac_misc)) != 1) + return -EINVAL; - if (EVP_DigestFinal_ex(mdctx, digest, NULL) != 1) - return -EINVAL; + if (EVP_DigestFinal_ex(mdctx, digest, NULL) != 1) + return -EINVAL; - return 0; + return 0; } /* @@ -65,46 +65,46 @@ static int hmac_add_misc(EVP_MD_CTX *mdctx, uid_t uid, gid_t gid, mode_t mode, * each xattr, but attempt to re-use the previously allocated memory. */ int evm_calc_hmac_or_hash(enum hash_algo algo, u8 *digest, - int lsm_label_len, char *lsm_label, - int ima_digest_len, u8 *ima_digest, - int caps_bin_len, u8 *caps_bin, - uid_t uid, gid_t gid, mode_t mode) + int lsm_label_len, char *lsm_label, + int ima_digest_len, u8 *ima_digest, + int caps_bin_len, u8 *caps_bin, + uid_t uid, gid_t gid, mode_t mode) { - EVP_MD_CTX *mdctx; - const EVP_MD *md; - int ret = -EINVAL; + EVP_MD_CTX *mdctx; + const EVP_MD *md; + int ret = -EINVAL; - OpenSSL_add_all_algorithms(); + OpenSSL_add_all_algorithms(); - md = EVP_get_digestbyname(hash_algo_name[algo]); - if (!md) - goto out; + md = EVP_get_digestbyname(hash_algo_name[algo]); + if (!md) + goto out; - mdctx = EVP_MD_CTX_create(); - if (!mdctx) - goto out; + mdctx = EVP_MD_CTX_create(); + if (!mdctx) + goto out; - if (EVP_DigestInit_ex(mdctx, md, NULL) != 1) - goto out_mdctx; + if (EVP_DigestInit_ex(mdctx, md, NULL) != 1) + goto out_mdctx; - if (lsm_label && - EVP_DigestUpdate(mdctx, (const u8 *)lsm_label, lsm_label_len) != 1) - goto out_mdctx; + if (lsm_label && + EVP_DigestUpdate(mdctx, (const u8 *)lsm_label, lsm_label_len) != 1) + goto out_mdctx; - if (EVP_DigestUpdate(mdctx, (const u8 *)ima_digest, - ima_digest_len) != 1) - goto out_mdctx; + if (EVP_DigestUpdate(mdctx, (const u8 *)ima_digest, + ima_digest_len) != 1) + goto out_mdctx; - if (EVP_DigestUpdate(mdctx, caps_bin, caps_bin_len) != 1) - goto out_mdctx; + if (EVP_DigestUpdate(mdctx, caps_bin, caps_bin_len) != 1) + goto out_mdctx; - if (hmac_add_misc(mdctx, uid, gid, mode, digest) < 0) - goto out_mdctx; + if (hmac_add_misc(mdctx, uid, gid, mode, digest) < 0) + goto out_mdctx; - ret = 0; + ret = 0; out_mdctx: - EVP_MD_CTX_destroy(mdctx); + EVP_MD_CTX_destroy(mdctx); out: - EVP_cleanup(); - return ret; + EVP_cleanup(); + return ret; } diff --git a/lib/ima_list.c b/lib/ima_list.c index 2faf7fa..cd92d4e 100644 --- a/lib/ima_list.c +++ b/lib/ima_list.c @@ -26,155 +26,155 @@ #define BUFLEN 1024 struct template_entry { - struct { - uint32_t pcr; - uint8_t digest[SHA_DIGEST_LENGTH]; - uint32_t name_len; - } header __attribute__((packed)); - char name[TCG_EVENT_NAME_LEN_MAX + 1]; - int template_len; - uint8_t *template; - int template_buf_len; + struct { + uint32_t pcr; + uint8_t digest[SHA_DIGEST_LENGTH]; + uint32_t name_len; + } header __attribute__((packed)); + char name[TCG_EVENT_NAME_LEN_MAX + 1]; + int template_len; + uint8_t *template; + int template_buf_len; }; int ima_copy_boot_aggregate(int fd) { - u8 buf[BUFLEN]; - size_t len; - int ret = 0, fd_ima; - - fd_ima = open(IMA_PATH, O_RDONLY); - if (fd_ima < 0) - return -EACCES; - - while ((len = read(fd_ima, buf, BUFLEN))) { - ret = write_check(fd, buf, len); - if (ret < 0) - goto out; - } + u8 buf[BUFLEN]; + size_t len; + int ret = 0, fd_ima; + + fd_ima = open(IMA_PATH, O_RDONLY); + if (fd_ima < 0) + return -EACCES; + + while ((len = read(fd_ima, buf, BUFLEN))) { + ret = write_check(fd, buf, len); + if (ret < 0) + goto out; + } out: - close(fd_ima); - return ret; + close(fd_ima); + return ret; } int ima_generate_entry(int dirfd, int fd, char *digest_list_dir, - char *digest_list_filename) + char *digest_list_filename) { - struct template_entry entry; - uint32_t *field_len, current_offset, offset = 0; - size_t keyid_len, sig_len, algo_name_len, xattr_len; - enum hash_algo algo; - u8 *xattr, *keyid, *sig; - int ret; + struct template_entry entry; + uint32_t *field_len, current_offset, offset = 0; + size_t keyid_len, sig_len, algo_name_len, xattr_len; + enum hash_algo algo; + u8 *xattr, *keyid, *sig; + int ret; - entry.header.pcr = DIGEST_LIST_PCR; - entry.header.name_len = sizeof(IMA_SIG_TEMPLATE) - 1; + entry.header.pcr = DIGEST_LIST_PCR; + entry.header.name_len = sizeof(IMA_SIG_TEMPLATE) - 1; - memcpy(entry.name, IMA_SIG_TEMPLATE, sizeof(IMA_SIG_TEMPLATE) - 1); + memcpy(entry.name, IMA_SIG_TEMPLATE, sizeof(IMA_SIG_TEMPLATE) - 1); - entry.template_buf_len = - /* d-ng template field */ - CRYPTO_MAX_ALG_NAME + 2 + SHA512_DIGEST_SIZE + - /* n-ng template field */ - PATH_MAX + - /* sig template field */ - MAX_SIGNATURE_SIZE; + entry.template_buf_len = + /* d-ng template field */ + CRYPTO_MAX_ALG_NAME + 2 + SHA512_DIGEST_SIZE + + /* n-ng template field */ + PATH_MAX + + /* sig template field */ + MAX_SIGNATURE_SIZE; - entry.template = malloc(entry.template_buf_len); - if (!entry.template) - return -ENOMEM; + entry.template = malloc(entry.template_buf_len); + if (!entry.template) + return -ENOMEM; - /* d-ng template field */ - field_len = (uint32_t *)(entry.template + offset); + /* d-ng template field */ + field_len = (uint32_t *)(entry.template + offset); - offset += sizeof(*field_len); - current_offset = offset; + offset += sizeof(*field_len); + current_offset = offset; - algo_name_len = strlen(hash_algo_name[IMA_DIGEST_ALGO]); - memcpy(entry.template + offset, hash_algo_name[IMA_DIGEST_ALGO], - algo_name_len); - offset += algo_name_len; + algo_name_len = strlen(hash_algo_name[IMA_DIGEST_ALGO]); + memcpy(entry.template + offset, hash_algo_name[IMA_DIGEST_ALGO], + algo_name_len); + offset += algo_name_len; - entry.template[offset++] = ':'; - entry.template[offset++] = '\0'; + entry.template[offset++] = ':'; + entry.template[offset++] = '\0'; - ret = calc_file_digest(entry.template + offset, dirfd, - digest_list_filename, IMA_DIGEST_ALGO); - if (ret < 0) - goto out; + ret = calc_file_digest(entry.template + offset, dirfd, + digest_list_filename, IMA_DIGEST_ALGO); + if (ret < 0) + goto out; - offset += hash_digest_size[IMA_DIGEST_ALGO]; - *field_len = (offset - current_offset); + offset += hash_digest_size[IMA_DIGEST_ALGO]; + *field_len = (offset - current_offset); - if (ima_canonical_fmt) - *field_len = cpu_to_le32(*field_len); + if (ima_canonical_fmt) + *field_len = cpu_to_le32(*field_len); - /* n-ng template field */ - field_len = (uint32_t *)(entry.template + offset); - offset += sizeof(*field_len); + /* n-ng template field */ + field_len = (uint32_t *)(entry.template + offset); + offset += sizeof(*field_len); - current_offset = offset; + current_offset = offset; - if (digest_list_filename[0] == '/') - digest_list_filename++; + if (digest_list_filename[0] == '/') + digest_list_filename++; - offset += snprintf((char *)entry.template + offset, - entry.template_buf_len - offset, "%s/%s", - digest_list_dir, digest_list_filename); - offset++; + offset += snprintf((char *)entry.template + offset, + entry.template_buf_len - offset, "%s/%s", + digest_list_dir, digest_list_filename); + offset++; - *field_len = (offset - current_offset); + *field_len = (offset - current_offset); - if (ima_canonical_fmt) - *field_len = cpu_to_le32(*field_len); + if (ima_canonical_fmt) + *field_len = cpu_to_le32(*field_len); - /* sig template field */ - field_len = (uint32_t *)(entry.template + offset); - offset += sizeof(*field_len); + /* sig template field */ + field_len = (uint32_t *)(entry.template + offset); + offset += sizeof(*field_len); - xattr = NULL; + xattr = NULL; - ret = read_ima_xattr(-1, (char *)entry.template + current_offset, - &xattr, &xattr_len, &keyid, &keyid_len, &sig, - &sig_len, &algo); - if (ret < 0 && (ret == -EINVAL || ret == -ENODATA)) - xattr_len = 0; - else if (ret < 0) - goto out; + ret = read_ima_xattr(-1, (char *)entry.template + current_offset, + &xattr, &xattr_len, &keyid, &keyid_len, &sig, + &sig_len, &algo); + if (ret < 0 && (ret == -EINVAL || ret == -ENODATA)) + xattr_len = 0; + else if (ret < 0) + goto out; - current_offset = offset; - memcpy(entry.template + offset, xattr, xattr_len); - offset += xattr_len; + current_offset = offset; + memcpy(entry.template + offset, xattr, xattr_len); + offset += xattr_len; - *field_len = (offset - current_offset); + *field_len = (offset - current_offset); - if (ima_canonical_fmt) - *field_len = cpu_to_le32(*field_len); + if (ima_canonical_fmt) + *field_len = cpu_to_le32(*field_len); - current_offset = offset; + current_offset = offset; - ret = calc_digest(entry.header.digest, entry.template, current_offset, - HASH_ALGO_SHA1); - if (ret < 0) - goto out; + ret = calc_digest(entry.header.digest, entry.template, current_offset, + HASH_ALGO_SHA1); + if (ret < 0) + goto out; - ret = write_check(fd, &entry.header, sizeof(entry.header)); - if (ret < 0) - goto out; + ret = write_check(fd, &entry.header, sizeof(entry.header)); + if (ret < 0) + goto out; - ret = write_check(fd, IMA_SIG_TEMPLATE, sizeof(IMA_SIG_TEMPLATE) - 1); - if (ret < 0) - goto out; + ret = write_check(fd, IMA_SIG_TEMPLATE, sizeof(IMA_SIG_TEMPLATE) - 1); + if (ret < 0) + goto out; - if (ima_canonical_fmt) - current_offset = cpu_to_le32(current_offset); + if (ima_canonical_fmt) + current_offset = cpu_to_le32(current_offset); - ret = write_check(fd, ¤t_offset, sizeof(current_offset)); - if (ret < 0) - goto out; + ret = write_check(fd, ¤t_offset, sizeof(current_offset)); + if (ret < 0) + goto out; - ret = write_check(fd, entry.template, offset); + ret = write_check(fd, entry.template, offset); out: - free(entry.template); - return ret; + free(entry.template); + return ret; } diff --git a/lib/kernel_lib.c b/lib/kernel_lib.c index 2f0caff..675f09e 100644 --- a/lib/kernel_lib.c +++ b/lib/kernel_lib.c @@ -21,45 +21,45 @@ /* from crypto/hash_info.c */ const char *const hash_algo_name[HASH_ALGO__LAST] = { - [HASH_ALGO_MD4] = "md4", - [HASH_ALGO_MD5] = "md5", - [HASH_ALGO_SHA1] = "sha1", - [HASH_ALGO_RIPE_MD_160] = "rmd160", - [HASH_ALGO_SHA256] = "sha256", - [HASH_ALGO_SHA384] = "sha384", - [HASH_ALGO_SHA512] = "sha512", - [HASH_ALGO_SHA224] = "sha224", - [HASH_ALGO_RIPE_MD_128] = "rmd128", - [HASH_ALGO_RIPE_MD_256] = "rmd256", - [HASH_ALGO_RIPE_MD_320] = "rmd320", - [HASH_ALGO_WP_256] = "wp256", - [HASH_ALGO_WP_384] = "wp384", - [HASH_ALGO_WP_512] = "wp512", - [HASH_ALGO_TGR_128] = "tgr128", - [HASH_ALGO_TGR_160] = "tgr160", - [HASH_ALGO_TGR_192] = "tgr192", - [HASH_ALGO_SM3_256] = "sm3-256", + [HASH_ALGO_MD4] = "md4", + [HASH_ALGO_MD5] = "md5", + [HASH_ALGO_SHA1] = "sha1", + [HASH_ALGO_RIPE_MD_160] = "rmd160", + [HASH_ALGO_SHA256] = "sha256", + [HASH_ALGO_SHA384] = "sha384", + [HASH_ALGO_SHA512] = "sha512", + [HASH_ALGO_SHA224] = "sha224", + [HASH_ALGO_RIPE_MD_128] = "rmd128", + [HASH_ALGO_RIPE_MD_256] = "rmd256", + [HASH_ALGO_RIPE_MD_320] = "rmd320", + [HASH_ALGO_WP_256] = "wp256", + [HASH_ALGO_WP_384] = "wp384", + [HASH_ALGO_WP_512] = "wp512", + [HASH_ALGO_TGR_128] = "tgr128", + [HASH_ALGO_TGR_160] = "tgr160", + [HASH_ALGO_TGR_192] = "tgr192", + [HASH_ALGO_SM3_256] = "sm3-256", }; const int hash_digest_size[HASH_ALGO__LAST] = { - [HASH_ALGO_MD4] = MD5_DIGEST_SIZE, - [HASH_ALGO_MD5] = MD5_DIGEST_SIZE, - [HASH_ALGO_SHA1] = SHA1_DIGEST_SIZE, - [HASH_ALGO_RIPE_MD_160] = RMD160_DIGEST_SIZE, - [HASH_ALGO_SHA256] = SHA256_DIGEST_SIZE, - [HASH_ALGO_SHA384] = SHA384_DIGEST_SIZE, - [HASH_ALGO_SHA512] = SHA512_DIGEST_SIZE, - [HASH_ALGO_SHA224] = SHA224_DIGEST_SIZE, - [HASH_ALGO_RIPE_MD_128] = RMD128_DIGEST_SIZE, - [HASH_ALGO_RIPE_MD_256] = RMD256_DIGEST_SIZE, - [HASH_ALGO_RIPE_MD_320] = RMD320_DIGEST_SIZE, - [HASH_ALGO_WP_256] = WP256_DIGEST_SIZE, - [HASH_ALGO_WP_384] = WP384_DIGEST_SIZE, - [HASH_ALGO_WP_512] = WP512_DIGEST_SIZE, - [HASH_ALGO_TGR_128] = TGR128_DIGEST_SIZE, - [HASH_ALGO_TGR_160] = TGR160_DIGEST_SIZE, - [HASH_ALGO_TGR_192] = TGR192_DIGEST_SIZE, - [HASH_ALGO_SM3_256] = SM3256_DIGEST_SIZE, + [HASH_ALGO_MD4] = MD5_DIGEST_SIZE, + [HASH_ALGO_MD5] = MD5_DIGEST_SIZE, + [HASH_ALGO_SHA1] = SHA1_DIGEST_SIZE, + [HASH_ALGO_RIPE_MD_160] = RMD160_DIGEST_SIZE, + [HASH_ALGO_SHA256] = SHA256_DIGEST_SIZE, + [HASH_ALGO_SHA384] = SHA384_DIGEST_SIZE, + [HASH_ALGO_SHA512] = SHA512_DIGEST_SIZE, + [HASH_ALGO_SHA224] = SHA224_DIGEST_SIZE, + [HASH_ALGO_RIPE_MD_128] = RMD128_DIGEST_SIZE, + [HASH_ALGO_RIPE_MD_256] = RMD256_DIGEST_SIZE, + [HASH_ALGO_RIPE_MD_320] = RMD320_DIGEST_SIZE, + [HASH_ALGO_WP_256] = WP256_DIGEST_SIZE, + [HASH_ALGO_WP_384] = WP384_DIGEST_SIZE, + [HASH_ALGO_WP_512] = WP512_DIGEST_SIZE, + [HASH_ALGO_TGR_128] = TGR128_DIGEST_SIZE, + [HASH_ALGO_TGR_160] = TGR160_DIGEST_SIZE, + [HASH_ALGO_TGR_192] = TGR192_DIGEST_SIZE, + [HASH_ALGO_SM3_256] = SM3256_DIGEST_SIZE, }; /* from lib/hexdump.c */ @@ -73,12 +73,12 @@ const int hash_digest_size[HASH_ALGO__LAST] = { */ int hex_to_bin(char ch) { - if ((ch >= '0') && (ch <= '9')) - return ch - '0'; - ch = tolower(ch); - if ((ch >= 'a') && (ch <= 'f')) - return ch - 'a' + 10; - return -1; + if ((ch >= '0') && (ch <= '9')) + return ch - '0'; + ch = tolower(ch); + if ((ch >= 'a') && (ch <= 'f')) + return ch - 'a' + 10; + return -1; } /** @@ -91,16 +91,16 @@ int hex_to_bin(char ch) */ int hex2bin(u8 *dst, const char *src, size_t count) { - while (count--) { - int hi = hex_to_bin(*src++); - int lo = hex_to_bin(*src++); + while (count--) { + int hi = hex_to_bin(*src++); + int lo = hex_to_bin(*src++); - if ((hi < 0) || (lo < 0)) - return -1; + if ((hi < 0) || (lo < 0)) + return -1; - *dst++ = (hi << 4) | lo; - } - return 0; + *dst++ = (hi << 4) | lo; + } + return 0; } #ifdef __BIG_ENDIAN__ @@ -112,12 +112,12 @@ bool ima_canonical_fmt = false; int default_func(u8 *digest, enum hash_algo algo, enum compact_types type, u16 modifiers) { - return 0; + return 0; } struct ima_h_table ima_digests_htable = { - .len = 0, - .queue[0 ... IMA_MEASURE_HTABLE_SIZE - 1] = HLIST_HEAD_INIT + .len = 0, + .queue[0 ... IMA_MEASURE_HTABLE_SIZE - 1] = HLIST_HEAD_INIT }; /********************* @@ -125,116 +125,116 @@ struct ima_h_table ima_digests_htable = { *********************/ struct ima_digest *ima_lookup_digest(u8 *digest, enum hash_algo algo) { - struct ima_digest *d = NULL; - int digest_len = hash_digest_size[algo]; - unsigned int key = ima_hash_key(digest); + struct ima_digest *d = NULL; + int digest_len = hash_digest_size[algo]; + unsigned int key = ima_hash_key(digest); - rcu_read_lock(); - hlist_for_each_entry_rcu(d, &ima_digests_htable.queue[key], hnext) - if (d->algo == algo && !memcmp(d->digest, digest, digest_len)) - break; + rcu_read_lock(); + hlist_for_each_entry_rcu(d, &ima_digests_htable.queue[key], hnext) + if (d->algo == algo && !memcmp(d->digest, digest, digest_len)) + break; - rcu_read_unlock(); - return d; + rcu_read_unlock(); + return d; } int ima_add_digest_data_entry_kernel(u8 *digest, enum hash_algo algo, - enum compact_types type, u16 modifiers) + enum compact_types type, u16 modifiers) { - struct ima_digest *d; - int digest_len = hash_digest_size[algo]; - unsigned int key = ima_hash_key(digest); - - d = ima_lookup_digest(digest, algo); - if (d) { - d->modifiers |= modifiers; - return -EEXIST; - } - - d = kmalloc(sizeof(*d) + digest_len, GFP_KERNEL); - if (d == NULL) - return -ENOMEM; - - d->algo = algo; - d->type = type; - d->modifiers = modifiers; - - memcpy(d->digest, digest, digest_len); - hlist_add_head_rcu(&d->hnext, &ima_digests_htable.queue[key]); - atomic_long_inc(&ima_digests_htable.len); - return 0; + struct ima_digest *d; + int digest_len = hash_digest_size[algo]; + unsigned int key = ima_hash_key(digest); + + d = ima_lookup_digest(digest, algo); + if (d) { + d->modifiers |= modifiers; + return -EEXIST; + } + + d = kmalloc(sizeof(*d) + digest_len, GFP_KERNEL); + if (d == NULL) + return -ENOMEM; + + d->algo = algo; + d->type = type; + d->modifiers = modifiers; + + memcpy(d->digest, digest, digest_len); + hlist_add_head_rcu(&d->hnext, &ima_digests_htable.queue[key]); + atomic_long_inc(&ima_digests_htable.len); + return 0; } /* from ima_digest_list.c */ int ima_parse_compact_list(loff_t size, void *buf, - add_digest_func ima_add_digest_data_entry, - enum hash_algo *algo) + add_digest_func ima_add_digest_data_entry, + enum hash_algo *algo) { - u8 *digest; - void *bufp = buf, *bufendp = buf + size; - struct compact_list_hdr hdr, *hdrp; - size_t digest_len; - int ret, i; - - while (bufp < bufendp) { - if (bufp + sizeof(hdr) > bufendp) { - pr_err("compact list, invalid data\n"); - return -EINVAL; - } - - hdrp = bufp; - memcpy(&hdr, hdrp, sizeof(hdr)); - - if (hdr.version != 1) { - pr_err("compact list, unsupported version\n"); - return -EINVAL; - } - - if (ima_canonical_fmt) { - hdr.type = le16_to_cpu(hdr.type); - hdr.modifiers = le16_to_cpu(hdr.modifiers); - hdr.algo = le16_to_cpu(hdr.algo); - hdr.count = le32_to_cpu(hdr.count); - hdr.datalen = le32_to_cpu(hdr.datalen); - } - - if (hdr.algo >= HASH_ALGO__LAST) - return -EINVAL; - - if (algo) - *algo = hdr.algo; - - digest_len = hash_digest_size[hdr.algo]; - - if (hdr.type >= COMPACT__LAST) { - pr_err("compact list, invalid type %d\n", hdr.type); - return -EINVAL; - } - - bufp += sizeof(hdr); - - for (i = 0; i < hdr.count; i++) { - if (bufp + digest_len > bufendp) { - pr_err("compact list, invalid data\n"); - return -EINVAL; - } - - digest = bufp; - bufp += digest_len; - - ret = ima_add_digest_data_entry(digest, hdr.algo, - hdr.type, - hdr.modifiers); - if (ret < 0 && ret != -EEXIST) - return ret; - } - - if (i != hdr.count || - bufp != (void *)hdrp + sizeof(hdr) + hdr.datalen) { - pr_err("compact list, invalid data\n"); - return -EINVAL; - } - } - - return bufp - buf; + u8 *digest; + void *bufp = buf, *bufendp = buf + size; + struct compact_list_hdr hdr, *hdrp; + size_t digest_len; + int ret, i; + + while (bufp < bufendp) { + if (bufp + sizeof(hdr) > bufendp) { + pr_err("compact list, invalid data\n"); + return -EINVAL; + } + + hdrp = bufp; + memcpy(&hdr, hdrp, sizeof(hdr)); + + if (hdr.version != 1) { + pr_err("compact list, unsupported version\n"); + return -EINVAL; + } + + if (ima_canonical_fmt) { + hdr.type = le16_to_cpu(hdr.type); + hdr.modifiers = le16_to_cpu(hdr.modifiers); + hdr.algo = le16_to_cpu(hdr.algo); + hdr.count = le32_to_cpu(hdr.count); + hdr.datalen = le32_to_cpu(hdr.datalen); + } + + if (hdr.algo >= HASH_ALGO__LAST) + return -EINVAL; + + if (algo) + *algo = hdr.algo; + + digest_len = hash_digest_size[hdr.algo]; + + if (hdr.type >= COMPACT__LAST) { + pr_err("compact list, invalid type %d\n", hdr.type); + return -EINVAL; + } + + bufp += sizeof(hdr); + + for (i = 0; i < hdr.count; i++) { + if (bufp + digest_len > bufendp) { + pr_err("compact list, invalid data\n"); + return -EINVAL; + } + + digest = bufp; + bufp += digest_len; + + ret = ima_add_digest_data_entry(digest, hdr.algo, + hdr.type, + hdr.modifiers); + if (ret < 0 && ret != -EEXIST) + return ret; + } + + if (i != hdr.count || + bufp != (void *)hdrp + sizeof(hdr) + hdr.datalen) { + pr_err("compact list, invalid data\n"); + return -EINVAL; + } + } + + return bufp - buf; } diff --git a/lib/lib.c b/lib/lib.c index 0cdecb1..e6294ca 100644 --- a/lib/lib.c +++ b/lib/lib.c @@ -28,307 +28,307 @@ #include "lib.h" static const char *file_attrs_str[ATTR__LAST] = { - [ATTR_PATH] = "path", - [ATTR_DIGESTALGO] = "digestalgo", - [ATTR_DIGESTALGOPGP] = "digestalgopgp", - [ATTR_DIGEST] = "digest", - [ATTR_MODE] = "mode", - [ATTR_UNAME] = "uname", - [ATTR_GNAME] = "gname", - [ATTR_CAPS] = "caps", + [ATTR_PATH] = "path", + [ATTR_DIGESTALGO] = "digestalgo", + [ATTR_DIGESTALGOPGP] = "digestalgopgp", + [ATTR_DIGEST] = "digest", + [ATTR_MODE] = "mode", + [ATTR_UNAME] = "uname", + [ATTR_GNAME] = "gname", + [ATTR_CAPS] = "caps", }; enum hash_algo pgp_algo_mapping[PGP_HASH__LAST] = { - [PGP_HASH_MD5] = HASH_ALGO_MD5, - [PGP_HASH_SHA1] = HASH_ALGO_SHA1, - [PGP_HASH_SHA224] = HASH_ALGO_SHA224, - [PGP_HASH_SHA256] = HASH_ALGO_SHA256, - [PGP_HASH_SHA384] = HASH_ALGO_SHA384, - [PGP_HASH_SHA512] = HASH_ALGO_SHA512, + [PGP_HASH_MD5] = HASH_ALGO_MD5, + [PGP_HASH_SHA1] = HASH_ALGO_SHA1, + [PGP_HASH_SHA224] = HASH_ALGO_SHA224, + [PGP_HASH_SHA256] = HASH_ALGO_SHA256, + [PGP_HASH_SHA384] = HASH_ALGO_SHA384, + [PGP_HASH_SHA512] = HASH_ALGO_SHA512, }; static int read_file_from_path_common(int dirfd, const char *path, void **buf, - loff_t *size, bool shared) + loff_t *size, bool shared) { - struct stat st; - int mmap_flags = MAP_PRIVATE; - int ret = 0, fd, open_flags = O_RDONLY; - - if (shared) { - open_flags = O_RDWR; - mmap_flags = MAP_SHARED; - } - - if (dirfd >= 0) { - if (fstatat(dirfd, path, &st, 0) == -1) - return -EACCES; - - fd = openat(dirfd, path, open_flags); - } else { - if (stat(path, &st) == -1) - return -EACCES; - - fd = open(path, open_flags); - } - - if (fd < 0) - return -EINVAL; - - *buf = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, mmap_flags, fd, - 0); - if (*buf == MAP_FAILED) { - ret = -ENOMEM; - goto out; - } - - *size = st.st_size; + struct stat st; + int mmap_flags = MAP_PRIVATE; + int ret = 0, fd, open_flags = O_RDONLY; + + if (shared) { + open_flags = O_RDWR; + mmap_flags = MAP_SHARED; + } + + if (dirfd >= 0) { + if (fstatat(dirfd, path, &st, 0) == -1) + return -EACCES; + + fd = openat(dirfd, path, open_flags); + } else { + if (stat(path, &st) == -1) + return -EACCES; + + fd = open(path, open_flags); + } + + if (fd < 0) + return -EINVAL; + + *buf = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, mmap_flags, fd, + 0); + if (*buf == MAP_FAILED) { + ret = -ENOMEM; + goto out; + } + + *size = st.st_size; out: - close(fd); - return ret; + close(fd); + return ret; } int read_file_from_path(int dirfd, const char *path, void **buf, loff_t *size) { - return read_file_from_path_common(dirfd, path, buf, size, false); + return read_file_from_path_common(dirfd, path, buf, size, false); } int read_write_file_from_path(int dirfd, const char *path, void **buf, - loff_t *size) + loff_t *size) { - return read_file_from_path_common(dirfd, path, buf, size, true); + return read_file_from_path_common(dirfd, path, buf, size, true); } ssize_t write_check(int fd, const void *buf, size_t count) { - ssize_t ret; - - while (count > 0) { - ret = write(fd, buf, count); - if (ret == -1) { - printf("write() error (%s)\n", strerror(errno)); - return -EIO; - } else if (!ret) { - printf("write() incomplete, remaining: %zu bytes\n", - count); - return -EIO; - } - - buf += ret; - count -= ret; - } - - return 0; + ssize_t ret; + + while (count > 0) { + ret = write(fd, buf, count); + if (ret == -1) { + printf("write() error (%s)\n", strerror(errno)); + return -EIO; + } else if (!ret) { + printf("write() incomplete, remaining: %zu bytes\n", + count); + return -EIO; + } + + buf += ret; + count -= ret; + } + + return 0; } int copy_file(char *src, char *dest) { - void *data; - loff_t size; - int ret, fd; + void *data; + loff_t size; + int ret, fd; - ret = read_file_from_path(-1, src, &data, &size); - if (ret < 0) - return ret; + ret = read_file_from_path(-1, src, &data, &size); + if (ret < 0) + return ret; - fd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0644); - if (fd < 0) - goto out; + fd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd < 0) + goto out; - ret = write_check(fd, data, size); - close(fd); + ret = write_check(fd, data, size); + close(fd); out: - munmap(data, size); - return ret; + munmap(data, size); + return ret; } struct lib *lookup_lib(struct list_head *head, const char *lib_type, - const char *format, int format_len) + const char *format, int format_len) { - struct lib *tmp, *new; - char lib_path[PATH_MAX + 1]; - char function[NAME_MAX + 1]; - const char *format_end_ptr, *func_name_ptr; - void *handle; - int ret, lib_path_len; - - format_end_ptr = format + format_len; - func_name_ptr = memchr(format, '+', format_len); - if (func_name_ptr) { - snprintf(function, sizeof(function), "%.*s_%s", - (int)(format_end_ptr - func_name_ptr - 1), - func_name_ptr + 1, lib_type); - format_len = func_name_ptr - format; - } else { - snprintf(function, sizeof(function), "%s", lib_type); - } - - if (!list_empty(head)) { - list_for_each_entry(tmp, head, list) - if (!strncmp(tmp->format, format, format_len)) - return tmp; - } - - new = calloc(1, sizeof(*new)); - if (!new) - return new; - - new->format = malloc(format_len + 1); - if (!new->format) - goto err_free; - - strncpy(new->format, format, format_len); - new->format[format_len] = '\0'; + struct lib *tmp, *new; + char lib_path[PATH_MAX + 1]; + char function[NAME_MAX + 1]; + const char *format_end_ptr, *func_name_ptr; + void *handle; + int ret, lib_path_len; + + format_end_ptr = format + format_len; + func_name_ptr = memchr(format, '+', format_len); + if (func_name_ptr) { + snprintf(function, sizeof(function), "%.*s_%s", + (int)(format_end_ptr - func_name_ptr - 1), + func_name_ptr + 1, lib_type); + format_len = func_name_ptr - format; + } else { + snprintf(function, sizeof(function), "%s", lib_type); + } + + if (!list_empty(head)) { + list_for_each_entry(tmp, head, list) + if (!strncmp(tmp->format, format, format_len)) + return tmp; + } + + new = calloc(1, sizeof(*new)); + if (!new) + return new; + + new->format = malloc(format_len + 1); + if (!new->format) + goto err_free; + + strncpy(new->format, format, format_len); + new->format[format_len] = '\0'; #ifdef UNIT_TESTING - handle = dlopen("libdigestlist-base-test.so", RTLD_LAZY); + handle = dlopen("libdigestlist-base-test.so", RTLD_LAZY); #else - handle = dlopen("libdigestlist-base.so", RTLD_LAZY); + handle = dlopen("libdigestlist-base.so", RTLD_LAZY); #endif - if (!handle) - goto err_free; + if (!handle) + goto err_free; - ret = dlinfo(handle, RTLD_DI_ORIGIN, lib_path); - dlclose(handle); + ret = dlinfo(handle, RTLD_DI_ORIGIN, lib_path); + dlclose(handle); - if (ret < 0) - goto err_free; + if (ret < 0) + goto err_free; - lib_path_len = strlen(lib_path); + lib_path_len = strlen(lib_path); - snprintf(lib_path + lib_path_len, sizeof(lib_path) - lib_path_len, - "/digestlist/lib%s-%s.so", lib_type, new->format); + snprintf(lib_path + lib_path_len, sizeof(lib_path) - lib_path_len, + "/digestlist/lib%s-%s.so", lib_type, new->format); - new->handle = dlopen(lib_path, RTLD_LAZY | RTLD_NODELETE); - if (!new->handle) { - snprintf(lib_path, sizeof(lib_path), "lib%s-%s.so", lib_type, - new->format); + new->handle = dlopen(lib_path, RTLD_LAZY | RTLD_NODELETE); + if (!new->handle) { + snprintf(lib_path, sizeof(lib_path), "lib%s-%s.so", lib_type, + new->format); - new->handle = dlopen(lib_path, RTLD_LAZY | RTLD_NODELETE); - if (!new->handle) - goto err_free; - } + new->handle = dlopen(lib_path, RTLD_LAZY | RTLD_NODELETE); + if (!new->handle) + goto err_free; + } - new->func = dlsym(new->handle, function); + new->func = dlsym(new->handle, function); - if (!new->func) - goto err_free; + if (!new->func) + goto err_free; - list_add_tail(&new->list, head); + list_add_tail(&new->list, head); - return new; + return new; err_free: - if (new) { - free(new->format); - if (new->handle) - dlclose(new->handle); - } - - free(new); - return NULL; + if (new) { + free(new->format); + if (new->handle) + dlclose(new->handle); + } + + free(new); + return NULL; } void free_libs(struct list_head *head) { - struct lib *cur, *tmp; - - list_for_each_entry_safe(cur, tmp, head, list) { - list_del(&cur->list); - free(cur->format); - dlclose(cur->handle); - free(cur); - } + struct lib *cur, *tmp; + + list_for_each_entry_safe(cur, tmp, head, list) { + list_del(&cur->list); + free(cur->format); + dlclose(cur->handle); + free(cur); + } } int add_path_struct(char *path, char **attrs, struct list_head *head) { - struct path_struct *new; - int i; - - new = calloc(1, sizeof(*new)); - if (!new) - return -ENOMEM; - - if (attrs) { - /* skip the path */ - for (i = 1; i < ATTR__LAST; i++) { - if (!attrs[i]) - continue; - - new->attrs[i] = strdup(attrs[i]); - if (!new->attrs[i]) - goto err; - } - } - - new->path = malloc(strlen(path) + 1); - if (!new->path) - goto err; - - strcpy(new->path, path); - list_add_tail(&new->list, head); - return 0; + struct path_struct *new; + int i; + + new = calloc(1, sizeof(*new)); + if (!new) + return -ENOMEM; + + if (attrs) { + /* skip the path */ + for (i = 1; i < ATTR__LAST; i++) { + if (!attrs[i]) + continue; + + new->attrs[i] = strdup(attrs[i]); + if (!new->attrs[i]) + goto err; + } + } + + new->path = malloc(strlen(path) + 1); + if (!new->path) + goto err; + + strcpy(new->path, path); + list_add_tail(&new->list, head); + return 0; err: - for (i = 0; i < ATTR__LAST; i++) - free(new->attrs[i]); + for (i = 0; i < ATTR__LAST; i++) + free(new->attrs[i]); - free(new); - return -ENOMEM; + free(new); + return -ENOMEM; } void move_path_structs(struct list_head *dest, struct list_head *src) { - struct path_struct *p, *q; + struct path_struct *p, *q; - list_for_each_entry_safe(p, q, src, list) { - list_del(&p->list); - list_add_tail(&p->list, dest); - } + list_for_each_entry_safe(p, q, src, list) { + list_del(&p->list); + list_add_tail(&p->list, dest); + } } void free_path_structs(struct list_head *head) { - struct path_struct *cur, *tmp; - int i; + struct path_struct *cur, *tmp; + int i; - if (list_empty(head)) - return; + if (list_empty(head)) + return; - list_for_each_entry_safe(cur, tmp, head, list) { - list_del(&cur->list); + list_for_each_entry_safe(cur, tmp, head, list) { + list_del(&cur->list); - for (i = 0; i < ATTR__LAST; i++) - free(cur->attrs[i]); + for (i = 0; i < ATTR__LAST; i++) + free(cur->attrs[i]); - free(cur->path); - free(cur); - } + free(cur->path); + free(cur); + } } int parse_file_attrs(char *str, char **attrs) { - char *attr_ptr; - char *sep; - int i; + char *attr_ptr; + char *sep; + int i; - for (i = 0; i < ATTR__LAST; i++) - attrs[i] = NULL; + for (i = 0; i < ATTR__LAST; i++) + attrs[i] = NULL; - while((attr_ptr = strsep(&str, "|"))) { - i = ATTR__LAST; - sep = strchr(attr_ptr, '='); - if (!sep) - continue; + while((attr_ptr = strsep(&str, "|"))) { + i = ATTR__LAST; + sep = strchr(attr_ptr, '='); + if (!sep) + continue; - *sep = '\0'; - for (i = 0; i < ATTR__LAST; i++) { - if (!strcmp(attr_ptr, file_attrs_str[i])) - break; - } + *sep = '\0'; + for (i = 0; i < ATTR__LAST; i++) { + if (!strcmp(attr_ptr, file_attrs_str[i])) + break; + } - if (i == ATTR__LAST) - continue; + if (i == ATTR__LAST) + continue; - attrs[i] = sep + 1; - } + attrs[i] = sep + 1; + } - return 0; + return 0; } diff --git a/lib/parser_lib.c b/lib/parser_lib.c index c68cc98..2a703ae 100644 --- a/lib/parser_lib.c +++ b/lib/parser_lib.c @@ -25,239 +25,239 @@ #include "cap.h" int add_digest(int fd, struct list_head *head, u16 type, u16 modifiers, - u16 algo, u8 *digest) + u16 algo, u8 *digest) { - struct list_struct *list; + struct list_struct *list; - if (!digest) { - pr_err("TLV compact list, invalid data\n"); - return -ENOENT; - } + if (!digest) { + pr_err("TLV compact list, invalid data\n"); + return -ENOENT; + } - list = compact_list_init(head, type, modifiers, algo, false); - if (!list) - return -ENOMEM; + list = compact_list_init(head, type, modifiers, algo, false); + if (!list) + return -ENOMEM; - return compact_list_add_digest(fd, list, digest); + return compact_list_add_digest(fd, list, digest); } int calc_metadata_digest(int fd, struct list_head *head, u16 type, - u16 modifiers, u16 algo, u8 *digest, u8 *evm_digest, - char *path, uid_t uid, gid_t gid, mode_t mode, - char *obj_label, char *caps) + u16 modifiers, u16 algo, u8 *digest, u8 *evm_digest, + char *path, uid_t uid, gid_t gid, mode_t mode, + char *obj_label, char *caps) { - cap_t c; - struct vfs_cap_data rawvfscap; - enum hash_algo evm_algo = HASH_ALGO_SHA256; - u8 ima_xattr[2 + SHA512_DIGEST_SIZE], *caps_bin = NULL; - int ret, ima_xattr_len, rawvfscap_len = 0; - - if (!digest || !path) { - pr_err("TLV compact list, missing data\n"); - return -ENOENT; - } - - ret = gen_write_ima_xattr(ima_xattr, &ima_xattr_len, path, algo, digest, - (modifiers & (1 << COMPACT_MOD_IMMUTABLE)), - false); - if (ret < 0) - return ret; - - if (ima_canonical_fmt) { - uid = le32_to_cpu(uid); - gid = le32_to_cpu(gid); - mode = le32_to_cpu(mode); - } - - if (caps) { - c = cap_from_text(caps); - if (!c) - return -EINVAL; - - ret = _fcaps_save(&rawvfscap, c, &rawvfscap_len); - - cap_free(c); - - if (ret < 0) - return -EINVAL; - } - - ret = evm_calc_hmac_or_hash(evm_algo, evm_digest, - obj_label ? strlen(obj_label) + 1 : 0, - obj_label, ima_xattr_len, ima_xattr, - rawvfscap_len, (u8 *)&rawvfscap, - uid, gid, mode); - free(caps_bin); - return ret; + cap_t c; + struct vfs_cap_data rawvfscap; + enum hash_algo evm_algo = HASH_ALGO_SHA256; + u8 ima_xattr[2 + SHA512_DIGEST_SIZE], *caps_bin = NULL; + int ret, ima_xattr_len, rawvfscap_len = 0; + + if (!digest || !path) { + pr_err("TLV compact list, missing data\n"); + return -ENOENT; + } + + ret = gen_write_ima_xattr(ima_xattr, &ima_xattr_len, path, algo, digest, + (modifiers & (1 << COMPACT_MOD_IMMUTABLE)), + false); + if (ret < 0) + return ret; + + if (ima_canonical_fmt) { + uid = le32_to_cpu(uid); + gid = le32_to_cpu(gid); + mode = le32_to_cpu(mode); + } + + if (caps) { + c = cap_from_text(caps); + if (!c) + return -EINVAL; + + ret = _fcaps_save(&rawvfscap, c, &rawvfscap_len); + + cap_free(c); + + if (ret < 0) + return -EINVAL; + } + + ret = evm_calc_hmac_or_hash(evm_algo, evm_digest, + obj_label ? strlen(obj_label) + 1 : 0, + obj_label, ima_xattr_len, ima_xattr, + rawvfscap_len, (u8 *)&rawvfscap, + uid, gid, mode); + free(caps_bin); + return ret; } int add_metadata_digest(int fd, struct list_head *head, u16 modifiers, u8 *evm_digest) { - enum hash_algo evm_algo = HASH_ALGO_SHA256; - struct list_struct *list_metadata; + enum hash_algo evm_algo = HASH_ALGO_SHA256; + struct list_struct *list_metadata; - list_metadata = compact_list_init(head, COMPACT_METADATA, modifiers, evm_algo, - false); - if (!list_metadata) - return -ENOMEM; + list_metadata = compact_list_init(head, COMPACT_METADATA, modifiers, evm_algo, + false); + if (!list_metadata) + return -ENOMEM; - return compact_list_add_digest(fd, list_metadata, evm_digest); + return compact_list_add_digest(fd, list_metadata, evm_digest); } int add_ima_xattr(int fd, struct list_head *head, u16 type, u16 modifiers, - u16 algo, u8 *digest, char *path) + u16 algo, u8 *digest, char *path) { - u8 ima_xattr[2 + SHA512_DIGEST_SIZE]; - int ret, ima_xattr_len; + u8 ima_xattr[2 + SHA512_DIGEST_SIZE]; + int ret, ima_xattr_len; - if (!digest || !path) { - pr_err("TLV compact list, missing data\n"); - return -ENOENT; - } + if (!digest || !path) { + pr_err("TLV compact list, missing data\n"); + return -ENOENT; + } - ret = gen_write_ima_xattr(ima_xattr, &ima_xattr_len, path, algo, digest, - (modifiers & (1 << COMPACT_MOD_IMMUTABLE)), - true); - if (ret < 0) - pr_err("Cannot set IMA xattr for %s\n", path); + ret = gen_write_ima_xattr(ima_xattr, &ima_xattr_len, path, algo, digest, + (modifiers & (1 << COMPACT_MOD_IMMUTABLE)), + true); + if (ret < 0) + pr_err("Cannot set IMA xattr for %s\n", path); - return 0; + return 0; } int check_repair_xattr(char *path, char *xattr_name, void *xattr_value, - int xattr_value_len, int ima_algo, int modifiers, - int repair) + int xattr_value_len, int ima_algo, int modifiers, + int repair) { - cap_t c; - struct vfs_cap_data rawvfscap; - void *cur_xattr_value = NULL; - int cur_xattr_value_len; - u8 ima_xattr[2 + SHA512_DIGEST_SIZE]; - int ret, rawvfscap_len, ima_xattr_len; - - if (!strcmp(xattr_name, XATTR_NAME_IMA)) { - ret = gen_write_ima_xattr(ima_xattr, &ima_xattr_len, path, - ima_algo, xattr_value, + cap_t c; + struct vfs_cap_data rawvfscap; + void *cur_xattr_value = NULL; + int cur_xattr_value_len; + u8 ima_xattr[2 + SHA512_DIGEST_SIZE]; + int ret, rawvfscap_len, ima_xattr_len; + + if (!strcmp(xattr_name, XATTR_NAME_IMA)) { + ret = gen_write_ima_xattr(ima_xattr, &ima_xattr_len, path, + ima_algo, xattr_value, (modifiers & (1 << COMPACT_MOD_IMMUTABLE)), false); - if (ret < 0) - return ret; + if (ret < 0) + return ret; - xattr_value = &ima_xattr; - xattr_value_len = ima_xattr_len; - } else if (!strcmp(xattr_name, XATTR_NAME_CAPS) && xattr_value_len) { - c = cap_from_text(xattr_value); - if (!c) - return -EINVAL; + xattr_value = &ima_xattr; + xattr_value_len = ima_xattr_len; + } else if (!strcmp(xattr_name, XATTR_NAME_CAPS) && xattr_value_len) { + c = cap_from_text(xattr_value); + if (!c) + return -EINVAL; - ret = _fcaps_save(&rawvfscap, c, &rawvfscap_len); + ret = _fcaps_save(&rawvfscap, c, &rawvfscap_len); - cap_free(c); + cap_free(c); - if (ret < 0) - return -EINVAL; + if (ret < 0) + return -EINVAL; - xattr_value = &rawvfscap; - xattr_value_len = rawvfscap_len; + xattr_value = &rawvfscap; + xattr_value_len = rawvfscap_len; } - cur_xattr_value_len = lgetxattr(path, xattr_name, NULL, 0); - if (((cur_xattr_value_len == -1 && errno == ENODATA) || - cur_xattr_value_len == 0) && !xattr_value_len) - return 0; - - if (cur_xattr_value_len == -1 && errno != ENODATA) { - pr_err("Path %s: cannot read %s xattr\n", path, xattr_name); - return cur_xattr_value_len; - } - - if (!xattr_value_len) { - pr_err("Path %s: %s xattr defined, it should be removed\n", - path, xattr_name); - - if (repair) { - ret = lremovexattr(path, xattr_name); - if (ret < 0) { - printf("Path: %s, cannot remove %s xattr\n", - path, xattr_name); - } - } - - return 0; - } - - if (cur_xattr_value_len > 0) { - cur_xattr_value = malloc(cur_xattr_value_len); - if (!cur_xattr_value) { - pr_err("Out of memory\n"); - return -ENOMEM; - } - } - - cur_xattr_value_len = lgetxattr(path, xattr_name, cur_xattr_value, - cur_xattr_value_len); - if (xattr_value_len != cur_xattr_value_len || - memcmp(xattr_value, cur_xattr_value, xattr_value_len)) { - pr_err("Path %s: %s xattr value mismatch\n", path, xattr_name); - - if (repair) { - ret = lsetxattr(path, xattr_name, xattr_value, - xattr_value_len, 0); - if (ret) { - pr_err("Path %s: failed to set %s xattr\n", - path, xattr_name); - goto out; - } - } - } - - ret = 0; + cur_xattr_value_len = lgetxattr(path, xattr_name, NULL, 0); + if (((cur_xattr_value_len == -1 && errno == ENODATA) || + cur_xattr_value_len == 0) && !xattr_value_len) + return 0; + + if (cur_xattr_value_len == -1 && errno != ENODATA) { + pr_err("Path %s: cannot read %s xattr\n", path, xattr_name); + return cur_xattr_value_len; + } + + if (!xattr_value_len) { + pr_err("Path %s: %s xattr defined, it should be removed\n", + path, xattr_name); + + if (repair) { + ret = lremovexattr(path, xattr_name); + if (ret < 0) { + printf("Path: %s, cannot remove %s xattr\n", + path, xattr_name); + } + } + + return 0; + } + + if (cur_xattr_value_len > 0) { + cur_xattr_value = malloc(cur_xattr_value_len); + if (!cur_xattr_value) { + pr_err("Out of memory\n"); + return -ENOMEM; + } + } + + cur_xattr_value_len = lgetxattr(path, xattr_name, cur_xattr_value, + cur_xattr_value_len); + if (xattr_value_len != cur_xattr_value_len || + memcmp(xattr_value, cur_xattr_value, xattr_value_len)) { + pr_err("Path %s: %s xattr value mismatch\n", path, xattr_name); + + if (repair) { + ret = lsetxattr(path, xattr_name, xattr_value, + xattr_value_len, 0); + if (ret) { + pr_err("Path %s: failed to set %s xattr\n", + path, xattr_name); + goto out; + } + } + } + + ret = 0; out: - free(cur_xattr_value); - return ret; + free(cur_xattr_value); + return ret; } int check_repair_attr(char *path, uid_t uid, gid_t gid, mode_t mode, - int repair) + int repair) { - struct stat st; - int ret; - - if (stat(path, &st) == -1) { - pr_err("Path %s: file does not exist\n", path); - return -ENOENT; - } - - if (uid != st.st_uid || gid != st.st_gid) { - if (uid != st.st_uid) - pr_err("Path %s: uid mismatch, expected: %d, " - "current: %d\n", path, uid, st.st_uid); - - if (gid != st.st_gid) - pr_err("Path %s: gid mismatch, expected: %d, " - "current: %d\n", path, gid, st.st_gid); - - if (repair) { - ret = chown(path, uid, gid); - if (ret < 0) { - pr_err("Path %s: cannot set uid/gid\n", path); - return ret; - } - } - } - - if (mode != st.st_mode) { - pr_err("Path %s: mode mismatch, expected: %d, current: %d\n", - path, mode, st.st_mode); - - if (repair) { - ret = chmod(path, mode); - if (ret < 0) { - pr_err("Path %s: cannot set mode\n", path); - return ret; - } - } - } - - return 0; + struct stat st; + int ret; + + if (stat(path, &st) == -1) { + pr_err("Path %s: file does not exist\n", path); + return -ENOENT; + } + + if (uid != st.st_uid || gid != st.st_gid) { + if (uid != st.st_uid) + pr_err("Path %s: uid mismatch, expected: %d, " + "current: %d\n", path, uid, st.st_uid); + + if (gid != st.st_gid) + pr_err("Path %s: gid mismatch, expected: %d, " + "current: %d\n", path, gid, st.st_gid); + + if (repair) { + ret = chown(path, uid, gid); + if (ret < 0) { + pr_err("Path %s: cannot set uid/gid\n", path); + return ret; + } + } + } + + if (mode != st.st_mode) { + pr_err("Path %s: mode mismatch, expected: %d, current: %d\n", + path, mode, st.st_mode); + + if (repair) { + ret = chmod(path, mode); + if (ret < 0) { + pr_err("Path %s: cannot set mode\n", path); + return ret; + } + } + } + + return 0; } diff --git a/lib/pgp.c b/lib/pgp.c index 8c33077..52762f2 100644 --- a/lib/pgp.c +++ b/lib/pgp.c @@ -56,132 +56,132 @@ static inline void __set_bit(int nr, volatile unsigned long *addr) * hold the length of the packet header. */ ssize_t pgp_parse_packet_header(const u8 **_data, size_t *_datalen, - enum pgp_packet_tag *_type, - u8 *_headerlen) + enum pgp_packet_tag *_type, + u8 *_headerlen) { - enum pgp_packet_tag type; - const u8 *data = *_data; - size_t size, datalen = *_datalen; - - pr_devel("-->pgp_parse_packet_header(,%zu,,)\n", datalen); - - if (datalen < 2) - goto short_packet; - - pr_devel("pkthdr %02x, %02x\n", data[0], data[1]); - - type = *data++; - datalen--; - if (!(type & 0x80)) { - pr_debug("Packet type does not have MSB set\n"); - return -EBADMSG; - } - type &= ~0x80; - - if (type & 0x40) { - /* New packet length format */ - type &= ~0x40; - pr_devel("new format: t=%u\n", type); - switch (data[0]) { - case 0x00 ... 0xbf: - /* One-byte length */ - size = data[0]; - data++; - datalen--; - *_headerlen = 2; - break; - case 0xc0 ... 0xdf: - /* Two-byte length */ - if (datalen < 2) - goto short_packet; - size = (data[0] - 192) * 256; - size += data[1] + 192; - data += 2; - datalen -= 2; - *_headerlen = 3; - break; - case 0xff: - /* Five-byte length */ - if (datalen < 5) - goto short_packet; - size = data[1] << 24; - size |= data[2] << 16; - size |= data[3] << 8; - size |= data[4]; - data += 5; - datalen -= 5; - *_headerlen = 6; - break; - default: - pr_debug("Partial body length packet not supported\n"); - return -EBADMSG; - } - } else { - /* Old packet length format */ - u8 length_type = type & 0x03; - type >>= 2; - pr_devel("old format: t=%u lt=%u\n", type, length_type); - - switch (length_type) { - case 0: - /* One-byte length */ - size = data[0]; - data++; - datalen--; - *_headerlen = 2; - break; - case 1: - /* Two-byte length */ - if (datalen < 2) - goto short_packet; - size = data[0] << 8; - size |= data[1]; - data += 2; - datalen -= 2; - *_headerlen = 3; - break; - case 2: - /* Four-byte length */ - if (datalen < 4) - goto short_packet; - size = data[0] << 24; - size |= data[1] << 16; - size |= data[2] << 8; - size |= data[3]; - data += 4; - datalen -= 4; - *_headerlen = 5; - break; - default: - pr_debug("Indefinite length packet not supported\n"); - return -EBADMSG; - } - } - - pr_devel("datalen=%zu size=%zu", datalen, size); - if (datalen < size) - goto short_packet; - if ((int)size < 0) - goto too_big; - - *_data = data; - *_datalen = datalen; - *_type = type; - pr_devel("Found packet type=%u size=%zd\n", type, size); - return size; + enum pgp_packet_tag type; + const u8 *data = *_data; + size_t size, datalen = *_datalen; + + pr_devel("-->pgp_parse_packet_header(,%zu,,)\n", datalen); + + if (datalen < 2) + goto short_packet; + + pr_devel("pkthdr %02x, %02x\n", data[0], data[1]); + + type = *data++; + datalen--; + if (!(type & 0x80)) { + pr_debug("Packet type does not have MSB set\n"); + return -EBADMSG; + } + type &= ~0x80; + + if (type & 0x40) { + /* New packet length format */ + type &= ~0x40; + pr_devel("new format: t=%u\n", type); + switch (data[0]) { + case 0x00 ... 0xbf: + /* One-byte length */ + size = data[0]; + data++; + datalen--; + *_headerlen = 2; + break; + case 0xc0 ... 0xdf: + /* Two-byte length */ + if (datalen < 2) + goto short_packet; + size = (data[0] - 192) * 256; + size += data[1] + 192; + data += 2; + datalen -= 2; + *_headerlen = 3; + break; + case 0xff: + /* Five-byte length */ + if (datalen < 5) + goto short_packet; + size = data[1] << 24; + size |= data[2] << 16; + size |= data[3] << 8; + size |= data[4]; + data += 5; + datalen -= 5; + *_headerlen = 6; + break; + default: + pr_debug("Partial body length packet not supported\n"); + return -EBADMSG; + } + } else { + /* Old packet length format */ + u8 length_type = type & 0x03; + type >>= 2; + pr_devel("old format: t=%u lt=%u\n", type, length_type); + + switch (length_type) { + case 0: + /* One-byte length */ + size = data[0]; + data++; + datalen--; + *_headerlen = 2; + break; + case 1: + /* Two-byte length */ + if (datalen < 2) + goto short_packet; + size = data[0] << 8; + size |= data[1]; + data += 2; + datalen -= 2; + *_headerlen = 3; + break; + case 2: + /* Four-byte length */ + if (datalen < 4) + goto short_packet; + size = data[0] << 24; + size |= data[1] << 16; + size |= data[2] << 8; + size |= data[3]; + data += 4; + datalen -= 4; + *_headerlen = 5; + break; + default: + pr_debug("Indefinite length packet not supported\n"); + return -EBADMSG; + } + } + + pr_devel("datalen=%zu size=%zu", datalen, size); + if (datalen < size) + goto short_packet; + if ((int)size < 0) + goto too_big; + + *_data = data; + *_datalen = datalen; + *_type = type; + pr_devel("Found packet type=%u size=%zd\n", type, size); + return size; short_packet: - pr_debug("Attempt to parse short packet\n"); - return -EBADMSG; + pr_debug("Attempt to parse short packet\n"); + return -EBADMSG; too_big: - pr_debug("Signature subpacket size >2G\n"); - return -EMSGSIZE; + pr_debug("Signature subpacket size >2G\n"); + return -EMSGSIZE; } struct pgp_parse_sig_params_ctx { - struct pgp_parse_sig_context base; - struct pgp_sig_parameters *params; - bool got_the_issuer; + struct pgp_parse_sig_context base; + struct pgp_sig_parameters *params; + bool got_the_issuer; }; /** @@ -197,75 +197,75 @@ struct pgp_parse_sig_params_ctx { * hold the length of the packet header. */ static ssize_t pgp_parse_sig_subpkt_header(const u8 **_data, size_t *_datalen, - enum pgp_sig_subpkt_type *_type) + enum pgp_sig_subpkt_type *_type) { - enum pgp_sig_subpkt_type type; - const u8 *data = *_data; - size_t size, datalen = *_datalen; - - pr_devel("-->%s(,%zu,,)\n", __func__, datalen); - - if (datalen < 2) - goto short_subpacket; - - pr_devel("subpkt hdr %02x, %02x\n", data[0], data[1]); - - switch (data[0]) { - case 0x00 ... 0xbf: - /* One-byte length */ - size = data[0]; - data++; - datalen--; - break; - case 0xc0 ... 0xfe: - /* Two-byte length */ - if (datalen < 3) - goto short_subpacket; - size = (data[0] - 192) * 256; - size += data[1] + 192; - data += 2; - datalen -= 2; - break; - case 0xff: - if (datalen < 6) - goto short_subpacket; - size = data[1] << 24; - size |= data[2] << 16; - size |= data[3] << 8; - size |= data[4]; - data += 5; - datalen -= 5; - break; - } - - /* The type octet is included in the size */ - pr_devel("datalen=%zu size=%zu\n", datalen, size); - if (datalen < size) - goto short_subpacket; - if (size == 0) - goto very_short_subpacket; - if ((int)size < 0) - goto too_big; - - type = *data++ & ~PGP_SIG_SUBPKT_TYPE_CRITICAL_MASK; - datalen--; - size--; - - *_data = data; - *_datalen = datalen; - *_type = type; - pr_devel("Found subpkt type=%u size=%zd\n", type, size); - return size; + enum pgp_sig_subpkt_type type; + const u8 *data = *_data; + size_t size, datalen = *_datalen; + + pr_devel("-->%s(,%zu,,)\n", __func__, datalen); + + if (datalen < 2) + goto short_subpacket; + + pr_devel("subpkt hdr %02x, %02x\n", data[0], data[1]); + + switch (data[0]) { + case 0x00 ... 0xbf: + /* One-byte length */ + size = data[0]; + data++; + datalen--; + break; + case 0xc0 ... 0xfe: + /* Two-byte length */ + if (datalen < 3) + goto short_subpacket; + size = (data[0] - 192) * 256; + size += data[1] + 192; + data += 2; + datalen -= 2; + break; + case 0xff: + if (datalen < 6) + goto short_subpacket; + size = data[1] << 24; + size |= data[2] << 16; + size |= data[3] << 8; + size |= data[4]; + data += 5; + datalen -= 5; + break; + } + + /* The type octet is included in the size */ + pr_devel("datalen=%zu size=%zu\n", datalen, size); + if (datalen < size) + goto short_subpacket; + if (size == 0) + goto very_short_subpacket; + if ((int)size < 0) + goto too_big; + + type = *data++ & ~PGP_SIG_SUBPKT_TYPE_CRITICAL_MASK; + datalen--; + size--; + + *_data = data; + *_datalen = datalen; + *_type = type; + pr_devel("Found subpkt type=%u size=%zd\n", type, size); + return size; very_short_subpacket: - pr_debug("Signature subpacket size can't be zero\n"); - return -EBADMSG; + pr_debug("Signature subpacket size can't be zero\n"); + return -EBADMSG; short_subpacket: - pr_debug("Attempt to parse short signature subpacket\n"); - return -EBADMSG; + pr_debug("Attempt to parse short signature subpacket\n"); + return -EBADMSG; too_big: - pr_debug("Signature subpacket size >2G\n"); - return -EMSGSIZE; + pr_debug("Signature subpacket size >2G\n"); + return -EMSGSIZE; } /** @@ -277,60 +277,60 @@ too_big: * Parse a set of PGP signature subpackets [RFC 4880: 5.2.3]. */ static int pgp_parse_sig_subpkts(const u8 *data, size_t datalen, - struct pgp_parse_sig_context *ctx) + struct pgp_parse_sig_context *ctx) { - enum pgp_sig_subpkt_type type; - ssize_t pktlen; - int ret; - - pr_devel("-->%s(,%zu,,)\n", __func__, datalen); - - while (datalen > 2) { - pktlen = pgp_parse_sig_subpkt_header(&data, &datalen, &type); - if (pktlen < 0) - return pktlen; - if (test_bit(type, ctx->types_of_interest)) { - ret = ctx->process_packet(ctx, type, data, pktlen); - if (ret < 0) - return ret; - } - data += pktlen; - datalen -= pktlen; - } - - if (datalen != 0) { - pr_debug("Excess octets in signature subpacket stream\n"); - return -EBADMSG; - } - - return 0; + enum pgp_sig_subpkt_type type; + ssize_t pktlen; + int ret; + + pr_devel("-->%s(,%zu,,)\n", __func__, datalen); + + while (datalen > 2) { + pktlen = pgp_parse_sig_subpkt_header(&data, &datalen, &type); + if (pktlen < 0) + return pktlen; + if (test_bit(type, ctx->types_of_interest)) { + ret = ctx->process_packet(ctx, type, data, pktlen); + if (ret < 0) + return ret; + } + data += pktlen; + datalen -= pktlen; + } + + if (datalen != 0) { + pr_debug("Excess octets in signature subpacket stream\n"); + return -EBADMSG; + } + + return 0; } /* * Process a V4 signature subpacket. */ static int pgp_process_sig_params_subpkt(struct pgp_parse_sig_context *context, - enum pgp_sig_subpkt_type type, - const u8 *data, - size_t datalen) + enum pgp_sig_subpkt_type type, + const u8 *data, + size_t datalen) { - struct pgp_parse_sig_params_ctx *ctx = - container_of(context, struct pgp_parse_sig_params_ctx, base); - - if (ctx->got_the_issuer) { - pr_debug("V4 signature packet has multiple issuers\n"); - return -EBADMSG; - } - - if (datalen != 8) { - pr_debug("V4 signature issuer subpkt not 8 long (%zu)\n", - datalen); - return -EBADMSG; - } - - memcpy(&ctx->params->issuer, data, 8); - ctx->got_the_issuer = true; - return 0; + struct pgp_parse_sig_params_ctx *ctx = + container_of(context, struct pgp_parse_sig_params_ctx, base); + + if (ctx->got_the_issuer) { + pr_debug("V4 signature packet has multiple issuers\n"); + return -EBADMSG; + } + + if (datalen != 8) { + pr_debug("V4 signature issuer subpkt not 8 long (%zu)\n", + datalen); + return -EBADMSG; + } + + memcpy(&ctx->params->issuer, data, 8); + ctx->got_the_issuer = true; + return 0; } /** @@ -352,202 +352,202 @@ static int pgp_process_sig_params_subpkt(struct pgp_parse_sig_context *context, * updated to point to the 16-bit subset of the hash value and the set of MPIs. */ int pgp_parse_sig_params(const u8 **_data, size_t *_datalen, - struct pgp_sig_parameters *p, - const u8 **hashed, size_t *hashedlen) + struct pgp_sig_parameters *p, + const u8 **hashed, size_t *hashedlen) { - const u8 *data = *_data; - size_t datalen = *_datalen; - int ret; - - pr_devel("-->%s(,%zu,,)\n", __func__, datalen); - - if (datalen < 1) - return -EBADMSG; - p->version = *data; - - if (p->version == PGP_SIG_VERSION_3) { - const struct pgp_signature_v3_packet *v3 = (const void *)data; - - if (datalen < sizeof(*v3)) { - pr_debug("Short V3 signature packet\n"); - return -EBADMSG; - } - - *hashedlen = v3->length_of_hashed; - *hashed = (u8 *)&v3->hashed; - - datalen -= sizeof(*v3); - data += sizeof(*v3); - - /* V3 has everything we need in the header */ - p->signature_type = v3->hashed.signature_type; - memcpy(&p->issuer, &v3->issuer, 8); - p->pubkey_algo = v3->pubkey_algo; - p->hash_algo = v3->hash_algo; - - } else if (p->version == PGP_SIG_VERSION_4) { - const struct pgp_signature_v4_packet *v4 = (const void *)data; - struct pgp_parse_sig_params_ctx ctx = { - .base.process_packet = pgp_process_sig_params_subpkt, - .params = p, - .got_the_issuer = false, - }; - size_t subdatalen; - - if (datalen < sizeof(*v4) + 2 + 2 + 2) { - pr_debug("Short V4 signature packet\n"); - return -EBADMSG; - } - datalen -= sizeof(*v4); - data += sizeof(*v4); - - /* V4 has most things in the header... */ - p->signature_type = v4->signature_type; - p->pubkey_algo = v4->pubkey_algo; - p->hash_algo = v4->hash_algo; - - /* ... but we have to get the key ID from the subpackets, of - * which there are two sets. - */ - __set_bit(PGP_SIG_ISSUER, ctx.base.types_of_interest); - - subdatalen = *data++ << 8; - subdatalen |= *data++; - datalen -= 2; - - *hashedlen = 4 + 2 + subdatalen; - *hashed = *_data; - - if (subdatalen) { - /* Hashed subpackets */ - pr_devel("hashed data: %zu (after %zu)\n", - subdatalen, sizeof(*v4)); - if (subdatalen > datalen + 2 + 2) { - pr_debug("Short V4 signature packet [hdata]\n"); - return -EBADMSG; - } - ret = pgp_parse_sig_subpkts(data, subdatalen, - &ctx.base); - if (ret < 0) - return ret; - data += subdatalen; - datalen -= subdatalen; - } - - subdatalen = *data++ << 8; - subdatalen |= *data++; - datalen -= 2; - if (subdatalen) { - /* Unhashed subpackets */ - pr_devel("unhashed data: %zu\n", subdatalen); - if (subdatalen > datalen + 2) { - pr_debug("Short V4 signature packet [udata]\n"); - return -EBADMSG; - } - ret = pgp_parse_sig_subpkts(data, subdatalen, - &ctx.base); - if (ret < 0) - return ret; - data += subdatalen; - datalen -= subdatalen; - } - - if (!ctx.got_the_issuer) { - pr_debug("V4 signature packet lacks issuer\n"); - return -EBADMSG; - } - } else { - pr_debug("Signature packet with unhandled version %d\n", - p->version); - return -EBADMSG; - } - - *_data = data; - *_datalen = datalen; - return 0; + const u8 *data = *_data; + size_t datalen = *_datalen; + int ret; + + pr_devel("-->%s(,%zu,,)\n", __func__, datalen); + + if (datalen < 1) + return -EBADMSG; + p->version = *data; + + if (p->version == PGP_SIG_VERSION_3) { + const struct pgp_signature_v3_packet *v3 = (const void *)data; + + if (datalen < sizeof(*v3)) { + pr_debug("Short V3 signature packet\n"); + return -EBADMSG; + } + + *hashedlen = v3->length_of_hashed; + *hashed = (u8 *)&v3->hashed; + + datalen -= sizeof(*v3); + data += sizeof(*v3); + + /* V3 has everything we need in the header */ + p->signature_type = v3->hashed.signature_type; + memcpy(&p->issuer, &v3->issuer, 8); + p->pubkey_algo = v3->pubkey_algo; + p->hash_algo = v3->hash_algo; + + } else if (p->version == PGP_SIG_VERSION_4) { + const struct pgp_signature_v4_packet *v4 = (const void *)data; + struct pgp_parse_sig_params_ctx ctx = { + .base.process_packet = pgp_process_sig_params_subpkt, + .params = p, + .got_the_issuer = false, + }; + size_t subdatalen; + + if (datalen < sizeof(*v4) + 2 + 2 + 2) { + pr_debug("Short V4 signature packet\n"); + return -EBADMSG; + } + datalen -= sizeof(*v4); + data += sizeof(*v4); + + /* V4 has most things in the header... */ + p->signature_type = v4->signature_type; + p->pubkey_algo = v4->pubkey_algo; + p->hash_algo = v4->hash_algo; + + /* ... but we have to get the key ID from the subpackets, of + * which there are two sets. + */ + __set_bit(PGP_SIG_ISSUER, ctx.base.types_of_interest); + + subdatalen = *data++ << 8; + subdatalen |= *data++; + datalen -= 2; + + *hashedlen = 4 + 2 + subdatalen; + *hashed = *_data; + + if (subdatalen) { + /* Hashed subpackets */ + pr_devel("hashed data: %zu (after %zu)\n", + subdatalen, sizeof(*v4)); + if (subdatalen > datalen + 2 + 2) { + pr_debug("Short V4 signature packet [hdata]\n"); + return -EBADMSG; + } + ret = pgp_parse_sig_subpkts(data, subdatalen, + &ctx.base); + if (ret < 0) + return ret; + data += subdatalen; + datalen -= subdatalen; + } + + subdatalen = *data++ << 8; + subdatalen |= *data++; + datalen -= 2; + if (subdatalen) { + /* Unhashed subpackets */ + pr_devel("unhashed data: %zu\n", subdatalen); + if (subdatalen > datalen + 2) { + pr_debug("Short V4 signature packet [udata]\n"); + return -EBADMSG; + } + ret = pgp_parse_sig_subpkts(data, subdatalen, + &ctx.base); + if (ret < 0) + return ret; + data += subdatalen; + datalen -= subdatalen; + } + + if (!ctx.got_the_issuer) { + pr_debug("V4 signature packet lacks issuer\n"); + return -EBADMSG; + } + } else { + pr_debug("Signature packet with unhandled version %d\n", + p->version); + return -EBADMSG; + } + + *_data = data; + *_datalen = datalen; + return 0; } int pgp_get_signature_data(const u8 *signature, size_t signature_len, - u8 **data, size_t *data_len, u8 **sig, - size_t *sig_len, u8 **issuer, u16 *algo) + u8 **data, size_t *data_len, u8 **sig, + size_t *sig_len, u8 **issuer, u16 *algo) { - unsigned int nbytes, nbytes_alloc; - enum pgp_packet_tag type; - ssize_t pktlen; - u8 headerlen; - struct pgp_sig_parameters p; - const u8 *hashed; - size_t hashedlen; - u8 trailer[6]; - int ret; - - *data = NULL; - - pktlen = pgp_parse_packet_header((const u8 **)&signature, - &signature_len, &type, &headerlen); - if (pktlen < 0) - return pktlen; - - ret = pgp_parse_sig_params(&signature, &signature_len, &p, - &hashed, &hashedlen); - if (ret < 0) - return ret; - - if (p.version == 3) { - *data_len = hashedlen; - *data = malloc(hashedlen); - if (*data == NULL) - return -ENOMEM; - - memcpy(*data, hashed, hashedlen); - } else if (p.version == 4) { - trailer[0] = p.version; - trailer[1] = 0xffU; - trailer[2] = hashedlen >> 24; - trailer[3] = hashedlen >> 16; - trailer[4] = hashedlen >> 8; - trailer[5] = hashedlen; - - *data_len = hashedlen + sizeof(trailer); - *data = malloc(hashedlen + 6); - if (*data == NULL) - return -ENOMEM; - - memcpy(*data, hashed, hashedlen); - memcpy(*data + hashedlen, trailer, 6); - } - - *algo = p.hash_algo; - - *issuer = malloc(4); - if (!*issuer) { - ret = -ENOMEM; - goto out; - } - - memcpy(*issuer, p.issuer.id + sizeof(uint32_t), sizeof(uint32_t)); - - signature += 2; - signature_len -= 2; - - nbytes = signature_len - 2; - nbytes_alloc = __KERNEL_DIV_ROUND_UP(nbytes, 8) * 8; - - *sig = calloc(nbytes_alloc, sizeof(u8)); - if (!*sig) { - ret = -ENOMEM; - goto out; - } - - memcpy(*sig + nbytes_alloc - nbytes, signature + 2, nbytes); - *sig_len = nbytes_alloc; - - ret = 0; + unsigned int nbytes, nbytes_alloc; + enum pgp_packet_tag type; + ssize_t pktlen; + u8 headerlen; + struct pgp_sig_parameters p; + const u8 *hashed; + size_t hashedlen; + u8 trailer[6]; + int ret; + + *data = NULL; + + pktlen = pgp_parse_packet_header((const u8 **)&signature, + &signature_len, &type, &headerlen); + if (pktlen < 0) + return pktlen; + + ret = pgp_parse_sig_params(&signature, &signature_len, &p, + &hashed, &hashedlen); + if (ret < 0) + return ret; + + if (p.version == 3) { + *data_len = hashedlen; + *data = malloc(hashedlen); + if (*data == NULL) + return -ENOMEM; + + memcpy(*data, hashed, hashedlen); + } else if (p.version == 4) { + trailer[0] = p.version; + trailer[1] = 0xffU; + trailer[2] = hashedlen >> 24; + trailer[3] = hashedlen >> 16; + trailer[4] = hashedlen >> 8; + trailer[5] = hashedlen; + + *data_len = hashedlen + sizeof(trailer); + *data = malloc(hashedlen + 6); + if (*data == NULL) + return -ENOMEM; + + memcpy(*data, hashed, hashedlen); + memcpy(*data + hashedlen, trailer, 6); + } + + *algo = p.hash_algo; + + *issuer = malloc(4); + if (!*issuer) { + ret = -ENOMEM; + goto out; + } + + memcpy(*issuer, p.issuer.id + sizeof(uint32_t), sizeof(uint32_t)); + + signature += 2; + signature_len -= 2; + + nbytes = signature_len - 2; + nbytes_alloc = __KERNEL_DIV_ROUND_UP(nbytes, 8) * 8; + + *sig = calloc(nbytes_alloc, sizeof(u8)); + if (!*sig) { + ret = -ENOMEM; + goto out; + } + + memcpy(*sig + nbytes_alloc - nbytes, signature + 2, nbytes); + *sig_len = nbytes_alloc; + + ret = 0; out: - if (ret < 0) { - free(*data); - free(*issuer); - } + if (ret < 0) { + free(*data); + free(*issuer); + } - return ret; + return ret; } diff --git a/lib/selinux.c b/lib/selinux.c index 28d7b86..068697f 100644 --- a/lib/selinux.c +++ b/lib/selinux.c @@ -23,39 +23,39 @@ static struct selabel_handle *h; int selinux_init_setup(void) { - int rc = 0; + int rc = 0; - h = selabel_open(SELABEL_CTX_FILE, NULL, 0); - if (!h) { - pr_err("Cannot initialize libselinux\n"); - return -EPERM; - } + h = selabel_open(SELABEL_CTX_FILE, NULL, 0); + if (!h) { + pr_err("Cannot initialize libselinux\n"); + return -EPERM; + } - selinux_restorecon_set_sehandle(h); + selinux_restorecon_set_sehandle(h); - return rc; + return rc; } void selinux_end_setup(void) { - if (h) { - selabel_close(h); - h = NULL; - } + if (h) { + selabel_close(h); + h = NULL; + } } int get_selinux_label(char *path, char *alt_root, char **label, mode_t mode) { - int offset = alt_root ? strlen(alt_root) : 0; - int ret; - - if (!h) { - ret = selinux_init_setup(); - if (ret < 0) { - *label = NULL; - return 0; - } - } - - return selabel_lookup_raw(h, label, path + offset, mode); + int offset = alt_root ? strlen(alt_root) : 0; + int ret; + + if (!h) { + ret = selinux_init_setup(); + if (ret < 0) { + *label = NULL; + return 0; + } + } + + return selabel_lookup_raw(h, label, path + offset, mode); } diff --git a/lib/xattr.c b/lib/xattr.c index 6f047c2..1fe97a7 100644 --- a/lib/xattr.c +++ b/lib/xattr.c @@ -20,150 +20,150 @@ int write_ima_xattr(int dirfd, char *path, u8 *keyid, size_t keyid_len, - u8 *sig, size_t sig_len, enum hash_algo algo) + u8 *sig, size_t sig_len, enum hash_algo algo) { - struct signature_v2_hdr *hdr; - u8 *xattr_buf; - size_t xattr_buf_len; - int ret, fd; - - xattr_buf_len = sizeof(*hdr) + sig_len; - xattr_buf = calloc(sizeof(u8), xattr_buf_len); - if (!xattr_buf) { - printf("Out of memory\n"); - return -ENOMEM; - } - - hdr = (struct signature_v2_hdr *)xattr_buf; - hdr->type = EVM_IMA_XATTR_DIGSIG; - hdr->version = 2; - hdr->hash_algo = algo; - if (keyid_len) - memcpy(&hdr->keyid, keyid, keyid_len); - hdr->sig_size = cpu_to_be16(sig_len); - memcpy(&hdr->sig, sig, sig_len); - - if (dirfd != -1) { - fd = openat(dirfd, path, O_RDONLY); - if (fd < 0) { - printf("Cannot open %s\n", path); - ret = fd; - goto out; - } - - ret = fsetxattr(fd, XATTR_NAME_IMA, - xattr_buf, xattr_buf_len, 0); - close(fd); - } else { - ret = lsetxattr(path, XATTR_NAME_IMA, - xattr_buf, xattr_buf_len, 0); - } + struct signature_v2_hdr *hdr; + u8 *xattr_buf; + size_t xattr_buf_len; + int ret, fd; + + xattr_buf_len = sizeof(*hdr) + sig_len; + xattr_buf = calloc(sizeof(u8), xattr_buf_len); + if (!xattr_buf) { + printf("Out of memory\n"); + return -ENOMEM; + } + + hdr = (struct signature_v2_hdr *)xattr_buf; + hdr->type = EVM_IMA_XATTR_DIGSIG; + hdr->version = 2; + hdr->hash_algo = algo; + if (keyid_len) + memcpy(&hdr->keyid, keyid, keyid_len); + hdr->sig_size = cpu_to_be16(sig_len); + memcpy(&hdr->sig, sig, sig_len); + + if (dirfd != -1) { + fd = openat(dirfd, path, O_RDONLY); + if (fd < 0) { + printf("Cannot open %s\n", path); + ret = fd; + goto out; + } + + ret = fsetxattr(fd, XATTR_NAME_IMA, + xattr_buf, xattr_buf_len, 0); + close(fd); + } else { + ret = lsetxattr(path, XATTR_NAME_IMA, + xattr_buf, xattr_buf_len, 0); + } out: - if (ret < 0 && errno != ENOTSUP) - printf("Cannot add %s xattr to %s: %s\n", XATTR_NAME_IMA, path, - strerror(errno)); + if (ret < 0 && errno != ENOTSUP) + printf("Cannot add %s xattr to %s: %s\n", XATTR_NAME_IMA, path, + strerror(errno)); - free(xattr_buf); - return 0; + free(xattr_buf); + return 0; } int write_evm_xattr(char *path, enum hash_algo algo) { - struct signature_v2_hdr hdr = { 0 }; - int ret; + struct signature_v2_hdr hdr = { 0 }; + int ret; - hdr.type = EVM_IMA_XATTR_DIGEST_LIST; - hdr.version = 2; - hdr.hash_algo = algo; + hdr.type = EVM_IMA_XATTR_DIGEST_LIST; + hdr.version = 2; + hdr.hash_algo = algo; - ret = lsetxattr(path, XATTR_NAME_EVM, &hdr, - offsetof(struct signature_v2_hdr, keyid), 0); - if (ret < 0 && errno != ENOTSUP) - printf("Cannot add %s xattr to %s: %s\n", XATTR_NAME_EVM, path, - strerror(errno)); + ret = lsetxattr(path, XATTR_NAME_EVM, &hdr, + offsetof(struct signature_v2_hdr, keyid), 0); + if (ret < 0 && errno != ENOTSUP) + printf("Cannot add %s xattr to %s: %s\n", XATTR_NAME_EVM, path, + strerror(errno)); - return 0; + return 0; } int parse_ima_xattr(u8 *buf, size_t buf_len, u8 **keyid, size_t *keyid_len, - u8 **sig, size_t *sig_len, enum hash_algo *algo) + u8 **sig, size_t *sig_len, enum hash_algo *algo) { - struct signature_v2_hdr *hdr; + struct signature_v2_hdr *hdr; - if (buf_len < sizeof(*hdr)) - return -EINVAL; + if (buf_len < sizeof(*hdr)) + return -EINVAL; - hdr = (struct signature_v2_hdr *)buf; + hdr = (struct signature_v2_hdr *)buf; - if (hdr->type != EVM_IMA_XATTR_DIGSIG && - hdr->type != EVM_XATTR_PORTABLE_DIGSIG) - return -EINVAL; + if (hdr->type != EVM_IMA_XATTR_DIGSIG && + hdr->type != EVM_XATTR_PORTABLE_DIGSIG) + return -EINVAL; - if (hdr->version != 2) - return -EINVAL; + if (hdr->version != 2) + return -EINVAL; - *algo = hdr->hash_algo; - *keyid = (u8 *)&hdr->keyid; - *keyid_len = sizeof(hdr->keyid); - *sig = hdr->sig; - *sig_len = be16_to_cpu(hdr->sig_size); + *algo = hdr->hash_algo; + *keyid = (u8 *)&hdr->keyid; + *keyid_len = sizeof(hdr->keyid); + *sig = hdr->sig; + *sig_len = be16_to_cpu(hdr->sig_size); - if (buf_len != sizeof(*hdr) + *sig_len) - return -EINVAL; + if (buf_len != sizeof(*hdr) + *sig_len) + return -EINVAL; - return 0; + return 0; } int read_ima_xattr(int dirfd, char *path, u8 **buf, size_t *buf_len, - u8 **keyid, size_t *keyid_len, u8 **sig, size_t *sig_len, - enum hash_algo *algo) + u8 **keyid, size_t *keyid_len, u8 **sig, size_t *sig_len, + enum hash_algo *algo) { - ssize_t ret; - int fd; - - fd = openat(dirfd, path, O_RDONLY); - if (fd < 0) { - printf("Cannot open %s\n", path); - return fd; - } - - ret = fgetxattr(fd, XATTR_NAME_IMA, NULL, 0); - if (ret < 0) - return -ENODATA; - - *buf_len = ret; - *buf = malloc(*buf_len); - if (!*buf) - return -ENOMEM; - - ret = fgetxattr(fd, XATTR_NAME_IMA, *buf, ret); - if (ret < 0) - return -ENODATA; - - ret = parse_ima_xattr(*buf, *buf_len, keyid, keyid_len, sig, sig_len, - algo); - close(fd); - return ret; + ssize_t ret; + int fd; + + fd = openat(dirfd, path, O_RDONLY); + if (fd < 0) { + printf("Cannot open %s\n", path); + return fd; + } + + ret = fgetxattr(fd, XATTR_NAME_IMA, NULL, 0); + if (ret < 0) + return -ENODATA; + + *buf_len = ret; + *buf = malloc(*buf_len); + if (!*buf) + return -ENOMEM; + + ret = fgetxattr(fd, XATTR_NAME_IMA, *buf, ret); + if (ret < 0) + return -ENODATA; + + ret = parse_ima_xattr(*buf, *buf_len, keyid, keyid_len, sig, sig_len, + algo); + close(fd); + return ret; } int gen_write_ima_xattr(u8 *buf, int *buf_len, char *path, u8 algo, u8 *digest, - bool immutable, bool write) + bool immutable, bool write) { - struct evm_ima_xattr_data *ima_xattr = (struct evm_ima_xattr_data *)buf; - int ret; + struct evm_ima_xattr_data *ima_xattr = (struct evm_ima_xattr_data *)buf; + int ret; - *buf_len = 1 + 1 + hash_digest_size[algo]; - ima_xattr->type = IMA_XATTR_DIGEST_NG; - ima_xattr->digest[0] = algo; - memcpy(&ima_xattr->digest[1], digest, hash_digest_size[algo]); + *buf_len = 1 + 1 + hash_digest_size[algo]; + ima_xattr->type = IMA_XATTR_DIGEST_NG; + ima_xattr->digest[0] = algo; + memcpy(&ima_xattr->digest[1], digest, hash_digest_size[algo]); - if (!write) - return 0; + if (!write) + return 0; - ret = lsetxattr(path, XATTR_NAME_IMA, buf, *buf_len, 0); - if (ret < 0 && errno != ENOTSUP) - printf("Cannot add %s xattr to %s: %s\n", XATTR_NAME_IMA, path, - strerror(errno)); + ret = lsetxattr(path, XATTR_NAME_IMA, buf, *buf_len, 0); + if (ret < 0 && errno != ENOTSUP) + printf("Cannot add %s xattr to %s: %s\n", XATTR_NAME_IMA, path, + strerror(errno)); - return 0; + return 0; } diff --git a/parsers/compact_tlv.c b/parsers/compact_tlv.c index 3cd3b95..c3fbe6e 100644 --- a/parsers/compact_tlv.c +++ b/parsers/compact_tlv.c @@ -23,254 +23,254 @@ #define items_data_len(id) (items[id] ? items[id]->len : 0) int parser(int fd, struct list_head *head, loff_t size, void *buf, - enum parser_ops op) + enum parser_ops op) { - u32 len; - u16 modifiers; - u32 i_meta[4] = { 0 }; - u64 fs_magic = 0; - struct _tlv_item *item_ptr; - struct _tlv_item *items[ID__LAST] = { NULL }; - enum hash_algo evm_algo = HASH_ALGO_SHA256; - u8 evm_digest[SHA512_DIGEST_SIZE], *evm_digest_ptr; - void *bufp = buf, *bufendp = buf + size; - struct compact_list_hdr hdr, *hdrp; - int ret, i, j, count; - - while (bufp < bufendp) { - if (bufp + sizeof(hdr) > bufendp) { - pr_err("compact list, invalid data\n"); - return -EINVAL; - } - - hdrp = bufp; - memcpy(&hdr, hdrp, sizeof(hdr)); - - if (hdr.version != 2) { - pr_err("compact list, unsupported version\n"); - return -EINVAL; - } - - if (ima_canonical_fmt) { - hdr.type = le16_to_cpu(hdr.type); - hdr.modifiers = le16_to_cpu(hdr.modifiers); - hdr.algo = le16_to_cpu(hdr.algo); - hdr.count = le32_to_cpu(hdr.count); - hdr.datalen = le32_to_cpu(hdr.datalen); - } - - if (hdr.algo >= HASH_ALGO__LAST) - return -EINVAL; - - if (hdr.type >= COMPACT__LAST) { - pr_err("TLV compact list, invalid type %d\n", - hdr.type); - return -EINVAL; - } - - bufp += sizeof(hdr); - - for (i = 0; i < hdr.count; i++) { - if (bufp + sizeof(u8) > bufendp) { - pr_err("TLV compact list, invalid data\n"); - return -EINVAL; - } - - for (j = 0; j < ID__LAST; j++) - items[j] = NULL; - - count = *(u8 *)bufp++; - - for (j = 0; j < count; j++) { - if (bufp + sizeof(**items) > bufendp) { - pr_err("TLV compact list, " - "invalid data\n"); - return -EINVAL; - } - - item_ptr = (struct _tlv_item *)bufp; - if (item_ptr->id >= ID__LAST) { - pr_err("TLV compact list, " - "invalid data\n"); - return -EINVAL; - } - - bufp += sizeof(*item_ptr); - - len = item_ptr->len; - if (ima_canonical_fmt) - len = le32_to_cpu(len); - - items[item_ptr->id] = item_ptr; - - if (bufp + len > bufendp) { - pr_err("TLV compact list, " - "invalid data\n"); - return -EINVAL; - } - - bufp += len; - } - - modifiers = hdr.modifiers; - - for (j = 0; j < 4; j++) { - if (!items_data(ID_INODE_UID + j)) - continue; - - i_meta[j] = - *(u32 *)items_data(ID_INODE_UID + j); - if (ima_canonical_fmt) - i_meta[j] = le32_to_cpu(i_meta[j]); - } - - if (((i_meta[2] & S_IXUGO) || !(i_meta[2] & S_IWUGO)) && - i_meta[3]) - modifiers |= (1 << COMPACT_MOD_IMMUTABLE); - - if (items_data(ID_FSMAGIC)) { - fs_magic = *(u64 *)items_data(ID_FSMAGIC); - if (ima_canonical_fmt) - fs_magic = le64_to_cpu(fs_magic); - } - - ret = 0; - - switch (op) { - case PARSER_OP_ADD_DIGEST: - ret = add_digest(fd, head, hdr.type, - modifiers, hdr.algo, - items_data(ID_DIGEST)); - break; - case PARSER_OP_ADD_DIGEST_TO_HTABLE: - ret = ima_add_digest_data_entry_kernel( - items_data(ID_DIGEST), - hdr.algo, hdr.type, - modifiers); - if (ret == -EEXIST) - ret = 0; - break; - case PARSER_OP_ADD_META_DIGEST: - case PARSER_OP_ADD_META_DIGEST_TO_HTABLE: - if (!items_data(ID_EVM_DIGEST)) { - ret = calc_metadata_digest(fd, head, - hdr.type, modifiers, - hdr.algo, items_data(ID_DIGEST), - evm_digest, - (char *)items_data(ID_PATH), - i_meta[0], i_meta[1], i_meta[2], - (char *)items_data(ID_OBJ_LABEL), - (char *)items_data(ID_CAPS)); - if (ret < 0) - break; - - evm_digest_ptr = evm_digest; - } else { - evm_digest_ptr = - items_data(ID_EVM_DIGEST); - } - - if (items_data(ID_EVM_DIGEST)) { - memcpy(items[ID_EVM_DIGEST]->data, - evm_digest, - hash_digest_size[evm_algo]); - break; - } - - if (op == PARSER_OP_ADD_META_DIGEST_TO_HTABLE) { - ret = ima_add_digest_data_entry_kernel( - evm_digest_ptr, - HASH_ALGO_SHA256, - COMPACT_METADATA, 0); - if (ret == -EEXIST) - ret = 0; - - break; - } - - ret = add_metadata_digest(fd, head, modifiers, - evm_digest_ptr); - break; - case PARSER_OP_ADD_IMA_XATTR: - if (fs_magic == TMPFS_MAGIC) - break; - - ret = add_ima_xattr(fd, head, hdr.type, - modifiers, hdr.algo, - items_data(ID_DIGEST), - (char *)items_data(ID_PATH)); - break; - case PARSER_OP_REMOVE_IMA_XATTR: - if (fs_magic == TMPFS_MAGIC) - break; - - removexattr((char *)items_data(ID_PATH), - XATTR_NAME_IMA); - break; - case PARSER_OP_ADD_EVM_XATTR: - write_evm_xattr((char *)items_data(ID_PATH), - hdr.algo); - break; - case PARSER_OP_REMOVE_EVM_XATTR: - if (fs_magic == TMPFS_MAGIC) - break; - - removexattr((char *)items_data(ID_PATH), - XATTR_NAME_EVM); - break; - case PARSER_OP_REMOVE_INFOFLOW_XATTR: - if (fs_magic == TMPFS_MAGIC) - break; - - removexattr((char *)items_data(ID_PATH), - "security.infoflow"); - break; - case PARSER_OP_DUMP: - compact_list_tlv_dump_items(items); - break; - case PARSER_OP_CHECK_META: - case PARSER_OP_REPAIR_META: - check_repair_xattr((char *)items_data(ID_PATH), - XATTR_NAME_SELINUX, - items_data(ID_OBJ_LABEL), - items_data_len(ID_OBJ_LABEL), - hdr.algo, modifiers, - (op == PARSER_OP_REPAIR_META)); - - check_repair_xattr((char *)items_data(ID_PATH), - XATTR_NAME_IMA, - items_data(ID_DIGEST), - items_data_len(ID_DIGEST), - hdr.algo, modifiers, - (op == PARSER_OP_REPAIR_META)); - - check_repair_xattr((char *)items_data(ID_PATH), - XATTR_NAME_CAPS, - items_data(ID_CAPS), - items_data_len(ID_CAPS), - hdr.algo, modifiers, - (op == PARSER_OP_REPAIR_META)); - - check_repair_attr((char *)items_data(ID_PATH), - i_meta[0], i_meta[1], i_meta[2], - (op == PARSER_OP_REPAIR_META)); - ret = 0; - break; - default: - ret = -ENOTSUP; - break; - } - - if (ret < 0) - return ret; - } - - if (i != hdr.count || - bufp != (void *)hdrp + sizeof(hdr) + hdr.datalen) { - pr_err("compact list, invalid data\n"); - return -EINVAL; - } - } - - return 0; + u32 len; + u16 modifiers; + u32 i_meta[4] = { 0 }; + u64 fs_magic = 0; + struct _tlv_item *item_ptr; + struct _tlv_item *items[ID__LAST] = { NULL }; + enum hash_algo evm_algo = HASH_ALGO_SHA256; + u8 evm_digest[SHA512_DIGEST_SIZE], *evm_digest_ptr; + void *bufp = buf, *bufendp = buf + size; + struct compact_list_hdr hdr, *hdrp; + int ret, i, j, count; + + while (bufp < bufendp) { + if (bufp + sizeof(hdr) > bufendp) { + pr_err("compact list, invalid data\n"); + return -EINVAL; + } + + hdrp = bufp; + memcpy(&hdr, hdrp, sizeof(hdr)); + + if (hdr.version != 2) { + pr_err("compact list, unsupported version\n"); + return -EINVAL; + } + + if (ima_canonical_fmt) { + hdr.type = le16_to_cpu(hdr.type); + hdr.modifiers = le16_to_cpu(hdr.modifiers); + hdr.algo = le16_to_cpu(hdr.algo); + hdr.count = le32_to_cpu(hdr.count); + hdr.datalen = le32_to_cpu(hdr.datalen); + } + + if (hdr.algo >= HASH_ALGO__LAST) + return -EINVAL; + + if (hdr.type >= COMPACT__LAST) { + pr_err("TLV compact list, invalid type %d\n", + hdr.type); + return -EINVAL; + } + + bufp += sizeof(hdr); + + for (i = 0; i < hdr.count; i++) { + if (bufp + sizeof(u8) > bufendp) { + pr_err("TLV compact list, invalid data\n"); + return -EINVAL; + } + + for (j = 0; j < ID__LAST; j++) + items[j] = NULL; + + count = *(u8 *)bufp++; + + for (j = 0; j < count; j++) { + if (bufp + sizeof(**items) > bufendp) { + pr_err("TLV compact list, " + "invalid data\n"); + return -EINVAL; + } + + item_ptr = (struct _tlv_item *)bufp; + if (item_ptr->id >= ID__LAST) { + pr_err("TLV compact list, " + "invalid data\n"); + return -EINVAL; + } + + bufp += sizeof(*item_ptr); + + len = item_ptr->len; + if (ima_canonical_fmt) + len = le32_to_cpu(len); + + items[item_ptr->id] = item_ptr; + + if (bufp + len > bufendp) { + pr_err("TLV compact list, " + "invalid data\n"); + return -EINVAL; + } + + bufp += len; + } + + modifiers = hdr.modifiers; + + for (j = 0; j < 4; j++) { + if (!items_data(ID_INODE_UID + j)) + continue; + + i_meta[j] = + *(u32 *)items_data(ID_INODE_UID + j); + if (ima_canonical_fmt) + i_meta[j] = le32_to_cpu(i_meta[j]); + } + + if (((i_meta[2] & S_IXUGO) || !(i_meta[2] & S_IWUGO)) && + i_meta[3]) + modifiers |= (1 << COMPACT_MOD_IMMUTABLE); + + if (items_data(ID_FSMAGIC)) { + fs_magic = *(u64 *)items_data(ID_FSMAGIC); + if (ima_canonical_fmt) + fs_magic = le64_to_cpu(fs_magic); + } + + ret = 0; + + switch (op) { + case PARSER_OP_ADD_DIGEST: + ret = add_digest(fd, head, hdr.type, + modifiers, hdr.algo, + items_data(ID_DIGEST)); + break; + case PARSER_OP_ADD_DIGEST_TO_HTABLE: + ret = ima_add_digest_data_entry_kernel( + items_data(ID_DIGEST), + hdr.algo, hdr.type, + modifiers); + if (ret == -EEXIST) + ret = 0; + break; + case PARSER_OP_ADD_META_DIGEST: + case PARSER_OP_ADD_META_DIGEST_TO_HTABLE: + if (!items_data(ID_EVM_DIGEST)) { + ret = calc_metadata_digest(fd, head, + hdr.type, modifiers, + hdr.algo, items_data(ID_DIGEST), + evm_digest, + (char *)items_data(ID_PATH), + i_meta[0], i_meta[1], i_meta[2], + (char *)items_data(ID_OBJ_LABEL), + (char *)items_data(ID_CAPS)); + if (ret < 0) + break; + + evm_digest_ptr = evm_digest; + } else { + evm_digest_ptr = + items_data(ID_EVM_DIGEST); + } + + if (items_data(ID_EVM_DIGEST)) { + memcpy(items[ID_EVM_DIGEST]->data, + evm_digest, + hash_digest_size[evm_algo]); + break; + } + + if (op == PARSER_OP_ADD_META_DIGEST_TO_HTABLE) { + ret = ima_add_digest_data_entry_kernel( + evm_digest_ptr, + HASH_ALGO_SHA256, + COMPACT_METADATA, 0); + if (ret == -EEXIST) + ret = 0; + + break; + } + + ret = add_metadata_digest(fd, head, modifiers, + evm_digest_ptr); + break; + case PARSER_OP_ADD_IMA_XATTR: + if (fs_magic == TMPFS_MAGIC) + break; + + ret = add_ima_xattr(fd, head, hdr.type, + modifiers, hdr.algo, + items_data(ID_DIGEST), + (char *)items_data(ID_PATH)); + break; + case PARSER_OP_REMOVE_IMA_XATTR: + if (fs_magic == TMPFS_MAGIC) + break; + + removexattr((char *)items_data(ID_PATH), + XATTR_NAME_IMA); + break; + case PARSER_OP_ADD_EVM_XATTR: + write_evm_xattr((char *)items_data(ID_PATH), + hdr.algo); + break; + case PARSER_OP_REMOVE_EVM_XATTR: + if (fs_magic == TMPFS_MAGIC) + break; + + removexattr((char *)items_data(ID_PATH), + XATTR_NAME_EVM); + break; + case PARSER_OP_REMOVE_INFOFLOW_XATTR: + if (fs_magic == TMPFS_MAGIC) + break; + + removexattr((char *)items_data(ID_PATH), + "security.infoflow"); + break; + case PARSER_OP_DUMP: + compact_list_tlv_dump_items(items); + break; + case PARSER_OP_CHECK_META: + case PARSER_OP_REPAIR_META: + check_repair_xattr((char *)items_data(ID_PATH), + XATTR_NAME_SELINUX, + items_data(ID_OBJ_LABEL), + items_data_len(ID_OBJ_LABEL), + hdr.algo, modifiers, + (op == PARSER_OP_REPAIR_META)); + + check_repair_xattr((char *)items_data(ID_PATH), + XATTR_NAME_IMA, + items_data(ID_DIGEST), + items_data_len(ID_DIGEST), + hdr.algo, modifiers, + (op == PARSER_OP_REPAIR_META)); + + check_repair_xattr((char *)items_data(ID_PATH), + XATTR_NAME_CAPS, + items_data(ID_CAPS), + items_data_len(ID_CAPS), + hdr.algo, modifiers, + (op == PARSER_OP_REPAIR_META)); + + check_repair_attr((char *)items_data(ID_PATH), + i_meta[0], i_meta[1], i_meta[2], + (op == PARSER_OP_REPAIR_META)); + ret = 0; + break; + default: + ret = -ENOTSUP; + break; + } + + if (ret < 0) + return ret; + } + + if (i != hdr.count || + bufp != (void *)hdrp + sizeof(hdr) + hdr.datalen) { + pr_err("compact list, invalid data\n"); + return -EINVAL; + } + } + + return 0; } diff --git a/parsers/rpm.c b/parsers/rpm.c index e344e30..9890074 100644 --- a/parsers/rpm.c +++ b/parsers/rpm.c @@ -23,259 +23,259 @@ #include "xattr.h" struct rpm_hdr { - u32 magic; - u32 reserved; - u32 tags; - u32 datasize; + u32 magic; + u32 reserved; + u32 tags; + u32 datasize; } __attribute__((packed)); struct rpm_entryinfo { - int32_t tag; - u32 type; - int32_t offset; - u32 count; + int32_t tag; + u32 type; + int32_t offset; + u32 count; } __attribute__((packed)); int parser(int fd, struct list_head *head, loff_t buf_size, void *buf, - enum parser_ops op) + enum parser_ops op) { - void *bufp = buf, *bufendp = buf + buf_size; - struct rpm_hdr *hdr = bufp; - u32 tags = be32_to_cpu(hdr->tags); - struct rpm_entryinfo *entry; - void *datap = bufp + sizeof(*hdr) + tags * sizeof(struct rpm_entryinfo); - void *sizes = NULL, *modes = NULL, *digests = NULL, *algo_buf = NULL; - void *dirnames = NULL, *basenames = NULL, *dirindexes = NULL; - void *filecaps = NULL, *digests_ptr; - char **dirnames_ptr = NULL, *filecaps_ptr = NULL; - u32 sizes_count = 0, modes_count = 0, digests_count = 0; - u32 dirnames_count = 0; - u16 algo = HASH_ALGO_MD5; - u8 digest[SHA512_DIGEST_SIZE]; - u8 evm_digest[SHA512_DIGEST_SIZE]; - char path[PATH_MAX]; - int ret = 0, i; - - const unsigned char rpm_header_magic[8] = { - 0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00 - }; - - if (buf_size < sizeof(*hdr)) { - pr_err("Missing RPM header\n"); - return -EINVAL; - } - - if (memcmp(bufp, rpm_header_magic, sizeof(rpm_header_magic))) { - pr_err("Invalid RPM header\n"); - return -EINVAL; - } - - bufp += sizeof(*hdr); - - for (i = 0; i < tags && (bufp + sizeof(*entry)) <= bufendp; - i++, bufp += sizeof(*entry)) { - entry = bufp; - - switch (be32_to_cpu(entry->tag)) { - case RPMTAG_FILESIZES: - sizes = datap + be32_to_cpu(entry->offset); - sizes_count = be32_to_cpu(entry->count); - break; - case RPMTAG_FILEMODES: - modes = datap + be32_to_cpu(entry->offset); - modes_count = be32_to_cpu(entry->count); - break; - case RPMTAG_FILEDIGESTS: - digests = datap + be32_to_cpu(entry->offset); - digests_count = be32_to_cpu(entry->count); - break; - case RPMTAG_FILEDIGESTALGO: - algo_buf = datap + be32_to_cpu(entry->offset); - break; - case RPMTAG_DIRNAMES: - dirnames = datap + be32_to_cpu(entry->offset); - dirnames_count = be32_to_cpu(entry->count); - break; - case RPMTAG_BASENAMES: - basenames = datap + be32_to_cpu(entry->offset); - break; - case RPMTAG_DIRINDEXES: - dirindexes = datap + be32_to_cpu(entry->offset); - break; - case RPMTAG_FILECAPS: - filecaps = datap + be32_to_cpu(entry->offset); - break; - } - - if (sizes && modes && digests && algo_buf && dirnames && - basenames && dirindexes && filecaps) - break; - } - - if (!digests || !sizes || !modes || !dirnames || !basenames || - !dirindexes) - return 0; - - dirnames_ptr = malloc(sizeof(*dirnames_ptr) * dirnames_count); - if (!dirnames_ptr) - return -ENOMEM; - - for (i = 0; i < dirnames_count && dirnames < bufendp; i++) { - dirnames_ptr[i] = dirnames; - dirnames += strlen(dirnames) + 1; - } - - if (i < dirnames_count) { - ret = -EINVAL; - goto out; - } - - if (algo_buf && algo_buf + sizeof(u32) <= bufendp) - algo = pgp_algo_mapping[be32_to_cpu(*(u32 *)algo_buf)]; - - for (i = 0; i < digests_count && digests < bufendp; i++) { - u16 modifiers = 0; - int digest_str_len = strlen(digests); - int basename_str_len = strlen(basenames); - int filecaps_str_len = filecaps ? strlen(filecaps) : 0; - char *obj_label; - u16 mode = 0; - u32 size = 0; - u32 dirindex = 0; - - if ((sizes && (i >= sizes_count || - sizes + (i + 1) * sizeof(size) > bufendp)) || - (modes && (i >= modes_count || - modes + (i + 1) * sizeof(mode) > bufendp)) || - (basenames && - basenames + basename_str_len + 1 > bufendp) || - (dirindexes && - dirindexes + (i + 1) * sizeof(dirindex) > bufendp) || - (filecaps + filecaps_str_len + 1 > bufendp) || - (digests + digest_str_len * 2 + 1 > bufendp)) { - pr_err("RPM header read at invalid offset\n"); - ret = -EINVAL; - goto out; - } - - if (!digest_str_len) { - digests += digest_str_len + 1; - basenames += basename_str_len + 1; - if (filecaps) - filecaps += filecaps_str_len + 1; - continue; - } - - size = be32_to_cpu(*(u32 *)(sizes + i * sizeof(size))); - mode = be16_to_cpu(*(u16 *)(modes + i * sizeof(mode))); - if (((mode & S_IXUGO) || !(mode & S_IWUGO)) && size) - modifiers = (1 << COMPACT_MOD_IMMUTABLE); - - digests_ptr = digests; - digests += digest_str_len + 1; - dirindex = be32_to_cpu(*(u32 *) - (dirindexes + i * sizeof(dirindex))); - - snprintf(path, sizeof(path), "%s%s", dirnames_ptr[dirindex], - (char *)basenames); - - basenames += basename_str_len + 1; - - if (filecaps) { - filecaps_ptr = filecaps; - filecaps += filecaps_str_len + 1; - } - - ret = hex2bin(digest, digests_ptr, digest_str_len / 2); - if (ret < 0) - goto out; - - ret = 0; - - switch (op) { - case PARSER_OP_ADD_DIGEST: - ret = add_digest(fd, head, COMPACT_FILE, modifiers, - algo, digest); - break; - case PARSER_OP_ADD_DIGEST_TO_HTABLE: - ret = ima_add_digest_data_entry_kernel(digest, algo, - COMPACT_FILE, - modifiers); - if (ret == -EEXIST) - ret = 0; - break; - case PARSER_OP_ADD_META_DIGEST: - case PARSER_OP_ADD_META_DIGEST_TO_HTABLE: - ret = get_selinux_label(path, NULL, &obj_label, mode); - if (ret < 0) - break; - - ret = calc_metadata_digest(fd, head, - COMPACT_FILE, modifiers, algo, - digest, evm_digest, path, 0, 0, mode, - obj_label, filecaps_str_len ? - filecaps_ptr : NULL); - - free(obj_label); - - if (ret < 0) - break; - - if (op == PARSER_OP_ADD_META_DIGEST_TO_HTABLE) { - ret = ima_add_digest_data_entry_kernel( - evm_digest, HASH_ALGO_SHA256, - COMPACT_METADATA, 0); - if (ret == -EEXIST) - ret = 0; - - break; - } - - ret = add_metadata_digest(fd, head, modifiers, - evm_digest); - break; - case PARSER_OP_ADD_IMA_XATTR: - ret = add_ima_xattr(fd, head, COMPACT_FILE, modifiers, - algo, digest, path); - break; - case PARSER_OP_REMOVE_IMA_XATTR: - removexattr(path, XATTR_NAME_IMA); - break; - case PARSER_OP_ADD_EVM_XATTR: - write_evm_xattr(path, algo); - break; - case PARSER_OP_REMOVE_EVM_XATTR: - removexattr(path, XATTR_NAME_EVM); - break; - case PARSER_OP_REMOVE_INFOFLOW_XATTR: - removexattr(path, "security.infoflow"); - break; - case PARSER_OP_DUMP: - break; - case PARSER_OP_CHECK_META: - case PARSER_OP_REPAIR_META: - check_repair_xattr(path, XATTR_NAME_IMA, digest, - digest_str_len / 2, algo, modifiers, - (op == PARSER_OP_REPAIR_META)); - - check_repair_xattr(path, XATTR_NAME_CAPS, filecaps_ptr, - filecaps_str_len, algo, modifiers, - (op == PARSER_OP_REPAIR_META)); - - check_repair_attr(path, 0, 0, mode, - (op == PARSER_OP_REPAIR_META)); - ret = 0; - break; - default: - ret = -ENOTSUP; - break; - } - - if (ret < 0) - return ret; - } + void *bufp = buf, *bufendp = buf + buf_size; + struct rpm_hdr *hdr = bufp; + u32 tags = be32_to_cpu(hdr->tags); + struct rpm_entryinfo *entry; + void *datap = bufp + sizeof(*hdr) + tags * sizeof(struct rpm_entryinfo); + void *sizes = NULL, *modes = NULL, *digests = NULL, *algo_buf = NULL; + void *dirnames = NULL, *basenames = NULL, *dirindexes = NULL; + void *filecaps = NULL, *digests_ptr; + char **dirnames_ptr = NULL, *filecaps_ptr = NULL; + u32 sizes_count = 0, modes_count = 0, digests_count = 0; + u32 dirnames_count = 0; + u16 algo = HASH_ALGO_MD5; + u8 digest[SHA512_DIGEST_SIZE]; + u8 evm_digest[SHA512_DIGEST_SIZE]; + char path[PATH_MAX]; + int ret = 0, i; + + const unsigned char rpm_header_magic[8] = { + 0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00 + }; + + if (buf_size < sizeof(*hdr)) { + pr_err("Missing RPM header\n"); + return -EINVAL; + } + + if (memcmp(bufp, rpm_header_magic, sizeof(rpm_header_magic))) { + pr_err("Invalid RPM header\n"); + return -EINVAL; + } + + bufp += sizeof(*hdr); + + for (i = 0; i < tags && (bufp + sizeof(*entry)) <= bufendp; + i++, bufp += sizeof(*entry)) { + entry = bufp; + + switch (be32_to_cpu(entry->tag)) { + case RPMTAG_FILESIZES: + sizes = datap + be32_to_cpu(entry->offset); + sizes_count = be32_to_cpu(entry->count); + break; + case RPMTAG_FILEMODES: + modes = datap + be32_to_cpu(entry->offset); + modes_count = be32_to_cpu(entry->count); + break; + case RPMTAG_FILEDIGESTS: + digests = datap + be32_to_cpu(entry->offset); + digests_count = be32_to_cpu(entry->count); + break; + case RPMTAG_FILEDIGESTALGO: + algo_buf = datap + be32_to_cpu(entry->offset); + break; + case RPMTAG_DIRNAMES: + dirnames = datap + be32_to_cpu(entry->offset); + dirnames_count = be32_to_cpu(entry->count); + break; + case RPMTAG_BASENAMES: + basenames = datap + be32_to_cpu(entry->offset); + break; + case RPMTAG_DIRINDEXES: + dirindexes = datap + be32_to_cpu(entry->offset); + break; + case RPMTAG_FILECAPS: + filecaps = datap + be32_to_cpu(entry->offset); + break; + } + + if (sizes && modes && digests && algo_buf && dirnames && + basenames && dirindexes && filecaps) + break; + } + + if (!digests || !sizes || !modes || !dirnames || !basenames || + !dirindexes) + return 0; + + dirnames_ptr = malloc(sizeof(*dirnames_ptr) * dirnames_count); + if (!dirnames_ptr) + return -ENOMEM; + + for (i = 0; i < dirnames_count && dirnames < bufendp; i++) { + dirnames_ptr[i] = dirnames; + dirnames += strlen(dirnames) + 1; + } + + if (i < dirnames_count) { + ret = -EINVAL; + goto out; + } + + if (algo_buf && algo_buf + sizeof(u32) <= bufendp) + algo = pgp_algo_mapping[be32_to_cpu(*(u32 *)algo_buf)]; + + for (i = 0; i < digests_count && digests < bufendp; i++) { + u16 modifiers = 0; + int digest_str_len = strlen(digests); + int basename_str_len = strlen(basenames); + int filecaps_str_len = filecaps ? strlen(filecaps) : 0; + char *obj_label; + u16 mode = 0; + u32 size = 0; + u32 dirindex = 0; + + if ((sizes && (i >= sizes_count || + sizes + (i + 1) * sizeof(size) > bufendp)) || + (modes && (i >= modes_count || + modes + (i + 1) * sizeof(mode) > bufendp)) || + (basenames && + basenames + basename_str_len + 1 > bufendp) || + (dirindexes && + dirindexes + (i + 1) * sizeof(dirindex) > bufendp) || + (filecaps + filecaps_str_len + 1 > bufendp) || + (digests + digest_str_len * 2 + 1 > bufendp)) { + pr_err("RPM header read at invalid offset\n"); + ret = -EINVAL; + goto out; + } + + if (!digest_str_len) { + digests += digest_str_len + 1; + basenames += basename_str_len + 1; + if (filecaps) + filecaps += filecaps_str_len + 1; + continue; + } + + size = be32_to_cpu(*(u32 *)(sizes + i * sizeof(size))); + mode = be16_to_cpu(*(u16 *)(modes + i * sizeof(mode))); + if (((mode & S_IXUGO) || !(mode & S_IWUGO)) && size) + modifiers = (1 << COMPACT_MOD_IMMUTABLE); + + digests_ptr = digests; + digests += digest_str_len + 1; + dirindex = be32_to_cpu(*(u32 *) + (dirindexes + i * sizeof(dirindex))); + + snprintf(path, sizeof(path), "%s%s", dirnames_ptr[dirindex], + (char *)basenames); + + basenames += basename_str_len + 1; + + if (filecaps) { + filecaps_ptr = filecaps; + filecaps += filecaps_str_len + 1; + } + + ret = hex2bin(digest, digests_ptr, digest_str_len / 2); + if (ret < 0) + goto out; + + ret = 0; + + switch (op) { + case PARSER_OP_ADD_DIGEST: + ret = add_digest(fd, head, COMPACT_FILE, modifiers, + algo, digest); + break; + case PARSER_OP_ADD_DIGEST_TO_HTABLE: + ret = ima_add_digest_data_entry_kernel(digest, algo, + COMPACT_FILE, + modifiers); + if (ret == -EEXIST) + ret = 0; + break; + case PARSER_OP_ADD_META_DIGEST: + case PARSER_OP_ADD_META_DIGEST_TO_HTABLE: + ret = get_selinux_label(path, NULL, &obj_label, mode); + if (ret < 0) + break; + + ret = calc_metadata_digest(fd, head, + COMPACT_FILE, modifiers, algo, + digest, evm_digest, path, 0, 0, mode, + obj_label, filecaps_str_len ? + filecaps_ptr : NULL); + + free(obj_label); + + if (ret < 0) + break; + + if (op == PARSER_OP_ADD_META_DIGEST_TO_HTABLE) { + ret = ima_add_digest_data_entry_kernel( + evm_digest, HASH_ALGO_SHA256, + COMPACT_METADATA, 0); + if (ret == -EEXIST) + ret = 0; + + break; + } + + ret = add_metadata_digest(fd, head, modifiers, + evm_digest); + break; + case PARSER_OP_ADD_IMA_XATTR: + ret = add_ima_xattr(fd, head, COMPACT_FILE, modifiers, + algo, digest, path); + break; + case PARSER_OP_REMOVE_IMA_XATTR: + removexattr(path, XATTR_NAME_IMA); + break; + case PARSER_OP_ADD_EVM_XATTR: + write_evm_xattr(path, algo); + break; + case PARSER_OP_REMOVE_EVM_XATTR: + removexattr(path, XATTR_NAME_EVM); + break; + case PARSER_OP_REMOVE_INFOFLOW_XATTR: + removexattr(path, "security.infoflow"); + break; + case PARSER_OP_DUMP: + break; + case PARSER_OP_CHECK_META: + case PARSER_OP_REPAIR_META: + check_repair_xattr(path, XATTR_NAME_IMA, digest, + digest_str_len / 2, algo, modifiers, + (op == PARSER_OP_REPAIR_META)); + + check_repair_xattr(path, XATTR_NAME_CAPS, filecaps_ptr, + filecaps_str_len, algo, modifiers, + (op == PARSER_OP_REPAIR_META)); + + check_repair_attr(path, 0, 0, mode, + (op == PARSER_OP_REPAIR_META)); + ret = 0; + break; + default: + ret = -ENOTSUP; + break; + } + + if (ret < 0) + return ret; + } out: - free(dirnames_ptr); + free(dirnames_ptr); - return ret; + return ret; } diff --git a/src/gen_digest_lists.c b/src/gen_digest_lists.c index c0e8a1f..581b94c 100644 --- a/src/gen_digest_lists.c +++ b/src/gen_digest_lists.c @@ -40,325 +40,325 @@ enum dir_ops { OP_ADD, OP_APPEND, OP_REMOVE, OP_SIGN, OP__LAST }; /* from evmctl.c */ static char *get_password(char *keypass, int keypass_len) { - struct termios flags, tmp_flags; - char *pwd; + struct termios flags, tmp_flags; + char *pwd; - tcgetattr(fileno(stdin), &flags); - tmp_flags = flags; - tmp_flags.c_lflag &= ~ECHO; - tmp_flags.c_lflag |= ECHONL; + tcgetattr(fileno(stdin), &flags); + tmp_flags = flags; + tmp_flags.c_lflag &= ~ECHO; + tmp_flags.c_lflag |= ECHONL; - if (tcsetattr(fileno(stdin), TCSANOW, &tmp_flags) != 0) { - perror("tcsetattr"); - return NULL; - } + if (tcsetattr(fileno(stdin), TCSANOW, &tmp_flags) != 0) { + perror("tcsetattr"); + return NULL; + } - printf("PEM password: "); - pwd = fgets(keypass, keypass_len, stdin); + printf("PEM password: "); + pwd = fgets(keypass, keypass_len, stdin); - /* restore terminal */ - if (tcsetattr(fileno(stdin), TCSANOW, &flags) != 0) { - perror("tcsetattr"); - return NULL; - } + /* restore terminal */ + if (tcsetattr(fileno(stdin), TCSANOW, &flags) != 0) { + perror("tcsetattr"); + return NULL; + } - return pwd; + return pwd; } static int process_dir(int dirfd, enum dir_ops op, enum compact_types type, - int *pos) + int *pos) { - struct dirent **digest_lists; - char new_filename[NAME_MAX + 1], target[NAME_MAX +1]; - char *cur_filename, *symlink_filename = NULL; - int ret = 0, i, n, index; - - n = scandirat(dirfd, ".", &digest_lists, filter_parser_list_symlink, - NULL); - if (n != -1) { - if (n == 1) { - ret = readlinkat(dirfd, digest_lists[0]->d_name, target, - sizeof(target) - 1); - if (ret < 0) { - printf("Cannot read symlink %s\n", - digest_lists[0]->d_name); - goto out; - } - - target[ret] = '\0'; - - symlink_filename = strdup(digest_lists[0]->d_name); - if (!symlink_filename) { - printf("Out of memory\n"); - ret = -ENOMEM; - goto out; - } - - free(digest_lists[0]); - } - - free(digest_lists); - } - - n = scandirat(dirfd, ".", &digest_lists, filter[type], - compare_lists); - if (n == -1) { - printf("Unable to access digest lists\n"); - return -EACCES; - } - - if (op == OP_APPEND) { - *pos = n; - goto out; - } - - for (i = 0; i < n; i++) { - index = (op == OP_ADD) ? n - 1 - i : i; - cur_filename = digest_lists[index]->d_name; - - if (op == OP_REMOVE && (*pos == -1 || index == *pos)) { - unlinkat(dirfd, cur_filename, 0); - if (symlink_filename && !strcmp(cur_filename, target)) - unlinkat(dirfd, symlink_filename, 0); - continue; - } - - if (i < *pos) - continue; - - snprintf(new_filename, sizeof(new_filename), "%d%s", - (op == OP_ADD) ? index + 1 : index - 1, - strchr(cur_filename, '-')); - renameat(dirfd, cur_filename, dirfd, new_filename); - - if (symlink_filename && !strcmp(cur_filename, target)) { - unlinkat(dirfd, symlink_filename, 0); - ret = symlinkat(new_filename, dirfd, symlink_filename); - if (ret < 0) - printf("Cannot create symbolic link\n"); - } - } + struct dirent **digest_lists; + char new_filename[NAME_MAX + 1], target[NAME_MAX +1]; + char *cur_filename, *symlink_filename = NULL; + int ret = 0, i, n, index; + + n = scandirat(dirfd, ".", &digest_lists, filter_parser_list_symlink, + NULL); + if (n != -1) { + if (n == 1) { + ret = readlinkat(dirfd, digest_lists[0]->d_name, target, + sizeof(target) - 1); + if (ret < 0) { + printf("Cannot read symlink %s\n", + digest_lists[0]->d_name); + goto out; + } + + target[ret] = '\0'; + + symlink_filename = strdup(digest_lists[0]->d_name); + if (!symlink_filename) { + printf("Out of memory\n"); + ret = -ENOMEM; + goto out; + } + + free(digest_lists[0]); + } + + free(digest_lists); + } + + n = scandirat(dirfd, ".", &digest_lists, filter[type], + compare_lists); + if (n == -1) { + printf("Unable to access digest lists\n"); + return -EACCES; + } + + if (op == OP_APPEND) { + *pos = n; + goto out; + } + + for (i = 0; i < n; i++) { + index = (op == OP_ADD) ? n - 1 - i : i; + cur_filename = digest_lists[index]->d_name; + + if (op == OP_REMOVE && (*pos == -1 || index == *pos)) { + unlinkat(dirfd, cur_filename, 0); + if (symlink_filename && !strcmp(cur_filename, target)) + unlinkat(dirfd, symlink_filename, 0); + continue; + } + + if (i < *pos) + continue; + + snprintf(new_filename, sizeof(new_filename), "%d%s", + (op == OP_ADD) ? index + 1 : index - 1, + strchr(cur_filename, '-')); + renameat(dirfd, cur_filename, dirfd, new_filename); + + if (symlink_filename && !strcmp(cur_filename, target)) { + unlinkat(dirfd, symlink_filename, 0); + ret = symlinkat(new_filename, dirfd, symlink_filename); + if (ret < 0) + printf("Cannot create symbolic link\n"); + } + } out: - for (i = 0; i < n; i++) - free(digest_lists[i]); + for (i = 0; i < n; i++) + free(digest_lists[i]); - free(digest_lists); - free(symlink_filename); + free(digest_lists); + free(symlink_filename); - return ret; + return ret; } static void usage(char *progname) { - printf("Usage: %s \n", progname); - printf("Options:\n"); - printf("\t-d : directory containing digest lists\n" - "\t-f : format of the input file, " - "syntax: +\n" - "\t-i : path of the input file\n" - "\t-o : operation to do\n" - "\t\t-add: insert a new digest list at the position specified\n" - "\t\t-append: add a new digest list after the existing ones\n" - "\t\t-remove: remove a digest list at the position specified\n" - "\t\t-sign: sign a digest list\n" - "\t-p : position in the directory to add/remove\n" - "\t-t : type of compact list to generate\n" - "\t-T: generate a TLV compact list\n" - "\t-m : compact list modifiers separated by comma\n" - "\t-a : digest list hash algorithm\n" - "\t-I : IMA hash algorithm\n" - "\t-s: sign generated digest lists\n" - "\t-k : key to sign\n" - "\t-w []: key password (- for prompt)\n" - "\t-A : alternative root for SELinux labeling\n" - "\t-h: display help\n"); + printf("Usage: %s \n", progname); + printf("Options:\n"); + printf("\t-d : directory containing digest lists\n" + "\t-f : format of the input file, " + "syntax: +\n" + "\t-i : path of the input file\n" + "\t-o : operation to do\n" + "\t\t-add: insert a new digest list at the position specified\n" + "\t\t-append: add a new digest list after the existing ones\n" + "\t\t-remove: remove a digest list at the position specified\n" + "\t\t-sign: sign a digest list\n" + "\t-p : position in the directory to add/remove\n" + "\t-t : type of compact list to generate\n" + "\t-T: generate a TLV compact list\n" + "\t-m : compact list modifiers separated by comma\n" + "\t-a : digest list hash algorithm\n" + "\t-I : IMA hash algorithm\n" + "\t-s: sign generated digest lists\n" + "\t-k : key to sign\n" + "\t-w []: key password (- for prompt)\n" + "\t-A : alternative root for SELinux labeling\n" + "\t-h: display help\n"); } int main(int argc, char **argv) { - char *cur_dir = DEFAULT_DIR, *input_fmt = NULL, *alt_root = NULL; - char *modifiers_opt, *modifiers_ptr, *modifiers_str; - char keypass[64], *keypass_ptr = keypass, *key_path = NULL; - enum dir_ops op = OP__LAST; - enum compact_types type = COMPACT__LAST; - enum hash_algo algo = HASH_ALGO_SHA256; - enum hash_algo ima_algo = HASH_ALGO_SHA256; - LIST_HEAD(generator_lib_head); - LIST_HEAD(head_in); - LIST_HEAD(head_out); - struct lib *generator; - bool tlv = false; - int ret = -EINVAL, c, i, dirfd, sign = 0, pos = -1, modifiers = 0; - - while ((c = getopt(argc, argv, "d:f:i:o:p:t:Tm:a:I:sk:w:A:h")) != -1) { - switch (c) { - case 'd': - cur_dir = optarg; - break; - case 'f': - input_fmt = optarg; - break; - case 'i': - if (add_path_struct(optarg, NULL, &head_in) < 0) - goto out; - break; - case 'o': - if (strcmp(optarg, "add") == 0) { - op = OP_ADD; - } else if (strcmp(optarg, "append") == 0) { - op = OP_APPEND; - } else if (strcmp(optarg, "remove") == 0) { - op = OP_REMOVE; - } else if (strcmp(optarg, "sign") == 0) { - op = OP_SIGN; - sign = 1; - } else { - printf("Invalid operation %s\n", optarg); - goto out; - } - break; - case 'p': - pos = strtol(optarg, NULL, 10); - break; - case 't': - for (i = 0; i < COMPACT__LAST; i++) - if (!strcmp(optarg, compact_types_str[i])) - break; - if (i == COMPACT__LAST) { - printf("Unknown compact type %s\n", optarg); - goto out; - } - type = i; - break; - case 'T': - tlv = true; - break; - case 'm': - modifiers_ptr = modifiers_opt = strdup(optarg); - while ((modifiers_str = strsep(&modifiers_ptr, ","))) { - for (i = 0; i < COMPACT_MOD__LAST; i++) { - if (!strcmp(modifiers_str, - compact_modifiers_str[i])) { - modifiers |= (1 << i); - break; - } - } - } - free(modifiers_opt); - break; - case 'a': - case 'I': - for (i = 0; i < HASH_ALGO__LAST; i++) - if (!strcmp(optarg, hash_algo_name[i])) - break; - if (i == HASH_ALGO__LAST) { - printf("Unknown hash algorithm %s\n", optarg); - goto out; - } - if (c == 'I') - ima_algo = i; - else - algo = i; - break; - case 's': - sign = 1; - break; - case 'k': - key_path = optarg; - break; - case 'w': - if (optarg[0] != '-') - keypass_ptr = optarg; - else - keypass_ptr = get_password(keypass, - sizeof(keypass)); - break; - case 'A': - alt_root = optarg; - break; - case 'h': - usage(argv[0]); - return -EINVAL; - default: - printf("Unknown option %c\n", optopt); - return -EINVAL; - } - } - - ret = -EINVAL; - - if (op == OP__LAST) { - printf("Operation not specified\n"); - goto out; - } - - if ((op != OP_SIGN || list_empty(&head_in)) && type == COMPACT__LAST) { - printf("Compact type not specified\n"); - goto out; - } - - if (op != OP_SIGN && op != OP_REMOVE && !input_fmt) { - printf("Input format not specified\n"); - goto out; - } - - if (sign && !key_path) { - printf("Key path not specified\n"); - goto out; - } - - dirfd = open(cur_dir, O_RDONLY | O_DIRECTORY); - if (dirfd < 0) { - printf("Unable to open %s, ret: %d\n", cur_dir, dirfd); - ret = dirfd; - goto out; - } - - if (op == OP_SIGN) { - if (!list_empty(&head_in)) { - move_path_structs(&head_out, &head_in); - } else { - ret = get_digest_lists(dirfd, type, &head_out); - if (ret < 0) - goto out; - } - - goto out_sign; - } - - if (op != OP_ADD || pos != -1) - ret = process_dir(dirfd, op, type, &pos); - - if (op == OP_REMOVE) - goto out_close; - - generator = lookup_lib(&generator_lib_head, "generator", input_fmt, - strlen(input_fmt)); - if (!generator) { - printf("Unable to find generator for %s\n", input_fmt); - goto out_close; - } - - if (type != COMPACT_FILE) - modifiers |= COMPACT_MOD_IMMUTABLE; - - ret = ((generator_func)generator->func)(dirfd, pos, &head_in, &head_out, - type, modifiers, algo, ima_algo, - tlv, alt_root); - if (ret < 0) { - printf("Generator %s returned %d\n", input_fmt, ret); - goto out_free; - } + char *cur_dir = DEFAULT_DIR, *input_fmt = NULL, *alt_root = NULL; + char *modifiers_opt, *modifiers_ptr, *modifiers_str; + char keypass[64], *keypass_ptr = keypass, *key_path = NULL; + enum dir_ops op = OP__LAST; + enum compact_types type = COMPACT__LAST; + enum hash_algo algo = HASH_ALGO_SHA256; + enum hash_algo ima_algo = HASH_ALGO_SHA256; + LIST_HEAD(generator_lib_head); + LIST_HEAD(head_in); + LIST_HEAD(head_out); + struct lib *generator; + bool tlv = false; + int ret = -EINVAL, c, i, dirfd, sign = 0, pos = -1, modifiers = 0; + + while ((c = getopt(argc, argv, "d:f:i:o:p:t:Tm:a:I:sk:w:A:h")) != -1) { + switch (c) { + case 'd': + cur_dir = optarg; + break; + case 'f': + input_fmt = optarg; + break; + case 'i': + if (add_path_struct(optarg, NULL, &head_in) < 0) + goto out; + break; + case 'o': + if (strcmp(optarg, "add") == 0) { + op = OP_ADD; + } else if (strcmp(optarg, "append") == 0) { + op = OP_APPEND; + } else if (strcmp(optarg, "remove") == 0) { + op = OP_REMOVE; + } else if (strcmp(optarg, "sign") == 0) { + op = OP_SIGN; + sign = 1; + } else { + printf("Invalid operation %s\n", optarg); + goto out; + } + break; + case 'p': + pos = strtol(optarg, NULL, 10); + break; + case 't': + for (i = 0; i < COMPACT__LAST; i++) + if (!strcmp(optarg, compact_types_str[i])) + break; + if (i == COMPACT__LAST) { + printf("Unknown compact type %s\n", optarg); + goto out; + } + type = i; + break; + case 'T': + tlv = true; + break; + case 'm': + modifiers_ptr = modifiers_opt = strdup(optarg); + while ((modifiers_str = strsep(&modifiers_ptr, ","))) { + for (i = 0; i < COMPACT_MOD__LAST; i++) { + if (!strcmp(modifiers_str, + compact_modifiers_str[i])) { + modifiers |= (1 << i); + break; + } + } + } + free(modifiers_opt); + break; + case 'a': + case 'I': + for (i = 0; i < HASH_ALGO__LAST; i++) + if (!strcmp(optarg, hash_algo_name[i])) + break; + if (i == HASH_ALGO__LAST) { + printf("Unknown hash algorithm %s\n", optarg); + goto out; + } + if (c == 'I') + ima_algo = i; + else + algo = i; + break; + case 's': + sign = 1; + break; + case 'k': + key_path = optarg; + break; + case 'w': + if (optarg[0] != '-') + keypass_ptr = optarg; + else + keypass_ptr = get_password(keypass, + sizeof(keypass)); + break; + case 'A': + alt_root = optarg; + break; + case 'h': + usage(argv[0]); + return -EINVAL; + default: + printf("Unknown option %c\n", optopt); + return -EINVAL; + } + } + + ret = -EINVAL; + + if (op == OP__LAST) { + printf("Operation not specified\n"); + goto out; + } + + if ((op != OP_SIGN || list_empty(&head_in)) && type == COMPACT__LAST) { + printf("Compact type not specified\n"); + goto out; + } + + if (op != OP_SIGN && op != OP_REMOVE && !input_fmt) { + printf("Input format not specified\n"); + goto out; + } + + if (sign && !key_path) { + printf("Key path not specified\n"); + goto out; + } + + dirfd = open(cur_dir, O_RDONLY | O_DIRECTORY); + if (dirfd < 0) { + printf("Unable to open %s, ret: %d\n", cur_dir, dirfd); + ret = dirfd; + goto out; + } + + if (op == OP_SIGN) { + if (!list_empty(&head_in)) { + move_path_structs(&head_out, &head_in); + } else { + ret = get_digest_lists(dirfd, type, &head_out); + if (ret < 0) + goto out; + } + + goto out_sign; + } + + if (op != OP_ADD || pos != -1) + ret = process_dir(dirfd, op, type, &pos); + + if (op == OP_REMOVE) + goto out_close; + + generator = lookup_lib(&generator_lib_head, "generator", input_fmt, + strlen(input_fmt)); + if (!generator) { + printf("Unable to find generator for %s\n", input_fmt); + goto out_close; + } + + if (type != COMPACT_FILE) + modifiers |= COMPACT_MOD_IMMUTABLE; + + ret = ((generator_func)generator->func)(dirfd, pos, &head_in, &head_out, + type, modifiers, algo, ima_algo, + tlv, alt_root); + if (ret < 0) { + printf("Generator %s returned %d\n", input_fmt, ret); + goto out_free; + } out_sign: - if (sign) - ret = sign_files(dirfd, &head_out, key_path, keypass_ptr, algo); + if (sign) + ret = sign_files(dirfd, &head_out, key_path, keypass_ptr, algo); out_free: - free_path_structs(&head_in); - free_path_structs(&head_out); - free_libs(&generator_lib_head); + free_path_structs(&head_in); + free_path_structs(&head_out); + free_libs(&generator_lib_head); out_close: - close(dirfd); + close(dirfd); out: - memset(keypass, 0, sizeof(keypass)); - return ret; + memset(keypass, 0, sizeof(keypass)); + return ret; } diff --git a/src/manage_digest_lists.c b/src/manage_digest_lists.c index 55a8856..522b7af 100644 --- a/src/manage_digest_lists.c +++ b/src/manage_digest_lists.c @@ -37,206 +37,206 @@ static int init_digest_list_upload(int *mount_sysfs, int *mount_securityfs) { - struct stat st; - int ret, fd; + struct stat st; + int ret, fd; - if (!stat(IMA_DIGEST_LIST_DATA_PATH, &st)) - goto out; + if (!stat(IMA_DIGEST_LIST_DATA_PATH, &st)) + goto out; - if (!stat(SECURITYFS_PATH, &st)) - goto mount_securityfs; + if (!stat(SECURITYFS_PATH, &st)) + goto mount_securityfs; - ret = mount(SYSFS_PATH, SYSFS_PATH, "sysfs", MOUNT_FLAGS, NULL); - if (ret < 0) { - printf("Cannot mount %s (%s)\n", SYSFS_PATH, - strerror(errno)); - return ret; - } + ret = mount(SYSFS_PATH, SYSFS_PATH, "sysfs", MOUNT_FLAGS, NULL); + if (ret < 0) { + printf("Cannot mount %s (%s)\n", SYSFS_PATH, + strerror(errno)); + return ret; + } - *mount_sysfs = 1; + *mount_sysfs = 1; mount_securityfs: - ret = mount(SECURITYFS_PATH, SECURITYFS_PATH, "securityfs", MOUNT_FLAGS, - NULL); - if (ret < 0) { - printf("Cannot mount %s (%s)\n", SECURITYFS_PATH, - strerror(errno)); - return ret; - } - - *mount_securityfs = 1; + ret = mount(SECURITYFS_PATH, SECURITYFS_PATH, "securityfs", MOUNT_FLAGS, + NULL); + if (ret < 0) { + printf("Cannot mount %s (%s)\n", SECURITYFS_PATH, + strerror(errno)); + return ret; + } + + *mount_securityfs = 1; out: - fd = open(IMA_DIGEST_LIST_DATA_PATH, O_WRONLY); - if (fd < 0) { - printf("Cannot open %s\n", IMA_DIGEST_LIST_DATA_PATH); - return -EACCES; - } + fd = open(IMA_DIGEST_LIST_DATA_PATH, O_WRONLY); + if (fd < 0) { + printf("Cannot open %s\n", IMA_DIGEST_LIST_DATA_PATH); + return -EACCES; + } - return fd; + return fd; } static void end_digest_list_upload(int umount_sysfs, int umount_securityfs) { - if (umount_securityfs) - umount(SECURITYFS_PATH); - if (umount_sysfs) - umount(SYSFS_PATH); + if (umount_securityfs) + umount(SECURITYFS_PATH); + if (umount_sysfs) + umount(SYSFS_PATH); } static void usage(char *progname) { - printf("Usage: %s \n", progname); - printf("Options:\n"); - printf("\t-d : directory containing digest lists\n" - "\t-f : filename in the digest list directory\n" - "\t-o : write converted digest list to a file\n" - "\t-p : specify parser operation:\n" - "\t\tadd-digest: add IMA digest to kernel/output file\n" - "\t\tadd-meta-digest: add EVM digest to kernel/output file\n" - "\t\tadd-ima-xattr: set IMA xattr for files in the digest lists\n" - "\t\trm-ima-xattr: remove IMA xattr for files in the digest lists\n" - "\t\tadd-evm-xattr: set EVM xattr for files in the digest lists\n" - "\t\trm-evm-xattr: remove EVM xattr for files in the digest lists\n" - "\t\trm-infoflow-xattr: remove Infoflow xattr for files in the digest lists\n" - "\t\tdump: display content of digest lists\n" - "\t\tgen-ima-list: generate IMA digest list with digest list measurement\n" - "\t\tcheck-meta: compare metadata between digest lists and filesystem\n" - "\t\trepair-meta: set metadata from the digest lists to the filesystem\n" - "\t\trepair-meta-digest-lists: set digest lists metadata\n" - "\t-v: verbose mode\n" - "\t-h: display help\n"); + printf("Usage: %s \n", progname); + printf("Options:\n"); + printf("\t-d : directory containing digest lists\n" + "\t-f : filename in the digest list directory\n" + "\t-o : write converted digest list to a file\n" + "\t-p : specify parser operation:\n" + "\t\tadd-digest: add IMA digest to kernel/output file\n" + "\t\tadd-meta-digest: add EVM digest to kernel/output file\n" + "\t\tadd-ima-xattr: set IMA xattr for files in the digest lists\n" + "\t\trm-ima-xattr: remove IMA xattr for files in the digest lists\n" + "\t\tadd-evm-xattr: set EVM xattr for files in the digest lists\n" + "\t\trm-evm-xattr: remove EVM xattr for files in the digest lists\n" + "\t\trm-infoflow-xattr: remove Infoflow xattr for files in the digest lists\n" + "\t\tdump: display content of digest lists\n" + "\t\tgen-ima-list: generate IMA digest list with digest list measurement\n" + "\t\tcheck-meta: compare metadata between digest lists and filesystem\n" + "\t\trepair-meta: set metadata from the digest lists to the filesystem\n" + "\t\trepair-meta-digest-lists: set digest lists metadata\n" + "\t-v: verbose mode\n" + "\t-h: display help\n"); } int main(int argc, char *argv[]) { - int c, i, dirfd, fd = -1, verbose = 0, ret = -EINVAL; - int mount_sysfs = 0, mount_securityfs = 0; - char *cur_dir = DEFAULT_DIR, *output = NULL; - enum parser_ops op = PARSER_OP__LAST; - char *digest_list_filename = NULL; - LIST_HEAD(list_head); - - while ((c = getopt(argc, argv, "d:o:p:f:vh")) != -1) { - switch (c) { - case 'd': - cur_dir = optarg; - break; - case 'f': - digest_list_filename = optarg; - break; - case 'o': - output = optarg; - break; - case 'p': - if (!strcmp(optarg, "add-digest")) { - op = PARSER_OP_ADD_DIGEST; - } else if (!strcmp(optarg, "add-meta-digest")) { - op = PARSER_OP_ADD_META_DIGEST; - } else if (!strcmp(optarg, "add-ima-xattr")) { - op = PARSER_OP_ADD_IMA_XATTR; - fd = -2; - } else if (!strcmp(optarg, "rm-ima-xattr")) { - op = PARSER_OP_REMOVE_IMA_XATTR; - fd = -2; - } else if (!strcmp(optarg, "add-evm-xattr")) { - op = PARSER_OP_ADD_EVM_XATTR; - fd = -2; - } else if (!strcmp(optarg, "rm-evm-xattr")) { - op = PARSER_OP_REMOVE_EVM_XATTR; - fd = -2; - } else if (!strcmp(optarg, "rm-infoflow-xattr")) { - op = PARSER_OP_REMOVE_INFOFLOW_XATTR; - fd = -2; - } else if (!strcmp(optarg, "dump")) { - op = PARSER_OP_DUMP; - fd = -2; - } else if (!strcmp(optarg, "gen-ima-list")) { - op = PARSER_OP_GEN_IMA_LIST; - } else if (!strcmp(optarg, "check-meta")) { - op = PARSER_OP_CHECK_META; - fd = -2; - } else if (!strcmp(optarg, "repair-meta")) { - op = PARSER_OP_REPAIR_META; - fd = -2; - } else if (!strcmp(optarg, - "repair-meta-digest-lists")) { - op = PARSER_OP_REPAIR_META_DIGEST_LISTS; - fd = -2; - } else { - printf("Invalid parser op %s\n", optarg); - return 1; - } - break; - case 'v': - verbose = 1; - break; - case 'h': - usage(argv[0]); - return -EINVAL; - default: - printf("Unknown option %c\n", optopt); - return -EINVAL; - } - } - - if (op == PARSER_OP__LAST) { - printf("Parser operation not specified\n"); - return -EINVAL; - } - - dirfd = open(cur_dir, O_RDONLY | O_DIRECTORY); - if (dirfd < 0) { - printf("Unable to open %s, ret: %d\n", cur_dir, dirfd); - goto out; - } - - if (fd == -1) { - if (!output) - fd = init_digest_list_upload(&mount_sysfs, - &mount_securityfs); - else - fd = open(output, O_WRONLY | O_CREAT | O_TRUNC, 0644); - - if (fd < 0) { - ret = -EACCES; - goto out_close_dirfd; - } - } - - if (op == PARSER_OP_GEN_IMA_LIST) { - ret = ima_copy_boot_aggregate(fd); - if (ret < 0) - return ret; - - ret = ima_generate_entry(-1, fd, "", IMA_KEY_PATH); - if (ret < 0) - return ret; - } - - for (i = 0; i < COMPACT__LAST; i++) { - ret = process_lists(dirfd, fd, (output != NULL), verbose, - &list_head, i, op, cur_dir, - digest_list_filename); - if (ret < 0) { - printf("Cannot upload digest lists, ret: %d\n", ret); - goto out_close_fd; - } - - ret = compact_list_flush_all(fd, &list_head); - if (ret < 0) { - printf("Cannot upload digest lists, ret: %d\n", ret); - goto out_close_fd; - } - } + int c, i, dirfd, fd = -1, verbose = 0, ret = -EINVAL; + int mount_sysfs = 0, mount_securityfs = 0; + char *cur_dir = DEFAULT_DIR, *output = NULL; + enum parser_ops op = PARSER_OP__LAST; + char *digest_list_filename = NULL; + LIST_HEAD(list_head); + + while ((c = getopt(argc, argv, "d:o:p:f:vh")) != -1) { + switch (c) { + case 'd': + cur_dir = optarg; + break; + case 'f': + digest_list_filename = optarg; + break; + case 'o': + output = optarg; + break; + case 'p': + if (!strcmp(optarg, "add-digest")) { + op = PARSER_OP_ADD_DIGEST; + } else if (!strcmp(optarg, "add-meta-digest")) { + op = PARSER_OP_ADD_META_DIGEST; + } else if (!strcmp(optarg, "add-ima-xattr")) { + op = PARSER_OP_ADD_IMA_XATTR; + fd = -2; + } else if (!strcmp(optarg, "rm-ima-xattr")) { + op = PARSER_OP_REMOVE_IMA_XATTR; + fd = -2; + } else if (!strcmp(optarg, "add-evm-xattr")) { + op = PARSER_OP_ADD_EVM_XATTR; + fd = -2; + } else if (!strcmp(optarg, "rm-evm-xattr")) { + op = PARSER_OP_REMOVE_EVM_XATTR; + fd = -2; + } else if (!strcmp(optarg, "rm-infoflow-xattr")) { + op = PARSER_OP_REMOVE_INFOFLOW_XATTR; + fd = -2; + } else if (!strcmp(optarg, "dump")) { + op = PARSER_OP_DUMP; + fd = -2; + } else if (!strcmp(optarg, "gen-ima-list")) { + op = PARSER_OP_GEN_IMA_LIST; + } else if (!strcmp(optarg, "check-meta")) { + op = PARSER_OP_CHECK_META; + fd = -2; + } else if (!strcmp(optarg, "repair-meta")) { + op = PARSER_OP_REPAIR_META; + fd = -2; + } else if (!strcmp(optarg, + "repair-meta-digest-lists")) { + op = PARSER_OP_REPAIR_META_DIGEST_LISTS; + fd = -2; + } else { + printf("Invalid parser op %s\n", optarg); + return 1; + } + break; + case 'v': + verbose = 1; + break; + case 'h': + usage(argv[0]); + return -EINVAL; + default: + printf("Unknown option %c\n", optopt); + return -EINVAL; + } + } + + if (op == PARSER_OP__LAST) { + printf("Parser operation not specified\n"); + return -EINVAL; + } + + dirfd = open(cur_dir, O_RDONLY | O_DIRECTORY); + if (dirfd < 0) { + printf("Unable to open %s, ret: %d\n", cur_dir, dirfd); + goto out; + } + + if (fd == -1) { + if (!output) + fd = init_digest_list_upload(&mount_sysfs, + &mount_securityfs); + else + fd = open(output, O_WRONLY | O_CREAT | O_TRUNC, 0644); + + if (fd < 0) { + ret = -EACCES; + goto out_close_dirfd; + } + } + + if (op == PARSER_OP_GEN_IMA_LIST) { + ret = ima_copy_boot_aggregate(fd); + if (ret < 0) + return ret; + + ret = ima_generate_entry(-1, fd, "", IMA_KEY_PATH); + if (ret < 0) + return ret; + } + + for (i = 0; i < COMPACT__LAST; i++) { + ret = process_lists(dirfd, fd, (output != NULL), verbose, + &list_head, i, op, cur_dir, + digest_list_filename); + if (ret < 0) { + printf("Cannot upload digest lists, ret: %d\n", ret); + goto out_close_fd; + } + + ret = compact_list_flush_all(fd, &list_head); + if (ret < 0) { + printf("Cannot upload digest lists, ret: %d\n", ret); + goto out_close_fd; + } + } out_close_fd: - if (fd >= 0) - close(fd); + if (fd >= 0) + close(fd); - end_digest_list_upload(mount_sysfs, mount_securityfs); + end_digest_list_upload(mount_sysfs, mount_securityfs); out_close_dirfd: - close(dirfd); + close(dirfd); out: - if (op == PARSER_OP_ADD_META_DIGEST) - selinux_end_setup(); + if (op == PARSER_OP_ADD_META_DIGEST) + selinux_end_setup(); - return ret; + return ret; } diff --git a/src/rpm_parser.c b/src/rpm_parser.c index 2cb4219..3279c20 100644 --- a/src/rpm_parser.c +++ b/src/rpm_parser.c @@ -38,290 +38,290 @@ #define DIGEST_LIST_DIR "/etc/ima/digest_lists/" enum hash_algo pgp_algo_mapping[PGP_HASH__LAST] = { - [PGP_HASH_MD5] = HASH_ALGO_MD5, - [PGP_HASH_SHA1] = HASH_ALGO_SHA1, - [PGP_HASH_SHA224] = HASH_ALGO_SHA224, - [PGP_HASH_SHA256] = HASH_ALGO_SHA256, - [PGP_HASH_SHA384] = HASH_ALGO_SHA384, - [PGP_HASH_SHA512] = HASH_ALGO_SHA512, + [PGP_HASH_MD5] = HASH_ALGO_MD5, + [PGP_HASH_SHA1] = HASH_ALGO_SHA1, + [PGP_HASH_SHA224] = HASH_ALGO_SHA224, + [PGP_HASH_SHA256] = HASH_ALGO_SHA256, + [PGP_HASH_SHA384] = HASH_ALGO_SHA384, + [PGP_HASH_SHA512] = HASH_ALGO_SHA512, }; struct rpm_hdr { - int32_t magic; - int32_t reserved; - int32_t tags; - int32_t datasize; + int32_t magic; + int32_t reserved; + int32_t tags; + int32_t datasize; } __attribute__((packed)); struct rpm_entryinfo { - int32_t tag; - int32_t type; - int32_t offset; - int32_t count; + int32_t tag; + int32_t type; + int32_t offset; + int32_t count; } __attribute__((packed)); struct digest_list { - struct compact_list_hdr hdr; - u8 digest[SHA512_DIGEST_SIZE]; + struct compact_list_hdr hdr; + u8 digest[SHA512_DIGEST_SIZE]; } __attribute__((packed)); static int parse_rpm(int fd_ima, int add, char *path, struct stat *st) { - void *bufp, *bufendp, *datap; - struct rpm_hdr *hdr; - int32_t tags; - struct rpm_entryinfo *entry; - void *digests = NULL, *algo_buf = NULL; - void *dirnames = NULL, *basenames = NULL, *dirindexes = NULL; - void *digests_ptr; - char **dirnames_ptr = NULL, *basename, *dir_ptr; - u32 digests_count = 0, dirnames_count = 0; - u16 algo = HASH_ALGO_MD5; - char file_path[PATH_MAX]; - u8 digest[SHA512_DIGEST_SIZE]; - struct digest_list list; - size_t len; - int ret = 0, fd_rpm, i, prefix_len = 0; - - const unsigned char rpm_header_magic[8] = { - 0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00 - }; - - if (st->st_size < sizeof(*hdr)) { - printf("Missing RPM header\n"); - return -EINVAL; - } - - fd_rpm = open(path, O_RDONLY); - if (fd_rpm < 0) - return -EACCES; - - bufp = mmap(NULL, st->st_size, PROT_READ | PROT_WRITE, - MAP_PRIVATE, fd_rpm, 0); - - close(fd_rpm); - - if (bufp == MAP_FAILED) - return -ENOMEM; - - if (memcmp(bufp, rpm_header_magic, sizeof(rpm_header_magic))) { - pr_err("Invalid RPM header\n"); - return -EINVAL; - } - - hdr = (struct rpm_hdr *)bufp; - tags = __be32_to_cpu(hdr->tags); - datap = bufp + sizeof(*hdr) + tags * sizeof(struct rpm_entryinfo); - bufendp = bufp + st->st_size; - bufp += sizeof(*hdr); - - for (i = 0; i < tags && (bufp + sizeof(*entry)) <= bufendp; - i++, bufp += sizeof(*entry)) { - entry = bufp; - - switch (be32_to_cpu(entry->tag)) { - case RPMTAG_FILEDIGESTS: - digests = datap + be32_to_cpu(entry->offset); - digests_count = be32_to_cpu(entry->count); - break; - case RPMTAG_FILEDIGESTALGO: - algo_buf = datap + be32_to_cpu(entry->offset); - break; - case RPMTAG_DIRNAMES: - dirnames = datap + be32_to_cpu(entry->offset); - dirnames_count = be32_to_cpu(entry->count); - break; - case RPMTAG_BASENAMES: - basenames = datap + be32_to_cpu(entry->offset); - break; - case RPMTAG_DIRINDEXES: - dirindexes = datap + be32_to_cpu(entry->offset); - break; - - if (digests && algo_buf && dirnames && basenames && dirindexes) - break; - } - } - - if (!digests || !dirnames || !basenames || !dirindexes) - return 0; - - dirnames_ptr = malloc(sizeof(*dirnames_ptr) * dirnames_count); - if (!dirnames_ptr) - return -ENOMEM; - - for (i = 0; i < dirnames_count && dirnames < bufendp; i++) { - dirnames_ptr[i] = dirnames; - dirnames += strlen(dirnames) + 1; - } - - if (i < dirnames_count) { - ret = -EINVAL; - goto out; - } - - if (algo_buf && algo_buf + sizeof(u32) <= bufendp) - algo = pgp_algo_mapping[be32_to_cpu(*(u32 *)algo_buf)]; - - for (i = 0; i < digests_count && digests < bufendp; i++) { - int digest_str_len = strlen(digests); - int basename_str_len = strlen(basenames); - u32 dirindex = 0; - - if ((basenames && - basenames + basename_str_len + 1 > bufendp) || - (dirindexes && - dirindexes + (i + 1) * sizeof(dirindex) > bufendp) || - (digests + digest_str_len * 2 + 1 > bufendp)) { - pr_err("RPM header read at invalid offset\n"); - ret = -EINVAL; - goto out; - } - - if (!digest_str_len) { - digests += digest_str_len + 1; - basenames += basename_str_len + 1; - continue; - } - - digests_ptr = digests; - digests += digest_str_len + 1; - dirindex = be32_to_cpu(*(u32 *) - (dirindexes + i * sizeof(dirindex))); - - basename = basenames; - basenames += basename_str_len + 1; - - if (strncmp(dirnames_ptr[dirindex], DIGEST_LIST_DIR, - sizeof(DIGEST_LIST_DIR) - 1)) - continue; - - dir_ptr = strstr(path, DIGEST_LIST_DIR); - - if (dir_ptr) - prefix_len = dir_ptr - path; - - snprintf(file_path, sizeof(file_path), "%.*s%s%s", prefix_len, - path, dirnames_ptr[dirindex], basename); - - ret = hex2bin(digest, digests_ptr, digest_str_len / 2); - if (ret < 0) - goto out; - - list.hdr.version = 1; - list.hdr.type = COMPACT_FILE; - list.hdr.modifiers = (1 << COMPACT_MOD_IMMUTABLE); - list.hdr.algo = algo; - list.hdr.count = 1; - list.hdr.datalen = digest_str_len / 2; - - if (ima_canonical_fmt) { - list.hdr.type = cpu_to_le16(list.hdr.type); - list.hdr.modifiers = cpu_to_le16(list.hdr.modifiers); - list.hdr.algo = cpu_to_le16(list.hdr.algo); - list.hdr.count = cpu_to_le32(list.hdr.count); - list.hdr.datalen = cpu_to_le32(list.hdr.datalen); - } - - memcpy(list.digest, digest, digest_str_len / 2); - - if (!add) { - len = write(fd_ima, file_path, strlen(file_path)); - if (len != strlen(file_path)) { - ret = -EIO; - goto out; - } - } - - len = write(fd_ima, (u8 *)&list, - sizeof(list.hdr) + digest_str_len / 2); - if (len != sizeof(list.hdr) + digest_str_len / 2) { - ret = -EIO; - goto out; - } - - if (add) { - lremovexattr(file_path, XATTR_NAME_IMA); - - len = write(fd_ima, file_path, strlen(file_path)); - if (len != strlen(file_path)) - ret = -EIO; - } - } + void *bufp, *bufendp, *datap; + struct rpm_hdr *hdr; + int32_t tags; + struct rpm_entryinfo *entry; + void *digests = NULL, *algo_buf = NULL; + void *dirnames = NULL, *basenames = NULL, *dirindexes = NULL; + void *digests_ptr; + char **dirnames_ptr = NULL, *basename, *dir_ptr; + u32 digests_count = 0, dirnames_count = 0; + u16 algo = HASH_ALGO_MD5; + char file_path[PATH_MAX]; + u8 digest[SHA512_DIGEST_SIZE]; + struct digest_list list; + size_t len; + int ret = 0, fd_rpm, i, prefix_len = 0; + + const unsigned char rpm_header_magic[8] = { + 0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00 + }; + + if (st->st_size < sizeof(*hdr)) { + printf("Missing RPM header\n"); + return -EINVAL; + } + + fd_rpm = open(path, O_RDONLY); + if (fd_rpm < 0) + return -EACCES; + + bufp = mmap(NULL, st->st_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE, fd_rpm, 0); + + close(fd_rpm); + + if (bufp == MAP_FAILED) + return -ENOMEM; + + if (memcmp(bufp, rpm_header_magic, sizeof(rpm_header_magic))) { + pr_err("Invalid RPM header\n"); + return -EINVAL; + } + + hdr = (struct rpm_hdr *)bufp; + tags = __be32_to_cpu(hdr->tags); + datap = bufp + sizeof(*hdr) + tags * sizeof(struct rpm_entryinfo); + bufendp = bufp + st->st_size; + bufp += sizeof(*hdr); + + for (i = 0; i < tags && (bufp + sizeof(*entry)) <= bufendp; + i++, bufp += sizeof(*entry)) { + entry = bufp; + + switch (be32_to_cpu(entry->tag)) { + case RPMTAG_FILEDIGESTS: + digests = datap + be32_to_cpu(entry->offset); + digests_count = be32_to_cpu(entry->count); + break; + case RPMTAG_FILEDIGESTALGO: + algo_buf = datap + be32_to_cpu(entry->offset); + break; + case RPMTAG_DIRNAMES: + dirnames = datap + be32_to_cpu(entry->offset); + dirnames_count = be32_to_cpu(entry->count); + break; + case RPMTAG_BASENAMES: + basenames = datap + be32_to_cpu(entry->offset); + break; + case RPMTAG_DIRINDEXES: + dirindexes = datap + be32_to_cpu(entry->offset); + break; + + if (digests && algo_buf && dirnames && basenames && dirindexes) + break; + } + } + + if (!digests || !dirnames || !basenames || !dirindexes) + return 0; + + dirnames_ptr = malloc(sizeof(*dirnames_ptr) * dirnames_count); + if (!dirnames_ptr) + return -ENOMEM; + + for (i = 0; i < dirnames_count && dirnames < bufendp; i++) { + dirnames_ptr[i] = dirnames; + dirnames += strlen(dirnames) + 1; + } + + if (i < dirnames_count) { + ret = -EINVAL; + goto out; + } + + if (algo_buf && algo_buf + sizeof(u32) <= bufendp) + algo = pgp_algo_mapping[be32_to_cpu(*(u32 *)algo_buf)]; + + for (i = 0; i < digests_count && digests < bufendp; i++) { + int digest_str_len = strlen(digests); + int basename_str_len = strlen(basenames); + u32 dirindex = 0; + + if ((basenames && + basenames + basename_str_len + 1 > bufendp) || + (dirindexes && + dirindexes + (i + 1) * sizeof(dirindex) > bufendp) || + (digests + digest_str_len * 2 + 1 > bufendp)) { + pr_err("RPM header read at invalid offset\n"); + ret = -EINVAL; + goto out; + } + + if (!digest_str_len) { + digests += digest_str_len + 1; + basenames += basename_str_len + 1; + continue; + } + + digests_ptr = digests; + digests += digest_str_len + 1; + dirindex = be32_to_cpu(*(u32 *) + (dirindexes + i * sizeof(dirindex))); + + basename = basenames; + basenames += basename_str_len + 1; + + if (strncmp(dirnames_ptr[dirindex], DIGEST_LIST_DIR, + sizeof(DIGEST_LIST_DIR) - 1)) + continue; + + dir_ptr = strstr(path, DIGEST_LIST_DIR); + + if (dir_ptr) + prefix_len = dir_ptr - path; + + snprintf(file_path, sizeof(file_path), "%.*s%s%s", prefix_len, + path, dirnames_ptr[dirindex], basename); + + ret = hex2bin(digest, digests_ptr, digest_str_len / 2); + if (ret < 0) + goto out; + + list.hdr.version = 1; + list.hdr.type = COMPACT_FILE; + list.hdr.modifiers = (1 << COMPACT_MOD_IMMUTABLE); + list.hdr.algo = algo; + list.hdr.count = 1; + list.hdr.datalen = digest_str_len / 2; + + if (ima_canonical_fmt) { + list.hdr.type = cpu_to_le16(list.hdr.type); + list.hdr.modifiers = cpu_to_le16(list.hdr.modifiers); + list.hdr.algo = cpu_to_le16(list.hdr.algo); + list.hdr.count = cpu_to_le32(list.hdr.count); + list.hdr.datalen = cpu_to_le32(list.hdr.datalen); + } + + memcpy(list.digest, digest, digest_str_len / 2); + + if (!add) { + len = write(fd_ima, file_path, strlen(file_path)); + if (len != strlen(file_path)) { + ret = -EIO; + goto out; + } + } + + len = write(fd_ima, (u8 *)&list, + sizeof(list.hdr) + digest_str_len / 2); + if (len != sizeof(list.hdr) + digest_str_len / 2) { + ret = -EIO; + goto out; + } + + if (add) { + lremovexattr(file_path, XATTR_NAME_IMA); + + len = write(fd_ima, file_path, strlen(file_path)); + if (len != strlen(file_path)) + ret = -EIO; + } + } out: - free(dirnames_ptr); + free(dirnames_ptr); - return ret; + return ret; } int parse_digest_list(char *name) { - char *type_start, *format_start, *format_end; + char *type_start, *format_start, *format_end; - type_start = strchr(name, '-'); - if (!type_start) - return 0; + type_start = strchr(name, '-'); + if (!type_start) + return 0; - format_start = strchr(type_start + 1, '-'); - if (!format_start) - return 0; + format_start = strchr(type_start + 1, '-'); + if (!format_start) + return 0; - format_end = strchr(format_start + 1, '-'); - if (!format_end) - return 0; + format_end = strchr(format_start + 1, '-'); + if (!format_end) + return 0; - if (format_end - format_start - 1 != 3 || - strncmp(format_start + 1, "rpm", 3)) - return 0; + if (format_end - format_start - 1 != 3 || + strncmp(format_start + 1, "rpm", 3)) + return 0; - return 1; + return 1; } int main(int argc, char *argv[]) { - FTS *fts = NULL; - FTSENT *ftsent; - char *ima_path = DIGEST_LIST_DATA; - int fts_flags = (FTS_PHYSICAL | FTS_COMFOLLOW | FTS_NOCHDIR | FTS_XDEV); - char *paths[2] = { NULL, NULL }; - int ret, fd_ima, add = 1; - - if (argc != 3) { - printf("Usage: %s add|del \n", argv[0]); - return -EINVAL; - } - - if (!strcmp(argv[1], "del")) { - ima_path = DIGEST_LIST_DATA_DEL; - add = 0; - } - - fd_ima = open(ima_path, O_WRONLY | O_CREAT, 0600); - if (fd_ima < 0) - return -EACCES; - - paths[0] = argv[2]; - - fts = fts_open(paths, fts_flags, NULL); - if (!fts) - return -EACCES; - - while ((ftsent = fts_read(fts)) != NULL) { - switch (ftsent->fts_info) { - case FTS_F: - if (!parse_digest_list(ftsent->fts_name)) - break; - - ret = parse_rpm(fd_ima, add, ftsent->fts_path, - ftsent->fts_statp); - if (ret < 0) - printf("Cannot parse %s\n", ftsent->fts_path); - break; - default: - break; - } - } - - close(fd_ima); - return 0; + FTS *fts = NULL; + FTSENT *ftsent; + char *ima_path = DIGEST_LIST_DATA; + int fts_flags = (FTS_PHYSICAL | FTS_COMFOLLOW | FTS_NOCHDIR | FTS_XDEV); + char *paths[2] = { NULL, NULL }; + int ret, fd_ima, add = 1; + + if (argc != 3) { + printf("Usage: %s add|del \n", argv[0]); + return -EINVAL; + } + + if (!strcmp(argv[1], "del")) { + ima_path = DIGEST_LIST_DATA_DEL; + add = 0; + } + + fd_ima = open(ima_path, O_WRONLY | O_CREAT, 0600); + if (fd_ima < 0) + return -EACCES; + + paths[0] = argv[2]; + + fts = fts_open(paths, fts_flags, NULL); + if (!fts) + return -EACCES; + + while ((ftsent = fts_read(fts)) != NULL) { + switch (ftsent->fts_info) { + case FTS_F: + if (!parse_digest_list(ftsent->fts_name)) + break; + + ret = parse_rpm(fd_ima, add, ftsent->fts_path, + ftsent->fts_statp); + if (ret < 0) + printf("Cannot parse %s\n", ftsent->fts_path); + break; + default: + break; + } + } + + close(fd_ima); + return 0; } diff --git a/src/upload_digest_lists.c b/src/upload_digest_lists.c index 37c0c53..9e62c67 100644 --- a/src/upload_digest_lists.c +++ b/src/upload_digest_lists.c @@ -35,160 +35,160 @@ #define DIGEST_LIST_DATA SECURITYFS_PATH "/ima/digest_list_data" struct format_entry { - struct list_head list; - char *format; + struct list_head list; + char *format; }; LIST_HEAD(formats); int add_format_parser(char *path) { - char *format = NULL, *name; - char *type_start, *format_start, *format_end; - struct format_entry *cur, *new; - int ret = 0; + char *format = NULL, *name; + char *type_start, *format_start, *format_end; + struct format_entry *cur, *new; + int ret = 0; - name = strrchr(path, '/'); - if (!name) - return -EINVAL; + name = strrchr(path, '/'); + if (!name) + return -EINVAL; - name++; + name++; - type_start = strchr(name, '-'); - if (!type_start) - return 0; + type_start = strchr(name, '-'); + if (!type_start) + return 0; - format_start = strchr(type_start + 1, '-'); - if (!format_start) - return 0; + format_start = strchr(type_start + 1, '-'); + if (!format_start) + return 0; - format_end = strchr(format_start + 1, '-'); - if (!format_end) - return 0; + format_end = strchr(format_start + 1, '-'); + if (!format_end) + return 0; - format = strndup(format_start + 1, format_end - format_start - 1); - if (!format) - return -ENOMEM; + format = strndup(format_start + 1, format_end - format_start - 1); + if (!format) + return -ENOMEM; - list_for_each_entry(cur, &formats, list) - if (!strcmp(format, cur->format)) - goto out; + list_for_each_entry(cur, &formats, list) + if (!strcmp(format, cur->format)) + goto out; - if (!strcmp(format, "compact")) - goto out; + if (!strcmp(format, "compact")) + goto out; - new = malloc(sizeof(*new)); - if (!new) { - ret = -ENOMEM; - goto out; - } + new = malloc(sizeof(*new)); + if (!new) { + ret = -ENOMEM; + goto out; + } - new->format = format; - list_add(&new->list, &formats); + new->format = format; + list_add(&new->list, &formats); out: - if (ret < 0) - free(format); + if (ret < 0) + free(format); - return ret; + return ret; } static int init_digest_list_upload(int *mount_sysfs, int *mount_securityfs) { - struct stat st; - int ret; + struct stat st; + int ret; - if (!stat(SECURITYFS_PATH, &st)) - goto mount_securityfs; + if (!stat(SECURITYFS_PATH, &st)) + goto mount_securityfs; - ret = mount(SYSFS_PATH, SYSFS_PATH, "sysfs", MOUNT_FLAGS, NULL); - if (ret < 0) { - printf("Cannot mount %s (%s)\n", SYSFS_PATH, - strerror(errno)); - return ret; - } + ret = mount(SYSFS_PATH, SYSFS_PATH, "sysfs", MOUNT_FLAGS, NULL); + if (ret < 0) { + printf("Cannot mount %s (%s)\n", SYSFS_PATH, + strerror(errno)); + return ret; + } - *mount_sysfs = 1; + *mount_sysfs = 1; mount_securityfs: - if (!stat(DIGEST_LIST_DATA, &st)) - return 0; - - ret = mount(SECURITYFS_PATH, SECURITYFS_PATH, "securityfs", MOUNT_FLAGS, - NULL); - if (ret < 0) { - printf("Cannot mount %s (%s)\n", SECURITYFS_PATH, - strerror(errno)); - return ret; - } - - *mount_securityfs = 1; - return 0; + if (!stat(DIGEST_LIST_DATA, &st)) + return 0; + + ret = mount(SECURITYFS_PATH, SECURITYFS_PATH, "securityfs", MOUNT_FLAGS, + NULL); + if (ret < 0) { + printf("Cannot mount %s (%s)\n", SECURITYFS_PATH, + strerror(errno)); + return ret; + } + + *mount_securityfs = 1; + return 0; } static void end_digest_list_upload(int umount_sysfs, int umount_securityfs) { - if (umount_securityfs) - umount(SECURITYFS_PATH); - if (umount_sysfs) - umount(SYSFS_PATH); + if (umount_securityfs) + umount(SECURITYFS_PATH); + if (umount_sysfs) + umount(SYSFS_PATH); } int main(int argc, char *argv[]) { - int mount_sysfs = 0, mount_securityfs = 0; - char *paths[2] = { NULL, NULL }; - struct format_entry *cur, *tmp; - char parser_path[PATH_MAX]; - FTS *fts = NULL; - FTSENT *ftsent; - int fts_flags = (FTS_PHYSICAL | FTS_COMFOLLOW | FTS_NOCHDIR | FTS_XDEV); - int ret; - - if (argc != 3) { - printf("Usage: %s add|del \n", argv[0]); - return -EINVAL; - } - - paths[0] = argv[2]; - - fts = fts_open(paths, fts_flags, NULL); - if (!fts) - return -EACCES; - - while ((ftsent = fts_read(fts)) != NULL) { - switch (ftsent->fts_info) { - case FTS_F: - ret = add_format_parser(ftsent->fts_path); - if (ret < 0) - printf("Cannot upload %s\n", ftsent->fts_path); - - break; - default: - break; - } - } - - fts_close(fts); - fts = NULL; - - ret = init_digest_list_upload(&mount_sysfs, &mount_securityfs); - if (ret < 0) - return -EACCES; - - list_for_each_entry_safe(cur, tmp, &formats, list) { - if (fork() == 0) { - snprintf(parser_path, sizeof(parser_path), - "/usr/libexec/%s_parser", cur->format); - return execlp(parser_path, parser_path, argv[1], - argv[2], NULL); - } - - wait(NULL); - - list_del(&cur->list); - free(cur->format); - free(cur); - } - - end_digest_list_upload(mount_sysfs, mount_securityfs); - return 0; + int mount_sysfs = 0, mount_securityfs = 0; + char *paths[2] = { NULL, NULL }; + struct format_entry *cur, *tmp; + char parser_path[PATH_MAX]; + FTS *fts = NULL; + FTSENT *ftsent; + int fts_flags = (FTS_PHYSICAL | FTS_COMFOLLOW | FTS_NOCHDIR | FTS_XDEV); + int ret; + + if (argc != 3) { + printf("Usage: %s add|del \n", argv[0]); + return -EINVAL; + } + + paths[0] = argv[2]; + + fts = fts_open(paths, fts_flags, NULL); + if (!fts) + return -EACCES; + + while ((ftsent = fts_read(fts)) != NULL) { + switch (ftsent->fts_info) { + case FTS_F: + ret = add_format_parser(ftsent->fts_path); + if (ret < 0) + printf("Cannot upload %s\n", ftsent->fts_path); + + break; + default: + break; + } + } + + fts_close(fts); + fts = NULL; + + ret = init_digest_list_upload(&mount_sysfs, &mount_securityfs); + if (ret < 0) + return -EACCES; + + list_for_each_entry_safe(cur, tmp, &formats, list) { + if (fork() == 0) { + snprintf(parser_path, sizeof(parser_path), + "/usr/libexec/%s_parser", cur->format); + return execlp(parser_path, parser_path, argv[1], + argv[2], NULL); + } + + wait(NULL); + + list_del(&cur->list); + free(cur->format); + free(cur); + } + + end_digest_list_upload(mount_sysfs, mount_securityfs); + return 0; } diff --git a/src/verify_digest_lists.c b/src/verify_digest_lists.c index 4b57acf..299e192 100644 --- a/src/verify_digest_lists.c +++ b/src/verify_digest_lists.c @@ -33,56 +33,56 @@ static void usage(char *progname) { - printf("Usage: %s \n", progname); - printf("Options:\n"); - printf("\t-d : directory containing digest lists\n" - "\t-f : filename in the digest list directory\n" - "\t-v: verbose mode\n" - "\t-h: display help\n"); + printf("Usage: %s \n", progname); + printf("Options:\n"); + printf("\t-d : directory containing digest lists\n" + "\t-f : filename in the digest list directory\n" + "\t-v: verbose mode\n" + "\t-h: display help\n"); } int main(int argc, char *argv[]) { - int c, i, dirfd, verbose = 0, ret = -EINVAL; - char *cur_dir = DEFAULT_DIR; - char *digest_list_filename = NULL; - LIST_HEAD(key_head); + int c, i, dirfd, verbose = 0, ret = -EINVAL; + char *cur_dir = DEFAULT_DIR; + char *digest_list_filename = NULL; + LIST_HEAD(key_head); - while ((c = getopt(argc, argv, "d:f:vh")) != -1) { - switch (c) { - case 'd': - cur_dir = optarg; - break; - case 'f': - digest_list_filename = optarg; - break; - case 'v': - verbose = 1; - break; - case 'h': - usage(argv[0]); - return -EINVAL; - default: - printf("Unknown option %c\n", optopt); - return -EINVAL; - } - } + while ((c = getopt(argc, argv, "d:f:vh")) != -1) { + switch (c) { + case 'd': + cur_dir = optarg; + break; + case 'f': + digest_list_filename = optarg; + break; + case 'v': + verbose = 1; + break; + case 'h': + usage(argv[0]); + return -EINVAL; + default: + printf("Unknown option %c\n", optopt); + return -EINVAL; + } + } - dirfd = open(cur_dir, O_RDONLY | O_DIRECTORY); - if (dirfd < 0) { - printf("Unable to open %s, ret: %d\n", cur_dir, dirfd); - return dirfd; - } + dirfd = open(cur_dir, O_RDONLY | O_DIRECTORY); + if (dirfd < 0) { + printf("Unable to open %s, ret: %d\n", cur_dir, dirfd); + return dirfd; + } - for (i = 0; i < COMPACT__LAST; i++) { - ret = process_lists(dirfd, -1, 0, verbose, &key_head, i, - PARSER_OP_VERIFY, cur_dir, - digest_list_filename); - if (ret < 0) - printf("Cannot access digest lists, ret: %d\n", ret); - } + for (i = 0; i < COMPACT__LAST; i++) { + ret = process_lists(dirfd, -1, 0, verbose, &key_head, i, + PARSER_OP_VERIFY, cur_dir, + digest_list_filename); + if (ret < 0) + printf("Cannot access digest lists, ret: %d\n", ret); + } - free_keys(&key_head); - close(dirfd); - return ret; + free_keys(&key_head); + close(dirfd); + return ret; } diff --git a/src/write_rpm_pgp_sig.c b/src/write_rpm_pgp_sig.c index 3f8b904..29c5721 100644 --- a/src/write_rpm_pgp_sig.c +++ b/src/write_rpm_pgp_sig.c @@ -20,53 +20,53 @@ int main(int argc, char *argv[]) { - void *pgp_sig; - loff_t pgp_sig_len; - u8 *sig = NULL, *data = NULL, *issuer = NULL; - size_t sig_len, data_len; - u16 algo; - int ret, fd; + void *pgp_sig; + loff_t pgp_sig_len; + u8 *sig = NULL, *data = NULL, *issuer = NULL; + size_t sig_len, data_len; + u16 algo; + int ret, fd; - if (argc < 3) { - printf("Missing argument\n"); - return -EINVAL; - } + if (argc < 3) { + printf("Missing argument\n"); + return -EINVAL; + } - ret = read_file_from_path(-1, argv[2], &pgp_sig, &pgp_sig_len); - if (ret < 0) - return ret; + ret = read_file_from_path(-1, argv[2], &pgp_sig, &pgp_sig_len); + if (ret < 0) + return ret; - ret = pgp_get_signature_data(pgp_sig, pgp_sig_len, &data, &data_len, - &sig, &sig_len, &issuer, &algo); - if (ret < 0) - goto out; + ret = pgp_get_signature_data(pgp_sig, pgp_sig_len, &data, &data_len, + &sig, &sig_len, &issuer, &algo); + if (ret < 0) + goto out; - if (argc == 4) { - free(sig); + if (argc == 4) { + free(sig); - ret = read_file_from_path(-1, argv[3], (void **)&sig, - (loff_t *)&sig_len); - if (ret < 0) - goto out; - } + ret = read_file_from_path(-1, argv[3], (void **)&sig, + (loff_t *)&sig_len); + if (ret < 0) + goto out; + } - write_ima_xattr(-1, argv[1], issuer, sizeof(uint32_t), sig, sig_len, - pgp_algo_mapping[algo]); + write_ima_xattr(-1, argv[1], issuer, sizeof(uint32_t), sig, sig_len, + pgp_algo_mapping[algo]); - fd = openat(-1, argv[1], O_WRONLY | O_APPEND, 0644); - if (fd < 0) { - ret = -EACCES; - goto out; - } + fd = openat(-1, argv[1], O_WRONLY | O_APPEND, 0644); + if (fd < 0) { + ret = -EACCES; + goto out; + } - ret = write_check(fd, data, data_len); - close(fd); + ret = write_check(fd, data, data_len); + close(fd); out: - munmap(pgp_sig, pgp_sig_len); - free(data); - if (argc == 4) - munmap(sig, sig_len); - else - free(sig); - return ret; + munmap(pgp_sig, pgp_sig_len); + free(data); + if (argc == 4) + munmap(sig, sig_len); + else + free(sig); + return ret; } diff --git a/tests/compact_tlv.c b/tests/compact_tlv.c index a94adc7..67c53ba 100644 --- a/tests/compact_tlv.c +++ b/tests/compact_tlv.c @@ -24,218 +24,218 @@ #include "compact_list.h" #define FILE_DIGEST \ - "5feceb66ffc86f38d952786c6d696c79c2dbc239dd4e91b46729d73a27fb57e9" + "5feceb66ffc86f38d952786c6d696c79c2dbc239dd4e91b46729d73a27fb57e9" #define NEW_FILE "new_file" #define NEW_COMPACT_LIST "test_compact_list" static int test_digest_func(u8 *digest, enum hash_algo algo, - enum compact_types type, u16 modifiers) + enum compact_types type, u16 modifiers) { - u8 ref_digest[SHA512_DIGEST_SIZE]; - enum hash_algo expected_algo = HASH_ALGO_SHA256; - int ret; + u8 ref_digest[SHA512_DIGEST_SIZE]; + enum hash_algo expected_algo = HASH_ALGO_SHA256; + int ret; - assert_int_equal(modifiers, (1 << COMPACT_MOD_IMMUTABLE)); - assert_int_equal(algo, expected_algo); + assert_int_equal(modifiers, (1 << COMPACT_MOD_IMMUTABLE)); + assert_int_equal(algo, expected_algo); - ret = hex2bin(ref_digest, FILE_DIGEST, hash_digest_size[algo]); - assert_return_code(ret, 0); + ret = hex2bin(ref_digest, FILE_DIGEST, hash_digest_size[algo]); + assert_return_code(ret, 0); - assert_memory_equal(digest, ref_digest, hash_digest_size[algo]); - return 0; + assert_memory_equal(digest, ref_digest, hash_digest_size[algo]); + return 0; } static int test_metadata_digest_func(u8 *digest, enum hash_algo algo, - enum compact_types type, u16 modifiers) + enum compact_types type, u16 modifiers) { - u8 calculated_digest[SHA512_DIGEST_SIZE]; - u8 *inode_metadata_buf; - int selinux_label_len, ima_xattr_len, buf_len; - enum hash_algo expected_algo = HASH_ALGO_SHA256; - struct stat st; - int ret; - - struct h_misc { - unsigned long ino; - u32 generation; - uid_t uid; - gid_t gid; - mode_t mode; - } inode_metadata = { 0 }; - - assert_int_equal(modifiers, (1 << COMPACT_MOD_IMMUTABLE)); - assert_int_equal(algo, expected_algo); - - ret = stat(NEW_FILE, &st); - assert_return_code(ret, 0); - - selinux_label_len = getxattr(NEW_FILE, XATTR_NAME_SELINUX, NULL, 0); - if (selinux_label_len < 0) - selinux_label_len = 0; - - inode_metadata.uid = st.st_uid; - inode_metadata.gid = st.st_gid; - inode_metadata.mode = st.st_mode; - - buf_len = selinux_label_len + 2 + hash_digest_size[algo] + \ - sizeof(inode_metadata); - - inode_metadata_buf = malloc(buf_len); - assert_non_null(inode_metadata_buf); - - if (selinux_label_len) { - ret = getxattr(NEW_FILE, XATTR_NAME_SELINUX, inode_metadata_buf, - buf_len); - assert_return_code(ret, 0); - } - - ret = calc_file_digest(calculated_digest, -1, NEW_FILE, algo); - assert_return_code(ret, 0); - - ret = gen_write_ima_xattr(inode_metadata_buf + selinux_label_len, - &ima_xattr_len, NEW_FILE, algo, - calculated_digest, true, false); - assert_return_code(ret, 0); - - memcpy(inode_metadata_buf + selinux_label_len + ima_xattr_len, - &inode_metadata, sizeof(inode_metadata)); - - ret = calc_digest(calculated_digest, inode_metadata_buf, buf_len, algo); - assert_return_code(ret, 0); - - assert_memory_equal(calculated_digest, digest, hash_digest_size[algo]); - free(inode_metadata_buf); - return 0; + u8 calculated_digest[SHA512_DIGEST_SIZE]; + u8 *inode_metadata_buf; + int selinux_label_len, ima_xattr_len, buf_len; + enum hash_algo expected_algo = HASH_ALGO_SHA256; + struct stat st; + int ret; + + struct h_misc { + unsigned long ino; + u32 generation; + uid_t uid; + gid_t gid; + mode_t mode; + } inode_metadata = { 0 }; + + assert_int_equal(modifiers, (1 << COMPACT_MOD_IMMUTABLE)); + assert_int_equal(algo, expected_algo); + + ret = stat(NEW_FILE, &st); + assert_return_code(ret, 0); + + selinux_label_len = getxattr(NEW_FILE, XATTR_NAME_SELINUX, NULL, 0); + if (selinux_label_len < 0) + selinux_label_len = 0; + + inode_metadata.uid = st.st_uid; + inode_metadata.gid = st.st_gid; + inode_metadata.mode = st.st_mode; + + buf_len = selinux_label_len + 2 + hash_digest_size[algo] + \ + sizeof(inode_metadata); + + inode_metadata_buf = malloc(buf_len); + assert_non_null(inode_metadata_buf); + + if (selinux_label_len) { + ret = getxattr(NEW_FILE, XATTR_NAME_SELINUX, inode_metadata_buf, + buf_len); + assert_return_code(ret, 0); + } + + ret = calc_file_digest(calculated_digest, -1, NEW_FILE, algo); + assert_return_code(ret, 0); + + ret = gen_write_ima_xattr(inode_metadata_buf + selinux_label_len, + &ima_xattr_len, NEW_FILE, algo, + calculated_digest, true, false); + assert_return_code(ret, 0); + + memcpy(inode_metadata_buf + selinux_label_len + ima_xattr_len, + &inode_metadata, sizeof(inode_metadata)); + + ret = calc_digest(calculated_digest, inode_metadata_buf, buf_len, algo); + assert_return_code(ret, 0); + + assert_memory_equal(calculated_digest, digest, hash_digest_size[algo]); + free(inode_metadata_buf); + return 0; } static void test_compact_tlv_parser(void **state) { - const char compact_str[] = "compact-test"; - const char compact_tlv_str[] = "compact_tlv-test"; - const char generator_str[] = "generator"; - const char parser_str[] = "parser"; - char path[PATH_MAX], lsm_opt[] = "l:"; - LIST_HEAD(generator_lib_head); - LIST_HEAD(parser_lib_head); - LIST_HEAD(head_in); - LIST_HEAD(head_out); - LIST_HEAD(list_head); - struct lib *generator_lib, *parser_lib; - struct path_struct *item; - void *gen_list_buf, *buf; - loff_t gen_list_size, size; - int ret, dirfd, fd, fd_compact_list; - - dirfd = open(".", O_RDONLY | O_DIRECTORY); - assert_return_code(dirfd, 0); - - snprintf(path, sizeof(path), "I:%s", NEW_FILE); - fd = open(&path[2], O_WRONLY | O_CREAT, 0644); - assert_return_code(fd, 0); - - ret = write(fd, "0", 1); - assert_return_code(ret, 1); - - close(fd); - - /* generate a TLV compact list */ - generator_lib = lookup_lib(&generator_lib_head, generator_str, - compact_str, sizeof(compact_str) - 1); - assert_non_null(generator_lib); - - ret = add_path_struct(path, NULL, &head_in); - assert_return_code(ret, 0); - - ret = add_path_struct(lsm_opt, NULL, &head_in); - assert_return_code(ret, 0); - - ret = ((generator_func)generator_lib->func)(dirfd, 0, &head_in, - &head_out, COMPACT_FILE, - (1 << COMPACT_MOD_IMMUTABLE), - HASH_ALGO_SHA256, - HASH_ALGO_SHA256, true, NULL); - assert_return_code(ret, 0); - assert_false(list_empty(&head_out)); - - item = list_first_entry(&head_out, struct path_struct, list); - ret = read_file_from_path(dirfd, item->path, &gen_list_buf, - &gen_list_size); - assert_return_code(ret, 0); - - unlinkat(dirfd, item->path, 0); - - /* parse the TLV compact list and write converted list to disk */ - parser_lib = lookup_lib(&parser_lib_head, parser_str, compact_tlv_str, - sizeof(compact_tlv_str) - 1); - assert_non_null(parser_lib); - - fd_compact_list = openat(dirfd, NEW_COMPACT_LIST, - O_WRONLY | O_CREAT | O_TRUNC, 0644); - assert_return_code(fd_compact_list, 0); - - ret = ((parser_func)parser_lib->func)(fd_compact_list, &list_head, - gen_list_size, gen_list_buf, - PARSER_OP_ADD_DIGEST); - assert_return_code(ret, 0); - - ret = compact_list_flush_all(fd_compact_list, &list_head); - assert_return_code(ret, 0); - - close(fd_compact_list); - free_path_structs(&head_in); - free_path_structs(&head_out); - free_libs(&generator_lib_head); - free_libs(&parser_lib_head); - - /* parse converted list */ - ret = read_file_from_path(dirfd, NEW_COMPACT_LIST, &buf, &size); - assert_return_code(ret, 0); - - ret = ima_parse_compact_list(size, buf, test_digest_func, NULL); - assert_return_code(ret, 0); - munmap(buf, size); - - fd_compact_list = openat(dirfd, NEW_COMPACT_LIST, - O_WRONLY | O_CREAT | O_TRUNC, 0644); - assert_return_code(fd_compact_list, 0); - - ret = ((parser_func)parser_lib->func)(fd_compact_list, &list_head, - gen_list_size, gen_list_buf, - PARSER_OP_ADD_META_DIGEST); - assert_return_code(ret, 0); - - ret = compact_list_flush_all(fd_compact_list, &list_head); - assert_return_code(ret, 0); - close(fd_compact_list); - - /* parse converted list */ - ret = read_file_from_path(dirfd, NEW_COMPACT_LIST, &buf, &size); - assert_return_code(ret, 0); - - ret = ima_parse_compact_list(size, buf, test_metadata_digest_func, - NULL); - assert_return_code(ret, 0); - munmap(buf, size); - munmap(gen_list_buf, gen_list_size); + const char compact_str[] = "compact-test"; + const char compact_tlv_str[] = "compact_tlv-test"; + const char generator_str[] = "generator"; + const char parser_str[] = "parser"; + char path[PATH_MAX], lsm_opt[] = "l:"; + LIST_HEAD(generator_lib_head); + LIST_HEAD(parser_lib_head); + LIST_HEAD(head_in); + LIST_HEAD(head_out); + LIST_HEAD(list_head); + struct lib *generator_lib, *parser_lib; + struct path_struct *item; + void *gen_list_buf, *buf; + loff_t gen_list_size, size; + int ret, dirfd, fd, fd_compact_list; + + dirfd = open(".", O_RDONLY | O_DIRECTORY); + assert_return_code(dirfd, 0); + + snprintf(path, sizeof(path), "I:%s", NEW_FILE); + fd = open(&path[2], O_WRONLY | O_CREAT, 0644); + assert_return_code(fd, 0); + + ret = write(fd, "0", 1); + assert_return_code(ret, 1); + + close(fd); + + /* generate a TLV compact list */ + generator_lib = lookup_lib(&generator_lib_head, generator_str, + compact_str, sizeof(compact_str) - 1); + assert_non_null(generator_lib); + + ret = add_path_struct(path, NULL, &head_in); + assert_return_code(ret, 0); + + ret = add_path_struct(lsm_opt, NULL, &head_in); + assert_return_code(ret, 0); + + ret = ((generator_func)generator_lib->func)(dirfd, 0, &head_in, + &head_out, COMPACT_FILE, + (1 << COMPACT_MOD_IMMUTABLE), + HASH_ALGO_SHA256, + HASH_ALGO_SHA256, true, NULL); + assert_return_code(ret, 0); + assert_false(list_empty(&head_out)); + + item = list_first_entry(&head_out, struct path_struct, list); + ret = read_file_from_path(dirfd, item->path, &gen_list_buf, + &gen_list_size); + assert_return_code(ret, 0); + + unlinkat(dirfd, item->path, 0); + + /* parse the TLV compact list and write converted list to disk */ + parser_lib = lookup_lib(&parser_lib_head, parser_str, compact_tlv_str, + sizeof(compact_tlv_str) - 1); + assert_non_null(parser_lib); + + fd_compact_list = openat(dirfd, NEW_COMPACT_LIST, + O_WRONLY | O_CREAT | O_TRUNC, 0644); + assert_return_code(fd_compact_list, 0); + + ret = ((parser_func)parser_lib->func)(fd_compact_list, &list_head, + gen_list_size, gen_list_buf, + PARSER_OP_ADD_DIGEST); + assert_return_code(ret, 0); + + ret = compact_list_flush_all(fd_compact_list, &list_head); + assert_return_code(ret, 0); + + close(fd_compact_list); + free_path_structs(&head_in); + free_path_structs(&head_out); + free_libs(&generator_lib_head); + free_libs(&parser_lib_head); + + /* parse converted list */ + ret = read_file_from_path(dirfd, NEW_COMPACT_LIST, &buf, &size); + assert_return_code(ret, 0); + + ret = ima_parse_compact_list(size, buf, test_digest_func, NULL); + assert_return_code(ret, 0); + munmap(buf, size); + + fd_compact_list = openat(dirfd, NEW_COMPACT_LIST, + O_WRONLY | O_CREAT | O_TRUNC, 0644); + assert_return_code(fd_compact_list, 0); + + ret = ((parser_func)parser_lib->func)(fd_compact_list, &list_head, + gen_list_size, gen_list_buf, + PARSER_OP_ADD_META_DIGEST); + assert_return_code(ret, 0); + + ret = compact_list_flush_all(fd_compact_list, &list_head); + assert_return_code(ret, 0); + close(fd_compact_list); + + /* parse converted list */ + ret = read_file_from_path(dirfd, NEW_COMPACT_LIST, &buf, &size); + assert_return_code(ret, 0); + + ret = ima_parse_compact_list(size, buf, test_metadata_digest_func, + NULL); + assert_return_code(ret, 0); + munmap(buf, size); + munmap(gen_list_buf, gen_list_size); } void cleanup(void **state) { - int dirfd; + int dirfd; - dirfd = open(".", O_RDONLY | O_DIRECTORY); - assert_return_code(dirfd, 0); + dirfd = open(".", O_RDONLY | O_DIRECTORY); + assert_return_code(dirfd, 0); - unlinkat(dirfd, NEW_FILE, 0); - unlinkat(dirfd, NEW_COMPACT_LIST, 0); - close(dirfd); + unlinkat(dirfd, NEW_FILE, 0); + unlinkat(dirfd, NEW_COMPACT_LIST, 0); + close(dirfd); } int main(void) { - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_compact_tlv_parser), - cmocka_unit_test(cleanup), - }; + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_compact_tlv_parser), + cmocka_unit_test(cleanup), + }; - return cmocka_run_group_tests(tests, NULL, NULL); + return cmocka_run_group_tests(tests, NULL, NULL); } diff --git a/tests/gen.c b/tests/gen.c index 5ddd365..1affe37 100644 --- a/tests/gen.c +++ b/tests/gen.c @@ -23,70 +23,70 @@ static void test_gen(void **state) { - struct stat st; - int ret; + struct stat st; + int ret; - if (fork() == 0) { - execlp("../src/gen_digest_lists", "gen_digest_lists", - "-t", "parser", "-o", "append", "-f", "compact", - "-i", "I:../src/manage_digest_lists", "-d", "test", NULL); - } + if (fork() == 0) { + execlp("../src/gen_digest_lists", "gen_digest_lists", + "-t", "parser", "-o", "append", "-f", "compact", + "-i", "I:../src/manage_digest_lists", "-d", "test", NULL); + } - wait(NULL); + wait(NULL); - ret = stat("test/0-parser_list-compact-manage_digest_lists", &st); - assert_return_code(ret, 0); + ret = stat("test/0-parser_list-compact-manage_digest_lists", &st); + assert_return_code(ret, 0); - if (fork() == 0) { - execlp("../src/gen_digest_lists", "gen_digest_lists", - "-t", "parser", "-o", "add", "-f", "compact", "-p", "0", - "-i", "I:../src/manage_digest_lists", "-d", "test", NULL); - } + if (fork() == 0) { + execlp("../src/gen_digest_lists", "gen_digest_lists", + "-t", "parser", "-o", "add", "-f", "compact", "-p", "0", + "-i", "I:../src/manage_digest_lists", "-d", "test", NULL); + } - wait(NULL); + wait(NULL); - ret = stat("test/1-parser_list-compact-manage_digest_lists", &st); - assert_return_code(ret, 0); + ret = stat("test/1-parser_list-compact-manage_digest_lists", &st); + assert_return_code(ret, 0); - if (fork() == 0) { - execlp("../src/gen_digest_lists", "gen_digest_lists", - "-t", "parser", "-o", "remove", "-p", "0", "-d", "test", - NULL); - } + if (fork() == 0) { + execlp("../src/gen_digest_lists", "gen_digest_lists", + "-t", "parser", "-o", "remove", "-p", "0", "-d", "test", + NULL); + } - wait(NULL); + wait(NULL); - if (fork() == 0) { - execlp("../src/gen_digest_lists", "gen_digest_lists", - "-t", "parser", "-o", "remove", "-p", "0", "-d", "test", - NULL); - } + if (fork() == 0) { + execlp("../src/gen_digest_lists", "gen_digest_lists", + "-t", "parser", "-o", "remove", "-p", "0", "-d", "test", + NULL); + } - wait(NULL); + wait(NULL); } void test_gen_init(void **state) { - mkdir("test", 0755); + mkdir("test", 0755); } void test_gen_cleanup(void **state) { - struct stat st; - int ret; + struct stat st; + int ret; - rmdir("test"); + rmdir("test"); - ret = stat("test", &st); - assert_int_equal(ret, -1); + ret = stat("test", &st); + assert_int_equal(ret, -1); } int main(void) { - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_gen_init), - cmocka_unit_test(test_gen), - cmocka_unit_test(test_gen_cleanup), - }; + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_gen_init), + cmocka_unit_test(test_gen), + cmocka_unit_test(test_gen_cleanup), + }; - return cmocka_run_group_tests(tests, NULL, NULL); + return cmocka_run_group_tests(tests, NULL, NULL); } diff --git a/tests/lib.c b/tests/lib.c index e2cca62..98182f1 100644 --- a/tests/lib.c +++ b/tests/lib.c @@ -18,35 +18,35 @@ static void test_lib_lookup(void **state) { - LIST_HEAD(lib_head); - struct lib *first_lib, *second_lib, *third_lib; - const char parser_str[] = "parser"; - const char rpm_str[] = "rpm-test"; - const char rpm_db_str[] = "rpm-test+db"; - const char ima_ng_str[] = "compact_tlv-test"; + LIST_HEAD(lib_head); + struct lib *first_lib, *second_lib, *third_lib; + const char parser_str[] = "parser"; + const char rpm_str[] = "rpm-test"; + const char rpm_db_str[] = "rpm-test+db"; + const char ima_ng_str[] = "compact_tlv-test"; - first_lib = lookup_lib(&lib_head, parser_str, rpm_str, - sizeof(rpm_str) - 1); - assert_non_null(first_lib); - assert_memory_equal(first_lib->format, rpm_str, sizeof(rpm_str) - 1); + first_lib = lookup_lib(&lib_head, parser_str, rpm_str, + sizeof(rpm_str) - 1); + assert_non_null(first_lib); + assert_memory_equal(first_lib->format, rpm_str, sizeof(rpm_str) - 1); - second_lib = lookup_lib(&lib_head, parser_str, rpm_db_str, - sizeof(rpm_db_str) - 1); - assert_non_null(second_lib); + second_lib = lookup_lib(&lib_head, parser_str, rpm_db_str, + sizeof(rpm_db_str) - 1); + assert_non_null(second_lib); - assert_ptr_equal(first_lib, second_lib); + assert_ptr_equal(first_lib, second_lib); - third_lib = lookup_lib(&lib_head, parser_str, ima_ng_str, - sizeof(ima_ng_str) - 1); - assert_non_null(third_lib); + third_lib = lookup_lib(&lib_head, parser_str, ima_ng_str, + sizeof(ima_ng_str) - 1); + assert_non_null(third_lib); - free_libs(&lib_head); + free_libs(&lib_head); } int main(void) { - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_lib_lookup), - }; + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_lib_lookup), + }; - return cmocka_run_group_tests(tests, NULL, NULL); + return cmocka_run_group_tests(tests, NULL, NULL); } diff --git a/tests/rpm.c b/tests/rpm.c index 330f35e..f570127 100644 --- a/tests/rpm.c +++ b/tests/rpm.c @@ -34,170 +34,170 @@ LIST_HEAD(ima_digest_head); static int get_digests(int dirfd) { - Header hdr; - rpmts ts = NULL; - FD_t rpmfd; - rpmVSFlags vsflags = 0; - rpmtd filedigests, filemodes, filesizes; - char **digests; - u16 *modes; - u32 *sizes; - int ret, fd, i; - struct ima_digest *new; + Header hdr; + rpmts ts = NULL; + FD_t rpmfd; + rpmVSFlags vsflags = 0; + rpmtd filedigests, filemodes, filesizes; + char **digests; + u16 *modes; + u32 *sizes; + int ret, fd, i; + struct ima_digest *new; - ts = rpmtsCreate(); - assert_non_null(ts); + ts = rpmtsCreate(); + assert_non_null(ts); - vsflags |= _RPMVSF_NODIGESTS; - vsflags |= _RPMVSF_NOSIGNATURES; - rpmtsSetVSFlags(ts, vsflags); + vsflags |= _RPMVSF_NODIGESTS; + vsflags |= _RPMVSF_NOSIGNATURES; + rpmtsSetVSFlags(ts, vsflags); - fd = openat(dirfd, RPM_HEADER, O_RDONLY); - assert_return_code(fd, 0); + fd = openat(dirfd, RPM_HEADER, O_RDONLY); + assert_return_code(fd, 0); - rpmfd = fdDup(fd); - assert_non_null(rpmfd); + rpmfd = fdDup(fd); + assert_non_null(rpmfd); - ret = rpmReadHeader(ts, rpmfd, &hdr, NULL); - assert_return_code(ret, RPMRC_OK); + ret = rpmReadHeader(ts, rpmfd, &hdr, NULL); + assert_return_code(ret, RPMRC_OK); - filedigests = rpmtdNew(); - filemodes = rpmtdNew(); - filesizes = rpmtdNew(); + filedigests = rpmtdNew(); + filemodes = rpmtdNew(); + filesizes = rpmtdNew(); - headerGet(hdr, RPMTAG_FILEDIGESTS, filedigests, 0); - headerGet(hdr, RPMTAG_FILEMODES, filemodes, 0); - headerGet(hdr, RPMTAG_FILESIZES, filesizes, 0); + headerGet(hdr, RPMTAG_FILEDIGESTS, filedigests, 0); + headerGet(hdr, RPMTAG_FILEMODES, filemodes, 0); + headerGet(hdr, RPMTAG_FILESIZES, filesizes, 0); - digests = filedigests->data; - modes = filemodes->data; - sizes = filesizes->data; + digests = filedigests->data; + modes = filemodes->data; + sizes = filesizes->data; - for (i = 0; i < filedigests->count; i++) { - if (!strlen(digests[i])) - continue; + for (i = 0; i < filedigests->count; i++) { + if (!strlen(digests[i])) + continue; - new = calloc(1, sizeof(*new) + SHA512_DIGEST_SIZE); - assert_non_null(new); + new = calloc(1, sizeof(*new) + SHA512_DIGEST_SIZE); + assert_non_null(new); - new->type = COMPACT_FILE; - new->modifiers = (1 << COMPACT_MOD_IMMUTABLE); + new->type = COMPACT_FILE; + new->modifiers = (1 << COMPACT_MOD_IMMUTABLE); - if (!sizes[i]) - new->modifiers = 0; + if (!sizes[i]) + new->modifiers = 0; - if (new->modifiers) { - if ((!(modes[i] & S_IXUGO) && (modes[i] & S_IWUGO)) || - !sizes[i]) - new->modifiers = 0; - } + if (new->modifiers) { + if ((!(modes[i] & S_IXUGO) && (modes[i] & S_IWUGO)) || + !sizes[i]) + new->modifiers = 0; + } - ret = hex2bin(new->digest, digests[i], strlen(digests[i]) / 2); - assert_return_code(ret, 0); + ret = hex2bin(new->digest, digests[i], strlen(digests[i]) / 2); + assert_return_code(ret, 0); - list_add_tail(&new->list, &ima_digest_head); - } + list_add_tail(&new->list, &ima_digest_head); + } - rpmtdFree(filesizes); - rpmtdFree(filemodes); - rpmtdFree(filedigests); - headerFree(hdr); - rpmtsFree(ts); + rpmtdFree(filesizes); + rpmtdFree(filemodes); + rpmtdFree(filedigests); + headerFree(hdr); + rpmtsFree(ts); - Fclose(rpmfd); - close(fd); + Fclose(rpmfd); + close(fd); - return ret; + return ret; } static int test_rpm_func(u8 *digest, enum hash_algo algo, enum compact_types type, u16 modifiers) { - struct ima_digest *digest_struct; + struct ima_digest *digest_struct; - assert_false(list_empty(&ima_digest_head)); + assert_false(list_empty(&ima_digest_head)); - digest_struct = list_first_entry(&ima_digest_head, struct ima_digest, - list); + digest_struct = list_first_entry(&ima_digest_head, struct ima_digest, + list); - assert_int_equal(type, digest_struct->type); - assert_int_equal(modifiers, digest_struct->modifiers); - assert_memory_equal(digest, digest_struct->digest, - hash_digest_size[algo]); + assert_int_equal(type, digest_struct->type); + assert_int_equal(modifiers, digest_struct->modifiers); + assert_memory_equal(digest, digest_struct->digest, + hash_digest_size[algo]); - list_del(&digest_struct->list); - free(digest_struct); - return 0; + list_del(&digest_struct->list); + free(digest_struct); + return 0; } static void test_rpm_parser(void **state) { - const char rpm_str[] = "rpm-test"; - const char parser_str[] = "parser"; - LIST_HEAD(list_head); - LIST_HEAD(lib_head); - struct lib *lib; - void *buf; - loff_t size; - int ret, dirfd, fd_compact_list; + const char rpm_str[] = "rpm-test"; + const char parser_str[] = "parser"; + LIST_HEAD(list_head); + LIST_HEAD(lib_head); + struct lib *lib; + void *buf; + loff_t size; + int ret, dirfd, fd_compact_list; - dirfd = open(".", O_RDONLY | O_DIRECTORY); - assert_return_code(dirfd, 0); + dirfd = open(".", O_RDONLY | O_DIRECTORY); + assert_return_code(dirfd, 0); - ret = get_digests(dirfd); - assert_return_code(ret, 0); + ret = get_digests(dirfd); + assert_return_code(ret, 0); - /* parse RPM header and write converted list to disk */ - lib = lookup_lib(&lib_head, parser_str, rpm_str, sizeof(rpm_str) - 1); - assert_non_null(lib); + /* parse RPM header and write converted list to disk */ + lib = lookup_lib(&lib_head, parser_str, rpm_str, sizeof(rpm_str) - 1); + assert_non_null(lib); - fd_compact_list = openat(dirfd, NEW_COMPACT_LIST, O_WRONLY | O_CREAT, - 0644); - assert_return_code(fd_compact_list, 0); + fd_compact_list = openat(dirfd, NEW_COMPACT_LIST, O_WRONLY | O_CREAT, + 0644); + assert_return_code(fd_compact_list, 0); - ret = read_file_from_path(dirfd, RPM_HEADER, &buf, &size); - assert_return_code(ret, 0); + ret = read_file_from_path(dirfd, RPM_HEADER, &buf, &size); + assert_return_code(ret, 0); - ret = ((parser_func)lib->func)(fd_compact_list, &list_head, size, buf, - PARSER_OP_ADD_DIGEST); - assert_return_code(ret, 0); + ret = ((parser_func)lib->func)(fd_compact_list, &list_head, size, buf, + PARSER_OP_ADD_DIGEST); + assert_return_code(ret, 0); - munmap(buf, size); + munmap(buf, size); - ret = compact_list_flush_all(fd_compact_list, &list_head); - assert_return_code(ret, 0); - assert_true(list_empty(&list_head)); + ret = compact_list_flush_all(fd_compact_list, &list_head); + assert_return_code(ret, 0); + assert_true(list_empty(&list_head)); - close(fd_compact_list); - free_libs(&lib_head); + close(fd_compact_list); + free_libs(&lib_head); - /* parse converted list */ - ret = read_file_from_path(dirfd, NEW_COMPACT_LIST, &buf, &size); - assert_return_code(ret, 0); + /* parse converted list */ + ret = read_file_from_path(dirfd, NEW_COMPACT_LIST, &buf, &size); + assert_return_code(ret, 0); - ret = ima_parse_compact_list(size, buf, test_rpm_func, NULL); - assert_return_code(ret, 0); + ret = ima_parse_compact_list(size, buf, test_rpm_func, NULL); + assert_return_code(ret, 0); - munmap(buf, size); - close(dirfd); + munmap(buf, size); + close(dirfd); } void cleanup(void **state) { - int dirfd; + int dirfd; - dirfd = open(".", O_RDONLY | O_DIRECTORY); - assert_return_code(dirfd, 0); + dirfd = open(".", O_RDONLY | O_DIRECTORY); + assert_return_code(dirfd, 0); - unlinkat(dirfd, NEW_COMPACT_LIST, 0); - close(dirfd); + unlinkat(dirfd, NEW_COMPACT_LIST, 0); + close(dirfd); } int main(void) { - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_rpm_parser), - cmocka_unit_test(cleanup), - }; + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_rpm_parser), + cmocka_unit_test(cleanup), + }; - return cmocka_run_group_tests(tests, NULL, NULL); + return cmocka_run_group_tests(tests, NULL, NULL); } -- Gitee