aboutsummaryrefslogtreecommitdiffstats
path: root/libselinux/src/label.c
diff options
context:
space:
mode:
authorRichard Haines <richard_c_haines@btinternet.com>2015-09-30 16:29:20 +0100
committerStephen Smalley <sds@tycho.nsa.gov>2015-10-13 17:13:24 -0400
commite40bbea95f555fe9708cbbc39895bd67a8ac6c48 (patch)
tree04c5edad51f2f00845887003700c7ec79927379d /libselinux/src/label.c
parentc9c1f273708777c8923268cf61798ed0dc2ffded (diff)
downloadandroid_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.c85
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);