diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2012-04-10 09:51:46 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2012-04-10 09:52:01 -0700 |
commit | 52cd377a74a710b2476c6a4c46da8b59a0dce50d (patch) | |
tree | d308c508dd880c3e50d07991cfc60c2a57b42c4f | |
parent | 3bc6d442097929a1579e91aa687d257b0cf82189 (diff) | |
parent | 35b01083fe5e34cbd318a78ef9b1a13432ae24d9 (diff) | |
download | libselinux-jb-dev.tar.gz |
Merge from upstream libselinuxandroid-sdk-adt_r20android-cts-4.1_r4android-cts-4.1_r2android-cts-4.1_r1android-4.1.2_r2.1android-4.1.2_r2android-4.1.2_r1android-4.1.1_r6.1android-4.1.1_r6android-4.1.1_r5android-4.1.1_r4android-4.1.1_r3android-4.1.1_r2android-4.1.1_r1.1android-4.1.1_r1tools_r20jb-releasejb-mr0-releasejb-devics-plus-aosp
Change-Id: I1fd35714001e3fcf9022756334cbb89611ce5c66
-rw-r--r-- | Android.mk | 3 | ||||
-rw-r--r-- | include/selinux/android.h | 4 | ||||
-rw-r--r-- | include/selinux/label.h | 2 | ||||
-rw-r--r-- | src/android.c | 103 | ||||
-rw-r--r-- | src/label.c | 7 | ||||
-rw-r--r-- | src/label_android_property.c | 296 | ||||
-rw-r--r-- | src/label_internal.h | 2 |
7 files changed, 407 insertions, 10 deletions
@@ -34,7 +34,8 @@ common_HOST_FILES := \ src/freecon.c \ src/init.c \ src/label.c \ - src/label_file.c + src/label_file.c \ + src/label_android_property.c common_COPY_HEADERS_TO := selinux diff --git a/include/selinux/android.h b/include/selinux/android.h index 883cff3..df3abc3 100644 --- a/include/selinux/android.h +++ b/include/selinux/android.h @@ -17,6 +17,10 @@ extern int selinux_android_setfilecon(const char *pkgdir, const char *name, uid_t uid); +extern int selinux_android_restorecon(const char *file); + +extern int selinux_android_seapp_context_reload(void); + #ifdef __cplusplus } #endif diff --git a/include/selinux/label.h b/include/selinux/label.h index 1a54307..8263f32 100644 --- a/include/selinux/label.h +++ b/include/selinux/label.h @@ -31,6 +31,8 @@ struct selabel_handle; #define SELABEL_CTX_X 2 /* db objects */ #define SELABEL_CTX_DB 3 +/* Android property service contexts */ +#define SELABEL_CTX_ANDROID_PROP 4 /* * Available options diff --git a/src/android.c b/src/android.c index 4768475..ad7a018 100644 --- a/src/android.c +++ b/src/android.c @@ -13,6 +13,7 @@ #include <selinux/selinux.h> #include <selinux/context.h> #include <selinux/android.h> +#include <selinux/label.h> #include "callbacks.h" #include "selinux_internal.h" @@ -22,7 +23,15 @@ * setting credentials for app processes and setting permissions * on app data directories. */ -#define SEAPP_CONTEXTS "/seapp_contexts" +static char const * const seapp_contexts_file[] = { + "/data/system/seapp_contexts", + "/seapp_contexts", + 0 }; + +static const struct selinux_opt seopts[] = { + { SELABEL_OPT_PATH, "/data/system/file_contexts" }, + { SELABEL_OPT_PATH, "/file_contexts" }, + { 0, NULL } }; struct seapp_context { /* input selectors */ @@ -83,21 +92,23 @@ static int seapp_context_cmp(const void *A, const void *B) static struct seapp_context **seapp_contexts = NULL; static int nspec = 0; -static void seapp_context_init(void) +int selinux_android_seapp_context_reload(void) { - FILE *fp; + FILE *fp = NULL; char line_buf[BUFSIZ]; - const char *path = SEAPP_CONTEXTS; char *token; unsigned lineno; struct seapp_context *cur; char *p, *name = NULL, *value = NULL, *saveptr; size_t len; + int i = 0, ret; + + while ((fp==NULL) && seapp_contexts_file[i]) + fp = fopen(seapp_contexts_file[i++], "r"); - fp = fopen(path, "r"); if (!fp) { - selinux_log(SELINUX_ERROR, "%s: could not open %s", __FUNCTION__, path); - return; + selinux_log(SELINUX_ERROR, "%s: could not open any seapp_contexts file", __FUNCTION__); + return -1; } nspec = 0; @@ -216,20 +227,30 @@ static void seapp_context_init(void) } #endif + ret = 0; + out: fclose(fp); - return; + return ret; err: selinux_log(SELINUX_ERROR, "%s: Error reading %s, line %u, name %s, value %s\n", - __FUNCTION__, path, lineno, name, value); + __FUNCTION__, seapp_contexts_file[i - 1], lineno, name, value); + ret = -1; goto out; oom: selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__); + ret = -1; goto out; } + +static void seapp_context_init(void) +{ + selinux_android_seapp_context_reload(); +} + static pthread_once_t once = PTHREAD_ONCE_INIT; int selinux_android_setfilecon(const char *pkgdir, @@ -463,3 +484,67 @@ oom: goto out; } +static struct selabel_handle *sehandle = NULL; + +static void file_context_init(void) +{ + int i = 0; + + sehandle = NULL; + while ((sehandle == NULL) && seopts[i].value) { + sehandle = selabel_open(SELABEL_CTX_FILE, &seopts[i], 1); + i++; + } + + if (!sehandle) + selinux_log(SELINUX_ERROR,"%s: Error getting sehandle label (%s)\n", + __FUNCTION__, strerror(errno)); +} + +static pthread_once_t fc_once = PTHREAD_ONCE_INIT; + +int selinux_android_restorecon(const char *pathname) +{ + + __selinux_once(fc_once, file_context_init); + + int ret; + + if (!sehandle) + goto bail; + + struct stat sb; + + if (lstat(pathname, &sb) < 0) + goto err; + + char *oldcontext, *newcontext; + + if (lgetfilecon(pathname, &oldcontext) < 0) + goto err; + + if (selabel_lookup(sehandle, &newcontext, pathname, sb.st_mode) < 0) + goto err; + + if (strcmp(newcontext, "<<none>>") && strcmp(oldcontext, newcontext)) + if (lsetfilecon(pathname, newcontext) < 0) + goto err; + + ret = 0; +out: + if (oldcontext) + freecon(oldcontext); + if (newcontext) + freecon(newcontext); + + return ret; + +err: + selinux_log(SELINUX_ERROR, + "%s: Error restoring context for %s (%s)\n", + __FUNCTION__, pathname, strerror(errno)); + +bail: + ret = -1; + goto out; +} diff --git a/src/label.c b/src/label.c index c448e3d..490d832 100644 --- a/src/label.c +++ b/src/label.c @@ -21,6 +21,10 @@ typedef int (*selabel_initfunc)(struct selabel_handle *rec, static selabel_initfunc initfuncs[] = { &selabel_file_init, + NULL, + NULL, + NULL, + &selabel_property_init, }; /* @@ -67,6 +71,9 @@ struct selabel_handle *selabel_open(unsigned int backend, goto out; } + if (initfuncs[backend] == NULL) + goto out; + rec = (struct selabel_handle *)malloc(sizeof(*rec)); if (!rec) goto out; diff --git a/src/label_android_property.c b/src/label_android_property.c new file mode 100644 index 0000000..cf73ec1 --- /dev/null +++ b/src/label_android_property.c @@ -0,0 +1,296 @@ +/* + * Property Service contexts backend for labeling Android + * property keys + */ + +#include <stdarg.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "callbacks.h" +#include "label_internal.h" + +/* A property security context specification. */ +typedef struct spec { + struct selabel_lookup_rec lr; /* holds contexts for lookup result */ + char *property_key; /* property key string */ +} spec_t; + +/* Our stored configuration */ +struct saved_data { + /* + * The array of specifications is sorted for longest + * prefix match + */ + spec_t *spec_arr; + unsigned int nspec; /* total number of specifications */ +}; + +static int cmp(const void *A, const void *B) +{ + const struct spec *sp1 = A, *sp2 = B; + + if (strncmp(sp1->property_key,"*",1) == 0) + return 1; + if (strncmp(sp2->property_key,"*",1) == 0) + return -1; + + size_t L1 = strlen(sp1->property_key); + size_t L2 = strlen(sp2->property_key); + + return (L1 < L2) - (L1 > L2); +} + +/* + * Warn about duplicate specifications. + */ +static int nodups_specs(struct saved_data *data, const char *path) +{ + int rc = 0; + unsigned int ii, jj; + struct spec *curr_spec, *spec_arr = data->spec_arr; + + for (ii = 0; ii < data->nspec; ii++) { + curr_spec = &spec_arr[ii]; + for (jj = ii + 1; jj < data->nspec; jj++) { + if ((!strcmp(spec_arr[jj].property_key, curr_spec->property_key))) { + rc = -1; + errno = EINVAL; + if (strcmp + (spec_arr[jj].lr.ctx_raw, + curr_spec->lr.ctx_raw)) { + selinux_log + (SELINUX_ERROR, + "%s: Multiple different specifications for %s (%s and %s).\n", + path, curr_spec->property_key, + spec_arr[jj].lr.ctx_raw, + curr_spec->lr.ctx_raw); + } else { + selinux_log + (SELINUX_ERROR, + "%s: Multiple same specifications for %s.\n", + path, curr_spec->property_key); + } + } + } + } + return rc; +} + +static int process_line(struct selabel_handle *rec, + const char *path, char *line_buf, + int pass, unsigned lineno) +{ + int items, len; + char buf1[BUFSIZ], buf2[BUFSIZ]; + char *buf_p, *prop = buf1, *context = buf2; + struct saved_data *data = (struct saved_data *)rec->data; + spec_t *spec_arr = data->spec_arr; + unsigned int nspec = data->nspec; + + len = strlen(line_buf); + if (line_buf[len - 1] == '\n') + line_buf[len - 1] = 0; + buf_p = line_buf; + while (isspace(*buf_p)) + buf_p++; + /* Skip comment lines and empty lines. */ + if (*buf_p == '#' || *buf_p == 0) + return 0; + items = sscanf(line_buf, "%255s %255s", prop, context); + if (items != 2) { + selinux_log(SELINUX_WARNING, + "%s: line %d is missing fields, skipping\n", path, + lineno); + return 0; + } + + if (pass == 1) { + /* On the second pass, process and store the specification in spec. */ + spec_arr[nspec].property_key = strdup(prop); + if (!spec_arr[nspec].property_key) { + selinux_log(SELINUX_WARNING, + "%s: out of memory at line %d on prop %s\n", + path, lineno, prop); + return -1; + + } + + spec_arr[nspec].lr.ctx_raw = strdup(context); + if (!spec_arr[nspec].lr.ctx_raw) { + selinux_log(SELINUX_WARNING, + "%s: out of memory at line %d on context %s\n", + path, lineno, context); + return -1; + } + } + + data->nspec = ++nspec; + return 0; +} + +static int init(struct selabel_handle *rec, struct selinux_opt *opts, + unsigned n) +{ + struct saved_data *data = (struct saved_data *)rec->data; + const char *path = NULL; + FILE *fp; + char line_buf[BUFSIZ]; + unsigned int lineno = 0, maxnspec, pass; + int status = -1; + struct stat sb; + + /* Process arguments */ + while (n--) + switch (opts[n].type) { + case SELABEL_OPT_PATH: + path = opts[n].value; + break; + default: + selinux_log(SELINUX_WARNING, + "Argument type (%d) not recognized. Skipping\n", opts[n].type); + break; + } + + /* Open the specification file. */ + if ((fp = fopen(path, "r")) == NULL) + return -1; + + if (fstat(fileno(fp), &sb) < 0) + return -1; + if (!S_ISREG(sb.st_mode)) { + errno = EINVAL; + return -1; + } + + /* + * Two passes of the specification file. First is to get the size. + * After the first pass, the spec array is malloced to the appropriate + * size. Second pass is to populate the spec array and check for + * dups. + */ + maxnspec = UINT_MAX / sizeof(spec_t); + for (pass = 0; pass < 2; pass++) { + data->nspec = 0; + + while (fgets(line_buf, sizeof line_buf - 1, fp) + && data->nspec < maxnspec) { + if (process_line(rec, path, line_buf, pass, ++lineno) != 0) { + goto finish; + } + } + + if (pass == 1) { + status = nodups_specs(data, path); + + if (status) + goto finish; + } + + if (pass == 0) { + + if (data->nspec == 0) { + status = 0; + goto finish; + } + + if (NULL == (data->spec_arr = + malloc(sizeof(spec_t) * data->nspec))) + goto finish; + + memset(data->spec_arr, 0, sizeof(spec_t)*data->nspec); + maxnspec = data->nspec; + rewind(fp); + } + } + + qsort(data->spec_arr, data->nspec, sizeof(struct spec), cmp); + + status = 0; +finish: + fclose(fp); + return status; +} + +/* + * Backend interface routines + */ +static void closef(struct selabel_handle *rec) +{ + struct saved_data *data = (struct saved_data *)rec->data; + struct spec *spec; + unsigned int i; + + for (i = 0; i < data->nspec; i++) { + spec = &data->spec_arr[i]; + free(spec->property_key); + free(spec->lr.ctx_raw); + free(spec->lr.ctx_trans); + } + + if (data->spec_arr) + free(data->spec_arr); + + free(data); +} + +static struct selabel_lookup_rec *lookup(struct selabel_handle *rec, + const char *key, + int __attribute__((unused)) type) +{ + struct saved_data *data = (struct saved_data *)rec->data; + spec_t *spec_arr = data->spec_arr; + unsigned int i; + struct selabel_lookup_rec *ret = NULL; + + if (!data->nspec) { + errno = ENOENT; + goto finish; + } + + for (i = 0; i < data->nspec; i++) { + if (strncmp(spec_arr[i].property_key, key, + strlen(spec_arr[i].property_key)) == 0) { + break; + } + if (strncmp(spec_arr[i].property_key, "*", 1) == 0) + break; + } + + if (i >= data->nspec) { + /* No matching specification. */ + errno = ENOENT; + goto finish; + } + + ret = &spec_arr[i].lr; + +finish: + return ret; +} + +static void stats(struct selabel_handle __attribute__((unused)) *rec) +{ + selinux_log(SELINUX_WARNING, "'stats' functionality not implemented.\n"); +} + +int selabel_property_init(struct selabel_handle *rec, struct selinux_opt *opts, + unsigned nopts) +{ + struct saved_data *data; + + data = (struct saved_data *)malloc(sizeof(*data)); + if (!data) + return -1; + memset(data, 0, sizeof(*data)); + + rec->data = data; + rec->func_close = &closef; + rec->func_stats = &stats; + rec->func_lookup = &lookup; + + return init(rec, opts, nopts); +} diff --git a/src/label_internal.h b/src/label_internal.h index 37a21db..5192d4d 100644 --- a/src/label_internal.h +++ b/src/label_internal.h @@ -25,6 +25,8 @@ int selabel_x_init(struct selabel_handle *rec, struct selinux_opt *opts, unsigned nopts) hidden; int selabel_db_init(struct selabel_handle *rec, struct selinux_opt *opts, unsigned nopts) hidden; +int selabel_property_init(struct selabel_handle *rec, + struct selinux_opt *opts, unsigned nopts) hidden; /* * Labeling internal structures |