diff options
Diffstat (limited to 'init')
-rw-r--r-- | init/Android.mk | 9 | ||||
-rw-r--r-- | init/builtins.c | 47 | ||||
-rw-r--r-- | init/devices.c | 157 | ||||
-rw-r--r-- | init/devices.h | 3 | ||||
-rw-r--r-- | init/init.c | 79 | ||||
-rw-r--r-- | init/init.h | 9 | ||||
-rw-r--r-- | init/init_parser.c | 10 | ||||
-rw-r--r-- | init/keywords.h | 4 | ||||
-rw-r--r-- | init/log.h | 2 | ||||
-rw-r--r-- | init/property_service.c | 201 | ||||
-rw-r--r-- | init/property_service.h | 1 | ||||
-rw-r--r-- | init/readme.txt | 10 | ||||
-rw-r--r-- | init/ueventd.c | 20 | ||||
-rw-r--r-- | init/util.c | 4 |
14 files changed, 341 insertions, 215 deletions
diff --git a/init/Android.mk b/init/Android.mk index 1f43ba6..489dc93 100644 --- a/init/Android.mk +++ b/init/Android.mk @@ -17,15 +17,20 @@ LOCAL_SRC_FILES:= \ ueventd_parser.c \ watchdogd.c +LOCAL_CFLAGS += -Wno-unused-parameter + ifeq ($(strip $(INIT_BOOTCHART)),true) LOCAL_SRC_FILES += bootchart.c LOCAL_CFLAGS += -DBOOTCHART=1 endif ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT))) -LOCAL_CFLAGS += -DALLOW_LOCAL_PROP_OVERRIDE=1 +LOCAL_CFLAGS += -DALLOW_LOCAL_PROP_OVERRIDE=1 -DALLOW_DISABLE_SELINUX=1 endif +# Enable ueventd logging +#LOCAL_CFLAGS += -DLOG_UEVENTS=1 + LOCAL_MODULE:= init LOCAL_FORCE_STATIC_EXECUTABLE := true @@ -42,6 +47,8 @@ LOCAL_STATIC_LIBRARIES := \ libmincrypt \ libext4_utils_static +LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk + include $(BUILD_EXECUTABLE) # Make a symlink from /sbin/ueventd and /sbin/watchdogd to /init diff --git a/init/builtins.c b/init/builtins.c index e2932d5..b32981e 100644 --- a/init/builtins.c +++ b/init/builtins.c @@ -33,7 +33,6 @@ #include <linux/loop.h> #include <cutils/partition_utils.h> #include <cutils/android_reboot.h> -#include <sys/system_properties.h> #include <fs_mgr.h> #include <selinux/selinux.h> @@ -196,6 +195,8 @@ static void service_start_if_not_disabled(struct service *svc) { if (!(svc->flags & SVC_DISABLED)) { service_start(svc, NULL); + } else { + svc->flags |= SVC_DISABLED_START; } } @@ -238,6 +239,21 @@ int do_domainname(int nargs, char **args) return write_file("/proc/sys/kernel/domainname", args[1]); } +int do_enable(int nargs, char **args) +{ + struct service *svc; + svc = service_find_by_name(args[1]); + if (svc) { + svc->flags &= ~(SVC_DISABLED | SVC_RC_DISABLED); + if (svc->flags & SVC_DISABLED_START) { + service_start(svc, NULL); + } + } else { + return -1; + } + return 0; +} + int do_exec(int nargs, char **args) { return -1; @@ -846,11 +862,24 @@ int do_setsebool(int nargs, char **args) { } int do_loglevel(int nargs, char **args) { - if (nargs == 2) { - klog_set_level(atoi(args[1])); - return 0; + int log_level; + char log_level_str[PROP_VALUE_MAX] = ""; + if (nargs != 2) { + ERROR("loglevel: missing argument\n"); + return -EINVAL; } - return -1; + + if (expand_props(log_level_str, args[1], sizeof(log_level_str))) { + ERROR("loglevel: cannot expand '%s'\n", args[1]); + return -EINVAL; + } + log_level = atoi(log_level_str); + if (log_level < KLOG_ERROR_LEVEL || log_level > KLOG_DEBUG_LEVEL) { + ERROR("loglevel: invalid log level'%d'\n", log_level); + return -EINVAL; + } + klog_set_level(log_level); + return 0; } int do_load_persist_props(int nargs, char **args) { @@ -861,6 +890,14 @@ int do_load_persist_props(int nargs, char **args) { return -1; } +int do_load_all_props(int nargs, char **args) { + if (nargs == 1) { + load_all_props(); + return 0; + } + return -1; +} + int do_wait(int nargs, char **args) { if (nargs == 2) { diff --git a/init/devices.c b/init/devices.c index f7df453..e27c311 100644 --- a/init/devices.c +++ b/init/devices.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 The Android Open Source Project + * Copyright (C) 2007-2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ */ #include <errno.h> +#include <fnmatch.h> #include <stddef.h> #include <stdio.h> #include <stdlib.h> @@ -37,7 +38,6 @@ #include <private/android_filesystem_config.h> #include <sys/time.h> -#include <asm/page.h> #include <sys/wait.h> #include <cutils/list.h> @@ -48,6 +48,8 @@ #include "util.h" #include "log.h" +#define UNUSED __attribute__((__unused__)) + #define SYSFS_PREFIX "/sys" #define FIRMWARE_DIR1 "/etc/firmware" #define FIRMWARE_DIR2 "/vendor/firmware" @@ -76,6 +78,7 @@ struct perms_ { unsigned int uid; unsigned int gid; unsigned short prefix; + unsigned short wildcard; }; struct perm_node { @@ -96,7 +99,8 @@ static list_declare(platform_names); int add_dev_perms(const char *name, const char *attr, mode_t perm, unsigned int uid, unsigned int gid, - unsigned short prefix) { + unsigned short prefix, + unsigned short wildcard) { struct perm_node *node = calloc(1, sizeof(*node)); if (!node) return -ENOMEM; @@ -115,6 +119,7 @@ int add_dev_perms(const char *name, const char *attr, node->dp.uid = uid; node->dp.gid = gid; node->dp.prefix = prefix; + node->dp.wildcard = wildcard; if (attr) list_add_tail(&sys_perms, &node->plist); @@ -129,40 +134,62 @@ void fixup_sys_perms(const char *upath) char buf[512]; struct listnode *node; struct perms_ *dp; - char *secontext; - /* upaths omit the "/sys" that paths in this list - * contain, so we add 4 when comparing... - */ + /* upaths omit the "/sys" that paths in this list + * contain, so we add 4 when comparing... + */ list_for_each(node, &sys_perms) { dp = &(node_to_item(node, struct perm_node, plist))->dp; if (dp->prefix) { if (strncmp(upath, dp->name + 4, strlen(dp->name + 4))) continue; + } else if (dp->wildcard) { + if (fnmatch(dp->name + 4, upath, FNM_PATHNAME) != 0) + continue; } else { if (strcmp(upath, dp->name + 4)) continue; } if ((strlen(upath) + strlen(dp->attr) + 6) > sizeof(buf)) - return; + break; sprintf(buf,"/sys%s/%s", upath, dp->attr); INFO("fixup %s %d %d 0%o\n", buf, dp->uid, dp->gid, dp->perm); chown(buf, dp->uid, dp->gid); chmod(buf, dp->perm); - if (sehandle) { - secontext = NULL; - selabel_lookup(sehandle, &secontext, buf, 0); - if (secontext) { - setfilecon(buf, secontext); - freecon(secontext); - } - } } + + // Now fixup SELinux file labels + int len = snprintf(buf, sizeof(buf), "/sys%s", upath); + if ((len < 0) || ((size_t) len >= sizeof(buf))) { + // Overflow + return; + } + if (access(buf, F_OK) == 0) { + INFO("restorecon_recursive: %s\n", buf); + restorecon_recursive(buf); + } +} + +static bool perm_path_matches(const char *path, struct perms_ *dp) +{ + if (dp->prefix) { + if (strncmp(path, dp->name, strlen(dp->name)) == 0) + return true; + } else if (dp->wildcard) { + if (fnmatch(dp->name, path, FNM_PATHNAME) == 0) + return true; + } else { + if (strcmp(path, dp->name) == 0) + return true; + } + + return false; } -static mode_t get_device_perm(const char *path, unsigned *uid, unsigned *gid) +static mode_t get_device_perm(const char *path, const char **links, + unsigned *uid, unsigned *gid) { mode_t perm; struct listnode *node; @@ -173,19 +200,30 @@ static mode_t get_device_perm(const char *path, unsigned *uid, unsigned *gid) * override ueventd.rc */ list_for_each_reverse(node, &dev_perms) { + bool match = false; + perm_node = node_to_item(node, struct perm_node, plist); dp = &perm_node->dp; - if (dp->prefix) { - if (strncmp(path, dp->name, strlen(dp->name))) - continue; + if (perm_path_matches(path, dp)) { + match = true; } else { - if (strcmp(path, dp->name)) - continue; + if (links) { + int i; + for (i = 0; links[i]; i++) { + if (perm_path_matches(links[i], dp)) { + match = true; + break; + } + } + } + } + + if (match) { + *uid = dp->uid; + *gid = dp->gid; + return dp->perm; } - *uid = dp->uid; - *gid = dp->gid; - return dp->perm; } /* Default if nothing found. */ *uid = 0; @@ -194,8 +232,9 @@ static mode_t get_device_perm(const char *path, unsigned *uid, unsigned *gid) } static void make_device(const char *path, - const char *upath, - int block, int major, int minor) + const char *upath UNUSED, + int block, int major, int minor, + const char **links) { unsigned uid; unsigned gid; @@ -203,10 +242,10 @@ static void make_device(const char *path, dev_t dev; char *secontext = NULL; - mode = get_device_perm(path, &uid, &gid) | (block ? S_IFBLK : S_IFCHR); + mode = get_device_perm(path, links, &uid, &gid) | (block ? S_IFBLK : S_IFCHR); if (sehandle) { - selabel_lookup(sehandle, &secontext, path, mode); + selabel_lookup_best_match(sehandle, &secontext, path, links, mode); setfscreatecon(secontext); } @@ -297,6 +336,37 @@ static void remove_platform_device(const char *path) } } +/* Given a path that may start with a PCI device, populate the supplied buffer + * with the PCI domain/bus number and the peripheral ID and return 0. + * If it doesn't start with a PCI device, or there is some error, return -1 */ +static int find_pci_device_prefix(const char *path, char *buf, ssize_t buf_sz) +{ + const char *start, *end; + + if (strncmp(path, "/devices/pci", 12)) + return -1; + + /* Beginning of the prefix is the initial "pci" after "/devices/" */ + start = path + 9; + + /* End of the prefix is two path '/' later, capturing the domain/bus number + * and the peripheral ID. Example: pci0000:00/0000:00:1f.2 */ + end = strchr(start, '/'); + if (!end) + return -1; + end = strchr(end + 1, '/'); + if (!end) + return -1; + + /* Make sure we have enough room for the string plus null terminator */ + if (end - start + 1 > buf_sz) + return -1; + + strncpy(buf, start, end - start); + buf[end - start] = '\0'; + return 0; +} + #if LOG_UEVENTS static inline suseconds_t get_usecs(void) @@ -421,11 +491,12 @@ err: return NULL; } -static char **parse_platform_block_device(struct uevent *uevent) +static char **get_block_device_symlinks(struct uevent *uevent) { const char *device; struct platform_node *pdev; char *slash; + const char *type; int width; char buf[256]; char link_path[256]; @@ -437,18 +508,24 @@ static char **parse_platform_block_device(struct uevent *uevent) struct stat info; pdev = find_platform_device(uevent->path); - if (!pdev) + if (pdev) { + device = pdev->name; + type = "platform"; + } else if (!find_pci_device_prefix(uevent->path, buf, sizeof(buf))) { + device = buf; + type = "pci"; + } else { return NULL; - device = pdev->name; + } char **links = malloc(sizeof(char *) * 4); if (!links) return NULL; memset(links, 0, sizeof(char *) * 4); - INFO("found platform device %s\n", device); + INFO("found %s device %s\n", type, device); - snprintf(link_path, sizeof(link_path), "/dev/block/platform/%s", device); + snprintf(link_path, sizeof(link_path), "/dev/block/%s/%s", type, device); if (uevent->partition_name) { p = strdup(uevent->partition_name); @@ -484,7 +561,7 @@ static void handle_device(const char *action, const char *devpath, int i; if(!strcmp(action, "add")) { - make_device(devpath, path, block, major, minor); + make_device(devpath, path, block, major, minor, (const char **)links); if (links) { for (i = 0; links[i]; i++) make_link(devpath, links[i]); @@ -555,7 +632,7 @@ static void handle_block_device_event(struct uevent *uevent) make_dir(base, 0755); if (!strncmp(uevent->path, "/devices/", 9)) - links = parse_platform_block_device(uevent); + links = get_block_device_symlinks(uevent); handle_device(uevent->action, devpath, uevent->path, 1, uevent->major, uevent->minor, links); @@ -590,6 +667,11 @@ static void mkdir_recursive_for_devpath(const char *devpath) mkdir_recursive(dir, 0755); } +static inline void __attribute__((__deprecated__)) kernel_logger() +{ + INFO("kernel logger is deprecated\n"); +} + static void handle_generic_device_event(struct uevent *uevent) { char *base; @@ -676,6 +758,7 @@ static void handle_generic_device_event(struct uevent *uevent) make_dir(base, 0755); } else if(!strncmp(uevent->subsystem, "misc", 4) && !strncmp(name, "log_", 4)) { + kernel_logger(); base = "/dev/log/"; make_dir(base, 0755); name += 4; @@ -692,7 +775,7 @@ static void handle_generic_device_event(struct uevent *uevent) static void handle_device_event(struct uevent *uevent) { - if (!strcmp(uevent->action,"add") || !strcmp(uevent->action, "change")) + if (!strcmp(uevent->action,"add") || !strcmp(uevent->action, "change") || !strcmp(uevent->action, "online")) fixup_sys_perms(uevent->path); if (!strncmp(uevent->subsystem, "block", 5)) { diff --git a/init/devices.h b/init/devices.h index a84fa58..5d0fe88 100644 --- a/init/devices.h +++ b/init/devices.h @@ -23,6 +23,7 @@ extern void handle_device_fd(); extern void device_init(void); extern int add_dev_perms(const char *name, const char *attr, mode_t perm, unsigned int uid, - unsigned int gid, unsigned short prefix); + unsigned int gid, unsigned short prefix, + unsigned short wildcard); int get_device_fd(); #endif /* _INIT_DEVICES_H */ diff --git a/init/init.c b/init/init.c index 00f4558..e4ac1cf 100644 --- a/init/init.c +++ b/init/init.c @@ -46,8 +46,6 @@ #include <private/android_filesystem_config.h> #include <termios.h> -#include <sys/system_properties.h> - #include "devices.h" #include "init.h" #include "log.h" @@ -164,7 +162,7 @@ void service_start(struct service *svc, const char *dynamic_args) * state and immediately takes it out of the restarting * state if it was in there */ - svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART)); + svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START)); svc->time_started = 0; /* running processes require no additional work -- if @@ -364,7 +362,7 @@ static void service_stop_or_reset(struct service *svc, int how) { /* The service is still SVC_RUNNING until its process exits, but if it has * already exited it shoudn't attempt a restart yet. */ - svc->flags &= (~SVC_RESTARTING); + svc->flags &= ~(SVC_RESTARTING | SVC_DISABLED_START); if ((how != SVC_DISABLED) && (how != SVC_RESET) && (how != SVC_RESTART)) { /* Hrm, an illegal flag. Default to SVC_DISABLED */ @@ -530,7 +528,8 @@ static int is_last_command(struct action *act, struct command *cmd) void execute_one_command(void) { - int ret; + int ret, i; + char cmd_str[256] = ""; if (!cur_action || !cur_command || is_last_command(cur_action, cur_command)) { cur_action = action_remove_queue_head(); @@ -547,7 +546,17 @@ void execute_one_command(void) return; ret = cur_command->func(cur_command->nargs, cur_command->args); - INFO("command '%s' r=%d\n", cur_command->args[0], ret); + if (klog_get_level() >= KLOG_INFO_LEVEL) { + for (i = 0; i < cur_command->nargs; i++) { + strlcat(cmd_str, cur_command->args[i], sizeof(cmd_str)); + if (i < cur_command->nargs - 1) { + strlcat(cmd_str, " ", sizeof(cmd_str)); + } + } + INFO("command '%s' action=%s status=%d (%s:%d)\n", + cmd_str, cur_action ? cur_action->name : "", ret, cur_command->filename, + cur_command->line); + } } static int wait_for_coldboot_done_action(int nargs, char **args) @@ -843,24 +852,21 @@ static int bootchart_init_action(int nargs, char **args) static const struct selinux_opt seopts_prop[] = { { SELABEL_OPT_PATH, "/property_contexts" }, + { SELABEL_OPT_PATH, "/data/security/current/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++; - } - + int policy_index = selinux_android_use_data_policy() ? 1 : 0; + struct selabel_handle* sehandle = selabel_open(SELABEL_CTX_ANDROID_PROP, + &seopts_prop[policy_index], 1); 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); + INFO("SELinux: Loaded property contexts from %s\n", seopts_prop[policy_index].value); return sehandle; } @@ -873,6 +879,7 @@ void selinux_init_all_handles(void) static bool selinux_is_disabled(void) { +#ifdef ALLOW_DISABLE_SELINUX char tmp[PROP_VALUE_MAX]; if (access("/sys/fs/selinux", F_OK) != 0) { @@ -886,12 +893,14 @@ static bool selinux_is_disabled(void) /* SELinux is compiled into the kernel, but we've been told to disable it. */ return true; } +#endif return false; } static bool selinux_is_enforcing(void) { +#ifdef ALLOW_DISABLE_SELINUX char tmp[PROP_VALUE_MAX]; if (property_get("ro.boot.selinux", tmp) == 0) { @@ -908,6 +917,7 @@ static bool selinux_is_enforcing(void) ERROR("SELinux: Unknown value of ro.boot.selinux. Got: \"%s\". Assuming enforcing.\n", tmp); } +#endif return true; } @@ -933,12 +943,33 @@ int selinux_reload_policy(void) return 0; } -int audit_callback(void *data, security_class_t cls, char *buf, size_t len) +static int audit_callback(void *data, security_class_t cls __attribute__((unused)), char *buf, size_t len) { snprintf(buf, len, "property=%s", !data ? "NULL" : (char *)data); return 0; } +int log_callback(int type, const char *fmt, ...) +{ + int level; + va_list ap; + switch (type) { + case SELINUX_WARNING: + level = KLOG_WARNING_LEVEL; + break; + case SELINUX_INFO: + level = KLOG_INFO_LEVEL; + break; + default: + level = KLOG_ERROR_LEVEL; + break; + } + va_start(ap, fmt); + klog_vwrite(level, fmt, ap); + va_end(ap); + return 0; +} + static void selinux_initialize(void) { if (selinux_is_disabled()) { @@ -1012,7 +1043,7 @@ int main(int argc, char **argv) process_kernel_cmdline(); union selinux_callback cb; - cb.func_log = klog_write; + cb.func_log = log_callback; selinux_set_callback(SELINUX_CB_LOG, cb); cb.func_audit = audit_callback; @@ -1031,8 +1062,7 @@ int main(int argc, char **argv) is_charger = !strcmp(bootmode, "charger"); INFO("property init\n"); - if (!is_charger) - property_load_boot_defaults(); + property_load_boot_defaults(); INFO("reading config file\n"); init_parse_config_file("/init.rc"); @@ -1047,28 +1077,19 @@ int main(int argc, char **argv) /* execute all the boot actions to get us started */ action_for_each_trigger("init", action_add_queue_tail); - /* skip mounting filesystems in charger mode */ - if (!is_charger) { - action_for_each_trigger("early-fs", action_add_queue_tail); - action_for_each_trigger("fs", action_add_queue_tail); - action_for_each_trigger("post-fs", action_add_queue_tail); - action_for_each_trigger("post-fs-data", action_add_queue_tail); - } - /* Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random * wasn't ready immediately after wait_for_coldboot_done */ queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng"); - queue_builtin_action(property_service_init_action, "property_service_init"); queue_builtin_action(signal_init_action, "signal_init"); queue_builtin_action(check_startup_action, "check_startup"); + /* Don't mount filesystems or start core system services if in charger mode. */ if (is_charger) { action_for_each_trigger("charger", action_add_queue_tail); } else { - action_for_each_trigger("early-boot", action_add_queue_tail); - action_for_each_trigger("boot", action_add_queue_tail); + action_for_each_trigger("late-init", action_add_queue_tail); } /* run all property triggers based on current state of the properties */ diff --git a/init/init.h b/init/init.h index 736b75b..a7615a3 100644 --- a/init/init.h +++ b/init/init.h @@ -29,10 +29,14 @@ struct command struct listnode clist; int (*func)(int nargs, char **args); + + int line; + const char *filename; + int nargs; char *args[1]; }; - + struct action { /* node in list of all actions */ struct listnode alist; @@ -43,7 +47,7 @@ struct action { unsigned hash; const char *name; - + struct listnode commands; struct command *current; }; @@ -74,6 +78,7 @@ struct svcenvinfo { so it can be restarted with its class */ #define SVC_RC_DISABLED 0x80 /* Remember if the disabled flag was set in the rc script */ #define SVC_RESTART 0x100 /* Use to safely restart (stop, wait, start) a service */ +#define SVC_DISABLED_START 0x200 /* a start was requested but it was disabled at the time */ #define NR_SVC_SUPP_GIDS 12 /* twelve supplementary groups */ diff --git a/init/init_parser.c b/init/init_parser.c index f49e698..6466db2 100644 --- a/init/init_parser.c +++ b/init/init_parser.c @@ -33,9 +33,6 @@ #include <cutils/iosched_policy.h> #include <cutils/list.h> -#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ -#include <sys/_system_properties.h> - static list_declare(service_list); static list_declare(action_list); static list_declare(action_queue); @@ -98,6 +95,7 @@ static int lookup_keyword(const char *s) if (!strcmp(s, "omainname")) return K_domainname; break; case 'e': + if (!strcmp(s, "nable")) return K_enable; if (!strcmp(s, "xec")) return K_exec; if (!strcmp(s, "xport")) return K_export; break; @@ -119,6 +117,7 @@ static int lookup_keyword(const char *s) case 'l': if (!strcmp(s, "oglevel")) return K_loglevel; if (!strcmp(s, "oad_persist_props")) return K_load_persist_props; + if (!strcmp(s, "oad_all_props")) return K_load_all_props; break; case 'm': if (!strcmp(s, "kdir")) return K_mkdir; @@ -582,6 +581,7 @@ void queue_builtin_action(int (*func)(int nargs, char **args), char *name) cmd = calloc(1, sizeof(*cmd)); cmd->func = func; cmd->args[0] = name; + cmd->nargs = 1; list_add_tail(&act->commands, &cmd->clist); list_add_tail(&action_list, &act->alist); @@ -759,7 +759,7 @@ static void parse_line_service(struct parse_state *state, int nargs, char **args break; case K_setenv: { /* name value */ struct svcenvinfo *ei; - if (nargs < 2) { + if (nargs < 3) { parse_error(state, "setenv option requires name and value arguments\n"); break; } @@ -868,6 +868,8 @@ static void parse_line_action(struct parse_state* state, int nargs, char **args) } cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs); cmd->func = kw_func(kw); + cmd->line = state->line; + cmd->filename = state->filename; cmd->nargs = nargs; memcpy(cmd->args, args, sizeof(char*) * nargs); list_add_tail(&act->commands, &cmd->clist); diff --git a/init/keywords.h b/init/keywords.h index 97fe50c..2d97e5b 100644 --- a/init/keywords.h +++ b/init/keywords.h @@ -6,6 +6,7 @@ int do_class_start(int nargs, char **args); int do_class_stop(int nargs, char **args); int do_class_reset(int nargs, char **args); int do_domainname(int nargs, char **args); +int do_enable(int nargs, char **args); int do_exec(int nargs, char **args); int do_export(int nargs, char **args); int do_hostname(int nargs, char **args); @@ -38,6 +39,7 @@ int do_chown(int nargs, char **args); int do_chmod(int nargs, char **args); int do_loglevel(int nargs, char **args); int do_load_persist_props(int nargs, char **args); +int do_load_all_props(int nargs, char **args); int do_wait(int nargs, char **args); #define __MAKE_KEYWORD_ENUM__ #define KEYWORD(symbol, flags, nargs, func) K_##symbol, @@ -55,6 +57,7 @@ enum { KEYWORD(critical, OPTION, 0, 0) KEYWORD(disabled, OPTION, 0, 0) KEYWORD(domainname, COMMAND, 1, do_domainname) + KEYWORD(enable, COMMAND, 1, do_enable) KEYWORD(exec, COMMAND, 1, do_exec) KEYWORD(export, COMMAND, 2, do_export) KEYWORD(group, OPTION, 0, 0) @@ -99,6 +102,7 @@ enum { KEYWORD(chmod, COMMAND, 2, do_chmod) KEYWORD(loglevel, COMMAND, 1, do_loglevel) KEYWORD(load_persist_props, COMMAND, 0, do_load_persist_props) + KEYWORD(load_all_props, COMMAND, 0, do_load_all_props) KEYWORD(ioprio, OPTION, 0, 0) #ifdef __MAKE_KEYWORD_ENUM__ KEYWORD_COUNT, @@ -23,6 +23,6 @@ #define NOTICE(x...) KLOG_NOTICE("init", x) #define INFO(x...) KLOG_INFO("init", x) -#define LOG_UEVENTS 0 /* log uevent messages if 1. verbose */ +extern int log_callback(int type, const char *fmt, ...); #endif diff --git a/init/property_service.c b/init/property_service.c index ac63377..d112699 100644 --- a/init/property_service.c +++ b/init/property_service.c @@ -38,7 +38,6 @@ #include <sys/types.h> #include <netinet/in.h> #include <sys/mman.h> -#include <sys/atomics.h> #include <private/android_filesystem_config.h> #include <selinux/selinux.h> @@ -56,63 +55,6 @@ static int property_area_inited = 0; static int property_set_fd = -1; -/* White list of permissions for setting property services. */ -struct { - const char *prefix; - unsigned int uid; - unsigned int gid; -} property_perms[] = { - { "net.rmnet0.", AID_RADIO, 0 }, - { "net.gprs.", AID_RADIO, 0 }, - { "net.ppp", AID_RADIO, 0 }, - { "net.qmi", AID_RADIO, 0 }, - { "net.lte", AID_RADIO, 0 }, - { "net.cdma", AID_RADIO, 0 }, - { "ril.", AID_RADIO, 0 }, - { "gsm.", AID_RADIO, 0 }, - { "persist.radio", AID_RADIO, 0 }, - { "net.dns", AID_RADIO, 0 }, - { "sys.usb.config", AID_RADIO, 0 }, - { "net.", AID_SYSTEM, 0 }, - { "dev.", AID_SYSTEM, 0 }, - { "runtime.", AID_SYSTEM, 0 }, - { "hw.", AID_SYSTEM, 0 }, - { "sys.", AID_SYSTEM, 0 }, - { "sys.powerctl", AID_SHELL, 0 }, - { "service.", AID_SYSTEM, 0 }, - { "wlan.", AID_SYSTEM, 0 }, - { "gps.", AID_GPS, 0 }, - { "bluetooth.", AID_BLUETOOTH, 0 }, - { "dhcp.", AID_SYSTEM, 0 }, - { "dhcp.", AID_DHCP, 0 }, - { "debug.", AID_SYSTEM, 0 }, - { "debug.", AID_SHELL, 0 }, - { "log.", AID_SHELL, 0 }, - { "service.adb.root", AID_SHELL, 0 }, - { "service.adb.tcp.port", AID_SHELL, 0 }, - { "persist.sys.", AID_SYSTEM, 0 }, - { "persist.service.", AID_SYSTEM, 0 }, - { "persist.security.", AID_SYSTEM, 0 }, - { "persist.gps.", AID_GPS, 0 }, - { "persist.service.bdroid.", AID_BLUETOOTH, 0 }, - { "selinux." , AID_SYSTEM, 0 }, - { NULL, 0, 0 } -}; - -/* - * White list of UID that are allowed to start/stop services. - * Currently there are no user apps that require. - */ -struct { - const char *service; - unsigned int uid; - unsigned int gid; -} control_perms[] = { - { "dumpstate",AID_SHELL, AID_LOG }, - { "ril-daemon",AID_RADIO, AID_RADIO }, - {NULL, 0, 0 } -}; - typedef struct { size_t size; int fd; @@ -194,34 +136,10 @@ static int check_control_mac_perms(const char *name, char *sctx) } /* - * 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, char *sctx) { - - int i; - if (uid == AID_SYSTEM || uid == AID_ROOT) - 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 check_control_mac_perms(name, sctx); - } - } - } - return 0; -} - -/* * 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, char *sctx) +static int check_perms(const char *name, char *sctx) { int i; unsigned int app_id; @@ -229,26 +147,7 @@ static int check_perms(const char *name, unsigned int uid, unsigned int gid, cha if(!strncmp(name, "ro.", 3)) name +=3; - if (uid == 0) - return check_mac_perms(name, sctx); - - app_id = multiuser_get_app_id(uid); - if (app_id == AID_BLUETOOTH) { - uid = app_id; - } - - for (i = 0; property_perms[i].prefix; i++) { - 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 check_mac_perms(name, sctx); - } - } - } - - return 0; + return check_mac_perms(name, sctx); } int __property_get(const char *name, char *value) @@ -269,6 +168,7 @@ static void write_persistent_property(const char *name, const char *value) return; } write(fd, value, strlen(value)); + fsync(fd); close(fd); snprintf(path, sizeof(path), "%s/%s", PERSISTENT_PROPERTY_DIR, name); @@ -405,14 +305,14 @@ void handle_property_set_fd() // Keep the old close-socket-early behavior when handling // ctl.* properties. close(s); - if (check_control_perms(msg.value, cr.uid, cr.gid, source_ctx)) { + if (check_control_mac_perms(msg.value, 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, source_ctx)) { + if (check_perms(msg.name, source_ctx)) { property_set((char*) msg.name, (char*) msg.value); } else { ERROR("sys_prop: permission denied uid:%d name:%s\n", @@ -439,40 +339,73 @@ void get_property_workspace(int *fd, int *sz) *sz = pa_workspace.size; } -static void load_properties(char *data, char *prefix) +static void load_properties_from_file(const char *, const char *); + +/* + * Filter is used to decide which properties to load: NULL loads all keys, + * "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match. + */ +static void load_properties(char *data, const char *filter) { - char *key, *value, *eol, *sol, *tmp; - size_t plen; + char *key, *value, *eol, *sol, *tmp, *fn; + size_t flen = 0; + + if (filter) { + flen = strlen(filter); + } - if (prefix) - plen = strlen(prefix); sol = data; - while((eol = strchr(sol, '\n'))) { + while ((eol = strchr(sol, '\n'))) { key = sol; *eol++ = 0; sol = eol; - value = strchr(key, '='); - if(value == 0) continue; - *value++ = 0; + while (isspace(*key)) key++; + if (*key == '#') continue; - while(isspace(*key)) key++; - if(*key == '#') continue; - tmp = value - 2; - while((tmp > key) && isspace(*tmp)) *tmp-- = 0; + tmp = eol - 2; + while ((tmp > key) && isspace(*tmp)) *tmp-- = 0; - if (prefix && strncmp(key, prefix, plen)) - continue; + if (!strncmp(key, "import ", 7) && flen == 0) { + fn = key + 7; + while (isspace(*fn)) fn++; - while(isspace(*value)) value++; - tmp = eol - 2; - while((tmp > value) && isspace(*tmp)) *tmp-- = 0; + key = strchr(fn, ' '); + if (key) { + *key++ = 0; + while (isspace(*key)) key++; + } + + load_properties_from_file(fn, key); + + } else { + value = strchr(key, '='); + if (!value) continue; + *value++ = 0; + + tmp = value - 2; + while ((tmp > key) && isspace(*tmp)) *tmp-- = 0; + + while (isspace(*value)) value++; + + if (flen > 0) { + if (filter[flen - 1] == '*') { + if (strncmp(key, filter, flen - 1)) continue; + } else { + if (strcmp(key, filter)) continue; + } + } - property_set(key, value); + property_set(key, value); + } } } -static void load_properties_from_file(const char *fn, char *prefix) +/* + * Filter is used to decide which properties to load: NULL loads all keys, + * "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match. + */ +static void load_properties_from_file(const char *fn, const char *filter) { char *data; unsigned sz; @@ -480,7 +413,7 @@ static void load_properties_from_file(const char *fn, char *prefix) data = read_file(fn, &sz); if(data != 0) { - load_properties(data, prefix); + load_properties(data, filter); free(data); } } @@ -523,7 +456,8 @@ static void load_persistent_properties() || (sb.st_gid != 0) || (sb.st_nlink != 1)) { ERROR("skipping insecure property file %s (uid=%u gid=%u nlink=%d mode=%o)\n", - entry->d_name, sb.st_uid, sb.st_gid, sb.st_nlink, sb.st_mode); + entry->d_name, (unsigned int)sb.st_uid, (unsigned int)sb.st_gid, + sb.st_nlink, sb.st_mode); close(fd); continue; } @@ -586,16 +520,21 @@ void load_persist_props(void) load_persistent_properties(); } -void start_property_service(void) +void load_all_props(void) { - int fd; - load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL); load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT, NULL); - load_properties_from_file(PROP_PATH_FACTORY, "ro."); + load_properties_from_file(PROP_PATH_FACTORY, "ro.*"); + load_override_properties(); + /* Read persistent properties after all default values have been loaded. */ load_persistent_properties(); +} + +void start_property_service(void) +{ + int fd; fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0, NULL); if(fd < 0) return; diff --git a/init/property_service.h b/init/property_service.h index 46cbd8f..730495e 100644 --- a/init/property_service.h +++ b/init/property_service.h @@ -24,6 +24,7 @@ extern void handle_property_set_fd(void); extern void property_init(void); extern void property_load_boot_defaults(void); extern void load_persist_props(void); +extern void load_all_props(void); extern void start_property_service(void); void get_property_workspace(int *fd, int *sz); extern int __property_get(const char *name, char *value); diff --git a/init/readme.txt b/init/readme.txt index 42a09cb..613a9e9 100644 --- a/init/readme.txt +++ b/init/readme.txt @@ -178,6 +178,16 @@ class_stop <serviceclass> domainname <name> Set the domain name. +enable <servicename> + Turns a disabled service into an enabled one as if the service did not + specify disabled. + If the service is supposed to be running, it will be started now. + Typically used when the bootloader sets a variable that indicates a specific + service should be started when needed. E.g. + on property:ro.boot.myfancyhardware=1 + enable my_fancy_service_for_my_fancy_hardware + + insmod <path> Install the module at <path> diff --git a/init/ueventd.c b/init/ueventd.c index 3d01836..833e4fd 100644 --- a/init/ueventd.c +++ b/init/ueventd.c @@ -21,6 +21,7 @@ #include <stdio.h> #include <ctype.h> #include <signal.h> +#include <selinux/selinux.h> #include <private/android_filesystem_config.h> @@ -69,6 +70,16 @@ int ueventd_main(int argc, char **argv) open_devnull_stdio(); klog_init(); +#if LOG_UEVENTS + /* Ensure we're at a logging level that will show the events */ + if (klog_get_level() < KLOG_INFO_LEVEL) { + klog_set_level(KLOG_INFO_LEVEL); + } +#endif + + union selinux_callback cb; + cb.func_log = log_callback; + selinux_set_callback(SELINUX_CB_LOG, cb); INFO("starting ueventd\n"); @@ -116,6 +127,7 @@ void set_device_permission(int nargs, char **args) uid_t uid; gid_t gid; int prefix = 0; + int wildcard = 0; char *endptr; int ret; char *tmp = 0; @@ -148,9 +160,13 @@ void set_device_permission(int nargs, char **args) name = tmp; } else { int len = strlen(name); - if (name[len - 1] == '*') { + char *wildcard_chr = strchr(name, '*'); + if ((name[len - 1] == '*') && + (wildcard_chr == (name + len - 1))) { prefix = 1; name[len - 1] = '\0'; + } else if (wildcard_chr) { + wildcard = 1; } } @@ -177,6 +193,6 @@ void set_device_permission(int nargs, char **args) } gid = ret; - add_dev_perms(name, attr, perm, uid, gid, prefix); + add_dev_perms(name, attr, perm, uid, gid, prefix, wildcard); free(tmp); } diff --git a/init/util.c b/init/util.c index e772342..0f69e1c 100644 --- a/init/util.c +++ b/init/util.c @@ -527,10 +527,10 @@ int make_dir(const char *path, mode_t mode) int restorecon(const char* pathname) { - return selinux_android_restorecon(pathname); + return selinux_android_restorecon(pathname, 0); } int restorecon_recursive(const char* pathname) { - return selinux_android_restorecon_recursive(pathname); + return selinux_android_restorecon(pathname, SELINUX_ANDROID_RESTORECON_RECURSE); } |