diff --git a/libselinux/include/selinux/android.h b/libselinux/include/selinux/android.h index 60813248..1249133f 100644 --- a/libselinux/include/selinux/android.h +++ b/libselinux/include/selinux/android.h @@ -11,38 +11,61 @@ extern "C" { #endif +/* Returns the file context handle */ extern struct selabel_handle* selinux_android_file_context_handle(void); +/* Returns the service context handle */ extern struct selabel_handle* selinux_android_service_context_handle(void); +/* Returns the hardware service context handle */ extern struct selabel_handle* selinux_android_hw_service_context_handle(void); +/* Returns the vendor service context handle */ extern struct selabel_handle* selinux_android_vendor_service_context_handle(void); +/* Returns the keystore2 context handle */ extern struct selabel_handle* selinux_android_keystore2_key_context_handle(void); +/* Sets the file context handle. Must be called using the output of + * selinux_android_file_context_handle. This function can be used to preload + * the file_contexts files and speed up later calls to + * selinux_android_restorecon and selinux_android_restorecon_pkgdir */ extern void selinux_android_set_sehandle(const struct selabel_handle *hndl); +/* Deprecated. Loads the default policy from /sepolicy. The policy loading is + * done directly by init. See system/core/init/selinux.cpp. */ extern int selinux_android_load_policy(void); +/* Deprecated. Loads a policy from fd. The policy loading is done directly by + * init. See system/core/init/selinux.cpp. */ extern int selinux_android_load_policy_from_fd(int fd, const char *description); +/* Sets the context of the current process. This should be used in preference + * to setcon() on Android. */ extern int selinux_android_setcon(const char *con); +/* Sets the context of the current app process based on the information + * provided. Returns -1 if no matching context is found or the transition + * failed */ extern int selinux_android_setcontext(uid_t uid, bool isSystemServer, const char *seinfo, const char *name); +/* Builds a new context based on context, adding the categories from userid and + * appid. If userid or appid are -1, the corresponding categories are not + * modified. */ extern int selinux_android_context_with_level(const char * context, char ** newContext, uid_t userid, uid_t appid); +/* Provides a log callback that uses the Android logging facility. See selinux_set_callback. */ extern int selinux_log_callback(int type, const char *fmt, ...) __attribute__ ((format(printf, 2, 3))); -// API to support legacy usecase where full-treble legacy VNDK vendor needs to use this callback. +/* Provides a log callback that uses the Android logging facility for vendors. + * See selinux_set_callback. */ extern int selinux_vendor_log_callback(int type, const char *fmt, ...) __attribute__ ((format(printf, 2, 3))); @@ -54,15 +77,23 @@ extern int selinux_vendor_log_callback(int type, const char *fmt, ...) #define SELINUX_ANDROID_RESTORECON_SKIPCE 32 #define SELINUX_ANDROID_RESTORECON_CROSS_FILESYSTEMS 64 #define SELINUX_ANDROID_RESTORECON_SKIP_SEHASH 128 +/* Restores the security context of a file. */ extern int selinux_android_restorecon(const char *file, unsigned int flags); +/* Restores the security context of a package's private directory. */ extern int selinux_android_restorecon_pkgdir(const char *pkgdir, const char *seinfo, uid_t uid, unsigned int flags); +/* Initialize the seapp contexts for future lookups. Loads all the + * seapp_contexts files. To force a reload of the files, use + * selinux_android_seapp_context_reload. While not required, this function can + * be used to speed up the inital calls to selinux_android_setcontext, + * selinux_android_restorecon and selinux_android_restorecon_pkgdir. */ extern void selinux_android_seapp_context_init(void); +/* Forces a reload of the seapp_contexts files. */ extern int selinux_android_seapp_context_reload(void); #ifdef __cplusplus diff --git a/libselinux/src/android/android.c b/libselinux/src/android/android.c index 7ee9e774..169af51f 100644 --- a/libselinux/src/android/android.c +++ b/libselinux/src/android/android.c @@ -1,239 +1,167 @@ #include "android_common.h" -// For 'system', 'system_ext' (optional), 'product' (optional), 'vendor' (mandatory) -// and/or 'odm' (optional). -#define MAX_FILE_CONTEXT_SIZE 5 - #ifdef __ANDROID_VNDK__ #ifndef LOG_EVENT_STRING #define LOG_EVENT_STRING(...) #endif // LOG_EVENT_STRING #endif // __ANDROID_VNDK__ -static const struct selinux_opt seopts_service_plat[] = { - { SELABEL_OPT_PATH, "/system/etc/selinux/plat_service_contexts" }, - { SELABEL_OPT_PATH, "/plat_service_contexts" } -}; -static const struct selinux_opt seopts_service_apex[] = { - { SELABEL_OPT_PATH, "/dev/selinux/apex_service_contexts" } -}; -static const struct selinux_opt seopts_service_system_ext[] = { - { SELABEL_OPT_PATH, "/system_ext/etc/selinux/system_ext_service_contexts" }, - { SELABEL_OPT_PATH, "/system_ext_service_contexts" } -}; -static const struct selinux_opt seopts_service_product[] = { - { SELABEL_OPT_PATH, "/product/etc/selinux/product_service_contexts" }, - { SELABEL_OPT_PATH, "/product_service_contexts" } -}; -static const struct selinux_opt seopts_service_vendor[] = { - { SELABEL_OPT_PATH, "/vendor/etc/selinux/vendor_service_contexts" }, - { SELABEL_OPT_PATH, "/vendor_service_contexts" } +static const char* const service_context_paths[MAX_CONTEXT_PATHS][MAX_ALT_CONTEXT_PATHS] = { + { + "/system/etc/selinux/plat_service_contexts", + "/plat_service_contexts" + }, + { + "/dev/selinux/apex_service_contexts" + }, + { + "/system_ext/etc/selinux/system_ext_service_contexts", + "/system_ext_service_contexts" + }, + { + "/product/etc/selinux/product_service_contexts", + "/product_service_contexts" + }, + { + "/vendor/etc/selinux/vendor_service_contexts", + "/vendor_service_contexts" + } }; -static const struct selinux_opt seopts_hwservice_plat[] = { - { SELABEL_OPT_PATH, "/system/etc/selinux/plat_hwservice_contexts" }, - { SELABEL_OPT_PATH, "/plat_hwservice_contexts" } -}; -static const struct selinux_opt seopts_hwservice_system_ext[] = { - { SELABEL_OPT_PATH, "/system_ext/etc/selinux/system_ext_hwservice_contexts" }, - { SELABEL_OPT_PATH, "/system_ext_hwservice_contexts" } -}; -static const struct selinux_opt seopts_hwservice_product[] = { - { SELABEL_OPT_PATH, "/product/etc/selinux/product_hwservice_contexts" }, - { SELABEL_OPT_PATH, "/product_hwservice_contexts" } -}; -static const struct selinux_opt seopts_hwservice_vendor[] = { - { SELABEL_OPT_PATH, "/vendor/etc/selinux/vendor_hwservice_contexts" }, - { SELABEL_OPT_PATH, "/vendor_hwservice_contexts" } -}; -static const struct selinux_opt seopts_hwservice_odm[] = { - { SELABEL_OPT_PATH, "/odm/etc/selinux/odm_hwservice_contexts" }, - { SELABEL_OPT_PATH, "/odm_hwservice_contexts" } +static const char* const hwservice_context_paths[MAX_CONTEXT_PATHS][MAX_ALT_CONTEXT_PATHS] = { + { + "/system/etc/selinux/plat_hwservice_contexts", + "/plat_hwservice_contexts" + }, + { + "/system_ext/etc/selinux/system_ext_hwservice_contexts", + "/system_ext_hwservice_contexts" + }, + { + "/product/etc/selinux/product_hwservice_contexts", + "/product_hwservice_contexts" + }, + { + "/vendor/etc/selinux/vendor_hwservice_contexts", + "/vendor_hwservice_contexts" + }, + { + "/odm/etc/selinux/odm_hwservice_contexts", + "/odm_hwservice_contexts" + }, }; -static const struct selinux_opt seopts_vndservice = - { SELABEL_OPT_PATH, "/vendor/etc/selinux/vndservice_contexts" }; - -static const struct selinux_opt seopts_vndservice_rootfs = - { SELABEL_OPT_PATH, "/vndservice_contexts" }; - -static const struct selinux_opt seopts_keystore2_key_plat[] = { - { SELABEL_OPT_PATH, "/system/etc/selinux/plat_keystore2_key_contexts" }, - { SELABEL_OPT_PATH, "/plat_keystore2_key_contexts" } -}; -static const struct selinux_opt seopts_keystore2_key_system_ext[] = { - { SELABEL_OPT_PATH, "/system_ext/etc/selinux/system_ext_keystore2_key_contexts" }, - { SELABEL_OPT_PATH, "/system_ext_keystore2_key_contexts" } -}; -static const struct selinux_opt seopts_keystore2_key_product[] = { - { SELABEL_OPT_PATH, "/product/etc/selinux/product_keystore2_key_contexts" }, - { SELABEL_OPT_PATH, "/product_keystore2_key_contexts" } -}; -static const struct selinux_opt seopts_keystore2_key_vendor[] = { - { SELABEL_OPT_PATH, "/vendor/etc/selinux/vendor_keystore2_key_contexts" }, - { SELABEL_OPT_PATH, "/vendor_keystore2_key_contexts" }, +static const char* const vndservice_context_paths[MAX_CONTEXT_PATHS][MAX_ALT_CONTEXT_PATHS] = { + { + "/vendor/etc/selinux/vndservice_contexts", + "/vndservice_contexts" + } }; -struct selabel_handle* selinux_android_service_open_context_handle(const struct selinux_opt* seopts_service, - unsigned nopts) +static const char* const keystore2_context_paths[MAX_CONTEXT_PATHS][MAX_ALT_CONTEXT_PATHS] = { + { + "/system/etc/selinux/plat_keystore2_key_contexts", + "/plat_keystore2_key_contexts" + }, + { + "/system_ext/etc/selinux/system_ext_keystore2_key_contexts", + "/system_ext_keystore2_key_contexts" + }, + { + "/product/etc/selinux/product_keystore2_key_contexts", + "/product_keystore2_key_contexts" + }, + { + "/vendor/etc/selinux/vendor_keystore2_key_contexts", + "/vendor_keystore2_key_contexts" + } +}; + +size_t find_existing_files( + const char* const path_sets[MAX_CONTEXT_PATHS][MAX_ALT_CONTEXT_PATHS], + const char* paths[MAX_CONTEXT_PATHS]) { - struct selabel_handle* sehandle; - - sehandle = selabel_open(SELABEL_CTX_ANDROID_SERVICE, - seopts_service, nopts); - - if (!sehandle) { - selinux_log(SELINUX_ERROR, "%s: Error getting service context handle (%s)\n", - __FUNCTION__, strerror(errno)); - return NULL; - } - selinux_log(SELINUX_INFO, "SELinux: Loaded service_contexts from:\n"); - for (unsigned i = 0; i < nopts; i++) { - selinux_log(SELINUX_INFO, " %s\n", seopts_service[i].value); - } - return sehandle; + size_t i, j, len = 0; + for (i = 0; i < MAX_CONTEXT_PATHS; i++) { + for (j = 0; j < MAX_ALT_CONTEXT_PATHS; j++) { + const char* file = path_sets[i][j]; + if (file && access(file, R_OK) != -1) { + paths[len++] = file; + /* Within each set, only the first valid entry is used */ + break; + } + } + } + return len; } -struct selabel_handle* selinux_android_keystore2_key_open_context_handle(const struct selinux_opt* seopts_service, - unsigned nopts) +void paths_to_opts(const char* paths[MAX_CONTEXT_PATHS], + size_t npaths, + struct selinux_opt* const opts) { - struct selabel_handle* sehandle; + for (size_t i = 0; i < npaths; i++) { + opts[i].type = SELABEL_OPT_PATH; + opts[i].value = paths[i]; + } +} - sehandle = selabel_open(SELABEL_CTX_ANDROID_KEYSTORE2_KEY, - seopts_service, nopts); +struct selabel_handle* initialize_backend( + unsigned int backend, + const char* name, + const struct selinux_opt* opts, + size_t nopts) +{ + struct selabel_handle* sehandle; - if (!sehandle) { - selinux_log(SELINUX_ERROR, "%s: Error getting keystore key context handle (%s)\n", - __FUNCTION__, strerror(errno)); - return NULL; - } - selinux_log(SELINUX_INFO, "SELinux: Loaded keystore2_key_contexts from:\n"); - for (unsigned i = 0; i < nopts; i++) { - selinux_log(SELINUX_INFO, " %s\n", seopts_service[i].value); - } - return sehandle; + sehandle = selabel_open(backend, opts, nopts); + + if (!sehandle) { + selinux_log(SELINUX_ERROR, "%s: Error getting %s handle (%s)\n", + __FUNCTION__, name, strerror(errno)); + return NULL; + } + selinux_log(SELINUX_INFO, "SELinux: Loaded %s context from:\n", name); + for (unsigned i = 0; i < nopts; i++) { + if (opts[i].type == SELABEL_OPT_PATH) + selinux_log(SELINUX_INFO, " %s\n", opts[i].value); + } + return sehandle; +} + +/* Initialize a backend using a set of context paths */ +static struct selabel_handle* context_handle( + unsigned int backend, + const char* const context_paths[MAX_CONTEXT_PATHS][MAX_ALT_CONTEXT_PATHS], + char *name) +{ + const char* existing_paths[MAX_CONTEXT_PATHS]; + struct selinux_opt opts[MAX_CONTEXT_PATHS]; + int size = 0; + + size = find_existing_files(context_paths, existing_paths); + paths_to_opts(existing_paths, size, opts); + + return initialize_backend(backend, name, opts, size); } struct selabel_handle* selinux_android_service_context_handle(void) { - struct selinux_opt seopts_service[MAX_FILE_CONTEXT_SIZE]; - int size = 0; - unsigned int i; - for (i = 0; i < ARRAY_SIZE(seopts_service_plat); i++) { - if (access(seopts_service_plat[i].value, R_OK) != -1) { - seopts_service[size++] = seopts_service_plat[i]; - break; - } - } - for (i = 0; i < ARRAY_SIZE(seopts_service_apex); i++) { - if (access(seopts_service_apex[i].value, R_OK) != -1) { - seopts_service[size++] = seopts_service_apex[i]; - break; - } - } - for (i = 0; i < ARRAY_SIZE(seopts_service_system_ext); i++) { - if (access(seopts_service_system_ext[i].value, R_OK) != -1) { - seopts_service[size++] = seopts_service_system_ext[i]; - break; - } - } - for (i = 0; i < ARRAY_SIZE(seopts_service_product); i++) { - if (access(seopts_service_product[i].value, R_OK) != -1) { - seopts_service[size++] = seopts_service_product[i]; - break; - } - } - for (i = 0; i < ARRAY_SIZE(seopts_service_vendor); i++) { - if (access(seopts_service_vendor[i].value, R_OK) != -1) { - seopts_service[size++] = seopts_service_vendor[i]; - break; - } - } - - return selinux_android_service_open_context_handle(seopts_service, size); + return context_handle(SELABEL_CTX_ANDROID_SERVICE, service_context_paths, "service"); } struct selabel_handle* selinux_android_hw_service_context_handle(void) { - struct selinux_opt seopts_service[MAX_FILE_CONTEXT_SIZE]; - int size = 0; - unsigned int i; - for (i = 0; i < ARRAY_SIZE(seopts_hwservice_plat); i++) { - if (access(seopts_hwservice_plat[i].value, R_OK) != -1) { - seopts_service[size++] = seopts_hwservice_plat[i]; - break; - } - } - for (i = 0; i < ARRAY_SIZE(seopts_hwservice_system_ext); i++) { - if (access(seopts_hwservice_system_ext[i].value, R_OK) != -1) { - seopts_service[size++] = seopts_hwservice_system_ext[i]; - break; - } - } - for (i = 0; i < ARRAY_SIZE(seopts_hwservice_product); i++) { - if (access(seopts_hwservice_product[i].value, R_OK) != -1) { - seopts_service[size++] = seopts_hwservice_product[i]; - break; - } - } - for (i = 0; i < ARRAY_SIZE(seopts_hwservice_vendor); i++) { - if (access(seopts_hwservice_vendor[i].value, R_OK) != -1) { - seopts_service[size++] = seopts_hwservice_vendor[i]; - break; - } - } - for (i = 0; i < ARRAY_SIZE(seopts_hwservice_odm); i++) { - if (access(seopts_hwservice_odm[i].value, R_OK) != -1) { - seopts_service[size++] = seopts_hwservice_odm[i]; - break; - } - } - return selinux_android_service_open_context_handle(seopts_service, size); + return context_handle(SELABEL_CTX_ANDROID_SERVICE, hwservice_context_paths, "hwservice"); } struct selabel_handle* selinux_android_vendor_service_context_handle(void) { - const struct selinux_opt* seopts_service; - if (access(seopts_vndservice.value, R_OK) != -1) { - seopts_service = &seopts_vndservice; - } else { - seopts_service = &seopts_vndservice_rootfs; - } - - return selinux_android_service_open_context_handle(seopts_service, 1); + return context_handle(SELABEL_CTX_ANDROID_SERVICE, vndservice_context_paths, "vndservice"); } struct selabel_handle* selinux_android_keystore2_key_context_handle(void) { - struct selinux_opt seopts_keystore2_key[MAX_FILE_CONTEXT_SIZE]; - int size = 0; - unsigned int i; - for (i = 0; i < ARRAY_SIZE(seopts_keystore2_key_plat); i++) { - if (access(seopts_keystore2_key_plat[i].value, R_OK) != -1) { - seopts_keystore2_key[size++] = seopts_keystore2_key_plat[i]; - break; - } - } - for (i = 0; i < ARRAY_SIZE(seopts_keystore2_key_system_ext); i++) { - if (access(seopts_keystore2_key_system_ext[i].value, R_OK) != -1) { - seopts_keystore2_key[size++] = seopts_keystore2_key_system_ext[i]; - break; - } - } - for (i = 0; i < ARRAY_SIZE(seopts_keystore2_key_product); i++) { - if (access(seopts_keystore2_key_product[i].value, R_OK) != -1) { - seopts_keystore2_key[size++] = seopts_keystore2_key_product[i]; - break; - } - } - for (i = 0; i < ARRAY_SIZE(seopts_keystore2_key_vendor); i++) { - if (access(seopts_keystore2_key_vendor[i].value, R_OK) != -1) { - seopts_keystore2_key[size++] = seopts_keystore2_key_vendor[i]; - break; - } - } - - return selinux_android_keystore2_key_open_context_handle(seopts_keystore2_key, size); + return context_handle(SELABEL_CTX_ANDROID_KEYSTORE2_KEY, keystore2_context_paths, "keystore2"); } int selinux_log_callback(int type, const char *fmt, ...) diff --git a/libselinux/src/android/android_common.h b/libselinux/src/android/android_common.h index 78b2e712..db634945 100644 --- a/libselinux/src/android/android_common.h +++ b/libselinux/src/android/android_common.h @@ -1,5 +1,3 @@ - -#include #include #include #include @@ -40,3 +38,9 @@ #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #define FC_DIGEST_SIZE SHA_DIGEST_LENGTH + +// Context files (file_contexts, service_contexts, etc) may be spread over +// multiple partitions: system, apex, system_ext, product, vendor and/or odm. +#define MAX_CONTEXT_PATHS 6 +// The maximum number of alternatives for a file on one partition. +#define MAX_ALT_CONTEXT_PATHS 2 diff --git a/libselinux/src/android/android_internal.h b/libselinux/src/android/android_internal.h new file mode 100644 index 00000000..f7764c63 --- /dev/null +++ b/libselinux/src/android/android_internal.h @@ -0,0 +1,24 @@ +#include + +#include "android_common.h" + +/* Within each set of files, adds the first file that is accessible to `paths`. + * Returns the number of accessible files. */ +size_t find_existing_files( + const char* const path_sets[MAX_CONTEXT_PATHS][MAX_ALT_CONTEXT_PATHS], + const char* paths[MAX_CONTEXT_PATHS]); + +/* Converts an array of file paths into an array of options for selabel_open. + * opts must be at least as large as paths. */ +void paths_to_opts( + const char* paths[MAX_CONTEXT_PATHS], + size_t npaths, + struct selinux_opt* const opts); + +/* Initialize a backend using the specified options. Ensure that any error is + * reported to the android logging facility */ +struct selabel_handle* initialize_backend( + unsigned int backend, + const char* name, + const struct selinux_opt* opts, + size_t nopts); diff --git a/libselinux/src/android/android_platform.c b/libselinux/src/android/android_platform.c index 05c923bc..ad08c596 100644 --- a/libselinux/src/android/android_platform.c +++ b/libselinux/src/android/android_platform.c @@ -1,136 +1,98 @@ #include "android_common.h" +#include "android_internal.h" #include -// For 'system', 'system_ext' (optional), 'apex' (optional), 'product' (optional), -// 'vendor' (mandatory) and/or 'odm' (optional) . -#define MAX_FILE_CONTEXT_SIZE 6 - static const char *const sepolicy_file = "/sepolicy"; -static const struct selinux_opt seopts_file_plat[] = { - { SELABEL_OPT_PATH, "/system/etc/selinux/plat_file_contexts" }, - { SELABEL_OPT_PATH, "/plat_file_contexts" } -}; -static const struct selinux_opt seopts_file_apex[] = { - { SELABEL_OPT_PATH, "/dev/selinux/apex_file_contexts" } -}; -static const struct selinux_opt seopts_file_system_ext[] = { - { SELABEL_OPT_PATH, "/system_ext/etc/selinux/system_ext_file_contexts" }, - { SELABEL_OPT_PATH, "/system_ext_file_contexts" } -}; -static const struct selinux_opt seopts_file_product[] = { - { SELABEL_OPT_PATH, "/product/etc/selinux/product_file_contexts" }, - { SELABEL_OPT_PATH, "/product_file_contexts" } -}; -static const struct selinux_opt seopts_file_vendor[] = { - { SELABEL_OPT_PATH, "/vendor/etc/selinux/vendor_file_contexts" }, - { SELABEL_OPT_PATH, "/vendor_file_contexts" } -}; -static const struct selinux_opt seopts_file_odm[] = { - { SELABEL_OPT_PATH, "/odm/etc/selinux/odm_file_contexts" }, - { SELABEL_OPT_PATH, "/odm_file_contexts" } -}; - -/* - * XXX Where should this configuration file be located? - * Needs to be accessible by zygote and installd when - * setting credentials for app processes and setting permissions - * on app data directories. +/* Locations for the file_contexts files. For each partition, only the first + * existing entry will be used (for example, if + * /system/etc/selinux/plat_file_contexts exists, /plat_file_contexts will be + * ignored). */ -static char const * const seapp_contexts_plat[] = { - "/system/etc/selinux/plat_seapp_contexts", - "/plat_seapp_contexts" -}; -static char const * const seapp_contexts_apex[] = { - "/dev/selinux/apex_seapp_contexts" -}; -static char const * const seapp_contexts_system_ext[] = { - "/system_ext/etc/selinux/system_ext_seapp_contexts", - "/system_ext_seapp_contexts" -}; -static char const * const seapp_contexts_product[] = { - "/product/etc/selinux/product_seapp_contexts", - "/product_seapp_contexts" -}; -static char const * const seapp_contexts_vendor[] = { - "/vendor/etc/selinux/vendor_seapp_contexts", - "/vendor_seapp_contexts" -}; -static char const * const seapp_contexts_odm[] = { - "/odm/etc/selinux/odm_seapp_contexts", - "/odm_seapp_contexts" +static const char* const file_context_paths[MAX_CONTEXT_PATHS][MAX_ALT_CONTEXT_PATHS] = { + { + "/system/etc/selinux/plat_file_contexts", + "/plat_file_contexts" + }, + { + "/dev/selinux/apex_file_contexts", + }, + { + "/system_ext/etc/selinux/system_ext_file_contexts", + "/system_ext_file_contexts" + }, + { + "/product/etc/selinux/product_file_contexts", + "/product_file_contexts" + }, + { + "/vendor/etc/selinux/vendor_file_contexts", + "/vendor_file_contexts" + }, + { + "/odm/etc/selinux/odm_file_contexts", + "/odm_file_contexts" + } }; -static struct selabel_handle* selinux_android_file_context(const struct selinux_opt *opts, - unsigned nopts) -{ - struct selabel_handle *sehandle; - struct selinux_opt fc_opts[nopts + 1]; - - memcpy(fc_opts, opts, nopts*sizeof(struct selinux_opt)); - fc_opts[nopts].type = SELABEL_OPT_BASEONLY; - fc_opts[nopts].value = (char *)1; - - sehandle = selabel_open(SELABEL_CTX_FILE, fc_opts, ARRAY_SIZE(fc_opts)); - if (!sehandle) { - selinux_log(SELINUX_ERROR, "%s: Error getting file context handle (%s)\n", - __FUNCTION__, strerror(errno)); - return NULL; - } - - selinux_log(SELINUX_INFO, "SELinux: Loaded file_contexts\n"); - - return sehandle; -} +/* Locations for the seapp_contexts files. For each partition, only the first + * existing entry will be used (for example, if + * /system/etc/selinux/plat_seapp_contexts exists, /plat_seapp_contexts will be + * ignored). + */ +static const char* const seapp_context_paths[MAX_CONTEXT_PATHS][MAX_ALT_CONTEXT_PATHS] = { + { + "/system/etc/selinux/plat_seapp_contexts", + "/plat_seapp_contexts" + }, + { + "/dev/selinux/apex_seapp_contexts", + }, + { + "/system_ext/etc/selinux/system_ext_seapp_contexts", + "/system_ext_seapp_contexts" + }, + { + "/product/etc/selinux/product_seapp_contexts", + "/product_seapp_contexts" + }, + { + "/vendor/etc/selinux/vendor_seapp_contexts", + "/vendor_seapp_contexts" + }, + { + "/odm/etc/selinux/odm_seapp_contexts", + "/odm_seapp_contexts" + } +}; +/* Returns a handle for the file contexts backend, initialized with the Android + * configuration */ struct selabel_handle* selinux_android_file_context_handle(void) { - struct selinux_opt seopts_file[MAX_FILE_CONTEXT_SIZE]; - int size = 0; - unsigned int i; - for (i = 0; i < ARRAY_SIZE(seopts_file_plat); i++) { - if (access(seopts_file_plat[i].value, R_OK) != -1) { - seopts_file[size++] = seopts_file_plat[i]; - break; - } - } - for (i = 0; i < ARRAY_SIZE(seopts_file_apex); i++) { - if (access(seopts_file_apex[i].value, R_OK) != -1) { - seopts_file[size++] = seopts_file_apex[i]; - break; - } - } - for (i = 0; i < ARRAY_SIZE(seopts_file_system_ext); i++) { - if (access(seopts_file_system_ext[i].value, R_OK) != -1) { - seopts_file[size++] = seopts_file_system_ext[i]; - break; - } - } - for (i = 0; i < ARRAY_SIZE(seopts_file_product); i++) { - if (access(seopts_file_product[i].value, R_OK) != -1) { - seopts_file[size++] = seopts_file_product[i]; - break; - } - } - for (i = 0; i < ARRAY_SIZE(seopts_file_vendor); i++) { - if (access(seopts_file_vendor[i].value, R_OK) != -1) { - seopts_file[size++] = seopts_file_vendor[i]; - break; - } - } - for (i = 0; i < ARRAY_SIZE(seopts_file_odm); i++) { - if (access(seopts_file_odm[i].value, R_OK) != -1) { - seopts_file[size++] = seopts_file_odm[i]; - break; - } - } - return selinux_android_file_context(seopts_file, size); + const char* file_contexts[MAX_CONTEXT_PATHS]; + struct selinux_opt opts[MAX_CONTEXT_PATHS + 1]; + int npaths, nopts; + + npaths = find_existing_files(file_context_paths, file_contexts); + paths_to_opts(file_contexts, npaths, opts); + + opts[npaths].type = SELABEL_OPT_BASEONLY; + opts[npaths].value = (char *) 1; + nopts = npaths + 1; + + return initialize_backend(SELABEL_CTX_FILE, "file", opts, nopts); } +/* Which categories should be associated to the process */ enum levelFrom { + /* None */ LEVELFROM_NONE, + /* The categories of the application */ LEVELFROM_APP, + /* The categories of the end-user */ LEVELFROM_USER, + /* Application and end-user */ LEVELFROM_ALL }; @@ -156,6 +118,9 @@ static void free_prefix_str(struct prefix_str *p) free(p->str); } +/* For a set of selectors, represents the contexts that should be applied to an + * app and its data. Each instance is based on a line in a seapp_contexts file. + * */ struct seapp_context { /* input selectors */ bool isSystemServer; @@ -188,8 +153,10 @@ static void free_seapp_context(struct seapp_context *s) free(s->level); } +/* If any duplicate was found while sorting the entries */ static bool seapp_contexts_dup = false; +/* Compare two seapp_context. Used to sort all the entries found. */ static int seapp_context_cmp(const void *A, const void *B) { const struct seapp_context *const *sp1 = (const struct seapp_context *const *) A; @@ -288,7 +255,9 @@ static int seapp_context_cmp(const void *A, const void *B) return 0; } +/* Array of all the seapp_context entries configured. */ static struct seapp_context **seapp_contexts = NULL; +/* Size of seapp_contexts */ static int nspec = 0; static void free_seapp_contexts(void) @@ -328,44 +297,11 @@ int selinux_android_seapp_context_reload(void) char *p, *name = NULL, *value = NULL, *saveptr; size_t i, len, files_len = 0; int ret; - const char* seapp_contexts_files[MAX_FILE_CONTEXT_SIZE]; - for (i = 0; i < ARRAY_SIZE(seapp_contexts_plat); i++) { - if (access(seapp_contexts_plat[i], R_OK) != -1) { - seapp_contexts_files[files_len++] = seapp_contexts_plat[i]; - break; - } - } - for (i = 0; i < ARRAY_SIZE(seapp_contexts_apex); i++) { - if (access(seapp_contexts_apex[i], R_OK) != -1) { - seapp_contexts_files[files_len++] = seapp_contexts_apex[i]; - break; - } - } - for (i = 0; i < ARRAY_SIZE(seapp_contexts_system_ext); i++) { - if (access(seapp_contexts_system_ext[i], R_OK) != -1) { - seapp_contexts_files[files_len++] = seapp_contexts_system_ext[i]; - break; - } - } - for (i = 0; i < ARRAY_SIZE(seapp_contexts_product); i++) { - if (access(seapp_contexts_product[i], R_OK) != -1) { - seapp_contexts_files[files_len++] = seapp_contexts_product[i]; - break; - } - } - for (i = 0; i < ARRAY_SIZE(seapp_contexts_vendor); i++) { - if (access(seapp_contexts_vendor[i], R_OK) != -1) { - seapp_contexts_files[files_len++] = seapp_contexts_vendor[i]; - break; - } - } - for (i = 0; i < ARRAY_SIZE(seapp_contexts_odm); i++) { - if (access(seapp_contexts_odm[i], R_OK) != -1) { - seapp_contexts_files[files_len++] = seapp_contexts_odm[i]; - break; - } - } + const char* seapp_contexts_files[MAX_CONTEXT_PATHS]; + files_len = find_existing_files(seapp_context_paths, seapp_contexts_files); + + /* Reset the current entries */ free_seapp_contexts(); nspec = 0; @@ -654,16 +590,16 @@ oom: goto out; } - +/* indirection to support pthread_once */ static void seapp_context_init(void) { - selinux_android_seapp_context_reload(); + selinux_android_seapp_context_reload(); } -static pthread_once_t once = PTHREAD_ONCE_INIT; +static pthread_once_t seapp_once = PTHREAD_ONCE_INIT; void selinux_android_seapp_context_init(void) { - __selinux_once(once, seapp_context_init); + __selinux_once(seapp_once, seapp_context_init); } /* @@ -672,8 +608,11 @@ void selinux_android_seapp_context_init(void) { */ #define CAT_MAPPING_MAX_ID (0x1<<16) +/* The kind of request when looking up an seapp_context. */ enum seapp_kind { + /* Returns the SELinux type for the app data directory */ SEAPP_TYPE, + /* Returns the SELinux type for the app process */ SEAPP_DOMAIN }; @@ -720,6 +659,7 @@ static int seinfo_parse(char *dest, const char *src, size_t size) return 0; } +/* Sets the categories of ctx based on the level request */ static int set_range_from_level(context_t ctx, enum levelFrom levelFrom, uid_t userid, uid_t appid) { char level[255]; @@ -753,6 +693,9 @@ static int set_range_from_level(context_t ctx, enum levelFrom levelFrom, uid_t u return 0; } +/* Search an app (or its data) based on its name and information within the list + * of known seapp_contexts. If found, sets the type and categories of ctx and + * returns 0. Returns -1 in case of error; -2 for out of memory */ static int seapp_context_lookup(enum seapp_kind kind, uid_t uid, bool isSystemServer, @@ -1043,8 +986,11 @@ static void file_context_init(void) static pthread_once_t fc_once = PTHREAD_ONCE_INIT; #define PKGTAB_SIZE 256 +/* Hash table for pkg_info. It uses the package name as key. In case of + * collision, the next entry is the private_data attribute */ static struct pkg_info *pkgTab[PKGTAB_SIZE]; +/* Returns a hash based on the package name */ static unsigned int pkghash(const char *pkgname) { unsigned int h = 7; @@ -1054,17 +1000,20 @@ static unsigned int pkghash(const char *pkgname) return h & (PKGTAB_SIZE - 1); } +/* Adds the pkg_info entry to the hash table */ static bool pkg_parse_callback(pkg_info *info, void *userdata) { (void) userdata; unsigned int hash = pkghash(info->name); if (pkgTab[hash]) + /* Collision. Prepend the entry. */ info->private_data = pkgTab[hash]; pkgTab[hash] = info; return true; } +/* Initialize the pkg_info hash table */ static void package_info_init(void) { @@ -1103,6 +1052,7 @@ static void package_info_init(void) static pthread_once_t pkg_once = PTHREAD_ONCE_INIT; +/* Returns the pkg_info for a package with a specific name */ struct pkg_info *package_info_lookup(const char *name) { struct pkg_info *info;