Merge changes I71954b62,I02aafefa
* changes: Refactor context files definitions Add documentation to Android functions
This commit is contained in:
commit
5a0344eaec
5 changed files with 297 additions and 360 deletions
|
@ -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
|
||||
|
|
|
@ -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, ...)
|
||||
|
|
|
@ -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
|
||||
|
|
24
libselinux/src/android/android_internal.h
Normal file
24
libselinux/src/android/android_internal.h
Normal 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);
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue