* commit '11c783f1ead9f276e8854cb1adaebeed8517e8a1': Implement SELinux/MAC checks for property service.
This commit is contained in:
commit
2fec4de5c7
3 changed files with 123 additions and 11 deletions
43
init/init.c
43
init/init.c
|
@ -62,6 +62,7 @@
|
|||
|
||||
#ifdef HAVE_SELINUX
|
||||
struct selabel_handle *sehandle;
|
||||
struct selabel_handle *sehandle_prop;
|
||||
#endif
|
||||
|
||||
static int property_triggers_enabled = 0;
|
||||
|
@ -756,9 +757,34 @@ static int bootchart_init_action(int nargs, char **args)
|
|||
#endif
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
static const struct selinux_opt seopts_prop[] = {
|
||||
{ SELABEL_OPT_PATH, "/data/system/property_contexts" },
|
||||
{ SELABEL_OPT_PATH, "/property_contexts" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
struct selabel_handle* selinux_android_prop_context_handle(void)
|
||||
{
|
||||
int i = 0;
|
||||
struct selabel_handle* sehandle = NULL;
|
||||
while ((sehandle == NULL) && seopts_prop[i].value) {
|
||||
sehandle = selabel_open(SELABEL_CTX_ANDROID_PROP, &seopts_prop[i], 1);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (!sehandle) {
|
||||
ERROR("SELinux: Could not load property_contexts: %s\n",
|
||||
strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
INFO("SELinux: Loaded property contexts from %s\n", seopts_prop[i - 1].value);
|
||||
return sehandle;
|
||||
}
|
||||
|
||||
void selinux_init_all_handles(void)
|
||||
{
|
||||
sehandle = selinux_android_file_context_handle();
|
||||
sehandle_prop = selinux_android_prop_context_handle();
|
||||
}
|
||||
|
||||
int selinux_reload_policy(void)
|
||||
|
@ -776,9 +802,19 @@ int selinux_reload_policy(void)
|
|||
if (sehandle)
|
||||
selabel_close(sehandle);
|
||||
|
||||
if (sehandle_prop)
|
||||
selabel_close(sehandle_prop);
|
||||
|
||||
selinux_init_all_handles();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int audit_callback(void *data, security_class_t cls, char *buf, size_t len)
|
||||
{
|
||||
snprintf(buf, len, "property=%s", !data ? "NULL" : (char *)data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv)
|
||||
|
@ -835,6 +871,13 @@ int main(int argc, char **argv)
|
|||
process_kernel_cmdline();
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
union selinux_callback cb;
|
||||
cb.func_log = klog_write;
|
||||
selinux_set_callback(SELINUX_CB_LOG, cb);
|
||||
|
||||
cb.func_audit = audit_callback;
|
||||
selinux_set_callback(SELINUX_CB_AUDIT, cb);
|
||||
|
||||
INFO("loading selinux policy\n");
|
||||
if (selinux_enabled) {
|
||||
if (selinux_android_load_policy() < 0) {
|
||||
|
|
|
@ -138,6 +138,7 @@ int load_565rle_image( char *file_name );
|
|||
|
||||
#ifdef HAVE_SELINUX
|
||||
extern struct selabel_handle *sehandle;
|
||||
extern struct selabel_handle *sehandle_prop;
|
||||
extern int selinux_reload_policy(void);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -40,6 +40,11 @@
|
|||
#include <sys/atomics.h>
|
||||
#include <private/android_filesystem_config.h>
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
#include <selinux/selinux.h>
|
||||
#include <selinux/label.h>
|
||||
#endif
|
||||
|
||||
#include "property_service.h"
|
||||
#include "init.h"
|
||||
#include "util.h"
|
||||
|
@ -194,23 +199,77 @@ static void update_prop_info(prop_info *pi, const char *value, unsigned len)
|
|||
__futex_wake(&pi->serial, INT32_MAX);
|
||||
}
|
||||
|
||||
static int check_mac_perms(const char *name, char *sctx)
|
||||
{
|
||||
#ifdef HAVE_SELINUX
|
||||
if (is_selinux_enabled() <= 0)
|
||||
return 1;
|
||||
|
||||
char *tctx = NULL;
|
||||
const char *class = "property_service";
|
||||
const char *perm = "set";
|
||||
int result = 0;
|
||||
|
||||
if (!sctx)
|
||||
goto err;
|
||||
|
||||
if (!sehandle_prop)
|
||||
goto err;
|
||||
|
||||
if (selabel_lookup(sehandle_prop, &tctx, name, 1) != 0)
|
||||
goto err;
|
||||
|
||||
if (selinux_check_access(sctx, tctx, class, perm, name) == 0)
|
||||
result = 1;
|
||||
|
||||
freecon(tctx);
|
||||
err:
|
||||
return result;
|
||||
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int check_control_mac_perms(const char *name, char *sctx)
|
||||
{
|
||||
#ifdef HAVE_SELINUX
|
||||
|
||||
/*
|
||||
* Create a name prefix out of ctl.<service name>
|
||||
* The new prefix allows the use of the existing
|
||||
* property service backend labeling while avoiding
|
||||
* mislabels based on true property prefixes.
|
||||
*/
|
||||
char ctl_name[PROP_VALUE_MAX+4];
|
||||
int ret = snprintf(ctl_name, sizeof(ctl_name), "ctl.%s", name);
|
||||
|
||||
if (ret < 0 || (size_t) ret >= sizeof(ctl_name))
|
||||
return 0;
|
||||
|
||||
return check_mac_perms(ctl_name, sctx);
|
||||
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks permissions for starting/stoping system services.
|
||||
* AID_SYSTEM and AID_ROOT are always allowed.
|
||||
*
|
||||
* Returns 1 if uid allowed, 0 otherwise.
|
||||
*/
|
||||
static int check_control_perms(const char *name, unsigned int uid, unsigned int gid) {
|
||||
static int check_control_perms(const char *name, unsigned int uid, unsigned int gid, char *sctx) {
|
||||
|
||||
int i;
|
||||
if (uid == AID_SYSTEM || uid == AID_ROOT)
|
||||
return 1;
|
||||
return check_control_mac_perms(name, sctx);
|
||||
|
||||
/* Search the ACL */
|
||||
for (i = 0; control_perms[i].service; i++) {
|
||||
if (strcmp(control_perms[i].service, name) == 0) {
|
||||
if ((uid && control_perms[i].uid == uid) ||
|
||||
(gid && control_perms[i].gid == gid)) {
|
||||
return 1;
|
||||
return check_control_mac_perms(name, sctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -221,22 +280,22 @@ static int check_control_perms(const char *name, unsigned int uid, unsigned int
|
|||
* Checks permissions for setting system properties.
|
||||
* Returns 1 if uid allowed, 0 otherwise.
|
||||
*/
|
||||
static int check_perms(const char *name, unsigned int uid, unsigned int gid)
|
||||
static int check_perms(const char *name, unsigned int uid, unsigned int gid, char *sctx)
|
||||
{
|
||||
int i;
|
||||
if (uid == 0)
|
||||
return 1;
|
||||
|
||||
if(!strncmp(name, "ro.", 3))
|
||||
name +=3;
|
||||
|
||||
if (uid == 0)
|
||||
return check_mac_perms(name, sctx);
|
||||
|
||||
for (i = 0; property_perms[i].prefix; i++) {
|
||||
int tmp;
|
||||
if (strncmp(property_perms[i].prefix, name,
|
||||
strlen(property_perms[i].prefix)) == 0) {
|
||||
if ((uid && property_perms[i].uid == uid) ||
|
||||
(gid && property_perms[i].gid == gid)) {
|
||||
return 1;
|
||||
|
||||
return check_mac_perms(name, sctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -357,6 +416,7 @@ void handle_property_set_fd()
|
|||
struct sockaddr_un addr;
|
||||
socklen_t addr_size = sizeof(addr);
|
||||
socklen_t cr_size = sizeof(cr);
|
||||
char * source_ctx = NULL;
|
||||
|
||||
if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {
|
||||
return;
|
||||
|
@ -382,18 +442,22 @@ void handle_property_set_fd()
|
|||
msg.name[PROP_NAME_MAX-1] = 0;
|
||||
msg.value[PROP_VALUE_MAX-1] = 0;
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
getpeercon(s, &source_ctx);
|
||||
#endif
|
||||
|
||||
if(memcmp(msg.name,"ctl.",4) == 0) {
|
||||
// Keep the old close-socket-early behavior when handling
|
||||
// ctl.* properties.
|
||||
close(s);
|
||||
if (check_control_perms(msg.value, cr.uid, cr.gid)) {
|
||||
if (check_control_perms(msg.value, cr.uid, cr.gid, source_ctx)) {
|
||||
handle_control_message((char*) msg.name + 4, (char*) msg.value);
|
||||
} else {
|
||||
ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\n",
|
||||
msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid);
|
||||
}
|
||||
} else {
|
||||
if (check_perms(msg.name, cr.uid, cr.gid)) {
|
||||
if (check_perms(msg.name, cr.uid, cr.gid, source_ctx)) {
|
||||
property_set((char*) msg.name, (char*) msg.value);
|
||||
} else {
|
||||
ERROR("sys_prop: permission denied uid:%d name:%s\n",
|
||||
|
@ -405,6 +469,10 @@ void handle_property_set_fd()
|
|||
// the property is written to memory.
|
||||
close(s);
|
||||
}
|
||||
#ifdef HAVE_SELINUX
|
||||
freecon(source_ctx);
|
||||
#endif
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
Loading…
Reference in a new issue