blob: 2e70ceb69cfb19bbf86a715724a9c2f554540be1 [file] [log] [blame]
#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_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" },
// TODO: remove nonplat* when no need to retain backward compatibility.
{ SELABEL_OPT_PATH, "/vendor/etc/selinux/nonplat_service_contexts" },
{ SELABEL_OPT_PATH, "/nonplat_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" },
// TODO: remove nonplat* when no need to retain backward compatibility.
{ SELABEL_OPT_PATH, "/vendor/etc/selinux/nonplat_hwservice_contexts" },
{ SELABEL_OPT_PATH, "/nonplat_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 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" };
struct selabel_handle* selinux_android_service_open_context_handle(const struct selinux_opt* seopts_service,
unsigned nopts)
{
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;
}
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_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);
}
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);
}
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);
}
int selinux_log_callback(int type, const char *fmt, ...)
{
va_list ap;
int priority;
char *strp;
switch(type) {
case SELINUX_WARNING:
priority = ANDROID_LOG_WARN;
break;
case SELINUX_INFO:
priority = ANDROID_LOG_INFO;
break;
default:
priority = ANDROID_LOG_ERROR;
break;
}
va_start(ap, fmt);
if (vasprintf(&strp, fmt, ap) != -1) {
LOG_PRI(priority, "SELinux", "%s", strp);
LOG_EVENT_STRING(AUDITD_LOG_TAG, strp);
free(strp);
}
va_end(ap);
return 0;
}
int selinux_vendor_log_callback(int type, const char *fmt, ...)
{
va_list ap;
int priority;
char *strp;
switch(type) {
case SELINUX_WARNING:
priority = ANDROID_LOG_WARN;
break;
case SELINUX_INFO:
priority = ANDROID_LOG_INFO;
break;
default:
priority = ANDROID_LOG_ERROR;
break;
}
va_start(ap, fmt);
if (vasprintf(&strp, fmt, ap) != -1) {
LOG_PRI(priority, "SELinux", "%s", strp);
free(strp);
}
va_end(ap);
return 0;
}