Merge changes I71954b62,I02aafefa

* changes:
  Refactor context files definitions
  Add documentation to Android functions
This commit is contained in:
Thiébaud Weksteen 2022-04-26 01:00:05 +00:00 committed by Gerrit Code Review
commit 5a0344eaec
5 changed files with 297 additions and 360 deletions

View file

@ -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

View file

@ -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, ...)

View file

@ -1,5 +1,3 @@
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
@ -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

View file

@ -0,0 +1,24 @@
#include <sys/types.h>
#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);

View file

@ -1,136 +1,98 @@
#include "android_common.h"
#include "android_internal.h"
#include <packagelistparser/packagelistparser.h>
// 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;