diff options
author | Richard Haines <richard_c_haines@btinternet.com> | 2015-09-30 16:29:20 +0100 |
---|---|---|
committer | Stephen Smalley <sds@tycho.nsa.gov> | 2015-10-13 17:13:24 -0400 |
commit | e40bbea95f555fe9708cbbc39895bd67a8ac6c48 (patch) | |
tree | 04c5edad51f2f00845887003700c7ec79927379d /libselinux/src/label.c | |
parent | c9c1f273708777c8923268cf61798ed0dc2ffded (diff) | |
download | android_external_selinux-e40bbea95f555fe9708cbbc39895bd67a8ac6c48.tar.gz android_external_selinux-e40bbea95f555fe9708cbbc39895bd67a8ac6c48.tar.bz2 android_external_selinux-e40bbea95f555fe9708cbbc39895bd67a8ac6c48.zip |
libselinux: Add selabel_digest function
selabel_digest(3) if enabled by the SELABEL_OPT_DIGEST option during
selabel_open(3) will return an SHA1 digest of the spec files, plus
a list of the specfiles used to calculate the digest. There is a
test utility supplied that will demonstrate the functionality.
The use case for selabel_digest(3) is to implement an selinux_restorecon
function based on the Android version that writes a hash of the
file_contexts files to an extended attribute to enhance performance
(see external/libselinux/src/android.c selinux_android_restorecon()).
Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>
Diffstat (limited to 'libselinux/src/label.c')
-rw-r--r-- | libselinux/src/label.c | 85 |
1 files changed, 83 insertions, 2 deletions
diff --git a/libselinux/src/label.c b/libselinux/src/label.c index 222b6b32..c656fdaf 100644 --- a/libselinux/src/label.c +++ b/libselinux/src/label.c @@ -10,6 +10,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/stat.h> #include <selinux/selinux.h> #include "callbacks.h" #include "label_internal.h" @@ -65,15 +66,21 @@ static char *selabel_sub(struct selabel_sub *ptr, const char *src) return NULL; } -struct selabel_sub *selabel_subs_init(const char *path, struct selabel_sub *list) +struct selabel_sub *selabel_subs_init(const char *path, + struct selabel_sub *list, + struct selabel_digest *digest) { char buf[1024]; FILE *cfg = fopen(path, "r"); - struct selabel_sub *sub; + struct selabel_sub *sub = NULL; + struct stat sb; if (!cfg) return list; + if (fstat(fileno(cfg), &sb) < 0) + return list; + while (fgets_unlocked(buf, sizeof(buf) - 1, cfg)) { char *ptr = NULL; char *src = buf; @@ -115,6 +122,10 @@ struct selabel_sub *selabel_subs_init(const char *path, struct selabel_sub *list sub->next = list; list = sub; } + + if (digest_add_specfile(digest, cfg, NULL, sb.st_size, path) < 0) + goto err; + out: fclose(cfg); return list; @@ -125,6 +136,57 @@ err: goto out; } +static inline struct selabel_digest *selabel_is_digest_set + (const struct selinux_opt *opts, + unsigned n, + struct selabel_digest *entry) +{ + struct selabel_digest *digest = NULL; + + while (n--) { + if (opts[n].type == SELABEL_OPT_DIGEST && + opts[n].value == (char *)1) { + digest = calloc(1, sizeof(*digest)); + if (!digest) + goto err; + + digest->digest = calloc(1, DIGEST_SPECFILE_SIZE + 1); + if (!digest->digest) + goto err; + + digest->specfile_list = calloc(DIGEST_FILES_MAX, + sizeof(char *)); + if (!digest->specfile_list) + goto err; + + entry = digest; + return entry; + } + } + return NULL; + +err: + free(digest->digest); + free(digest->specfile_list); + free(digest); + return NULL; +} + +static void selabel_digest_fini(struct selabel_digest *ptr) +{ + int i; + + free(ptr->digest); + free(ptr->hashbuf); + + if (ptr->specfile_list) { + for (i = 0; ptr->specfile_list[i]; i++) + free(ptr->specfile_list[i]); + free(ptr->specfile_list); + } + free(ptr); +} + /* * Validation functions */ @@ -273,6 +335,7 @@ struct selabel_handle *selabel_open(unsigned int backend, rec->subs = NULL; rec->dist_subs = NULL; + rec->digest = selabel_is_digest_set(opts, nopts, rec->digest); if ((*initfuncs[backend])(rec, opts, nopts)) { free(rec); @@ -378,10 +441,28 @@ enum selabel_cmp_result selabel_cmp(struct selabel_handle *h1, return h1->func_cmp(h1, h2); } +int selabel_digest(struct selabel_handle *rec, + unsigned char **digest, size_t *digest_len, + char ***specfiles, size_t *num_specfiles) +{ + if (!rec->digest) { + errno = EINVAL; + return -1; + } + + *digest = rec->digest->digest; + *digest_len = DIGEST_SPECFILE_SIZE; + *specfiles = rec->digest->specfile_list; + *num_specfiles = rec->digest->specfile_cnt; + return 0; +} + void selabel_close(struct selabel_handle *rec) { selabel_subs_fini(rec->subs); selabel_subs_fini(rec->dist_subs); + if (rec->digest) + selabel_digest_fini(rec->digest); rec->func_close(rec); free(rec->spec_file); free(rec); |