summaryrefslogtreecommitdiffstats
path: root/init
diff options
context:
space:
mode:
Diffstat (limited to 'init')
-rw-r--r--init/Android.mk22
-rw-r--r--init/builtins.c62
-rw-r--r--init/devices.c136
-rwxr-xr-xinit/init.c79
-rw-r--r--init/init.h4
-rw-r--r--init/init_parser.c2
-rw-r--r--init/keywords.h2
-rwxr-xr-x[-rw-r--r--]init/property_service.c105
-rw-r--r--init/readme.txt26
-rw-r--r--init/ueventd.c2
-rwxr-xr-xinit/util.c15
-rw-r--r--init/watchdogd.c77
-rw-r--r--init/watchdogd.h22
13 files changed, 334 insertions, 220 deletions
diff --git a/init/Android.mk b/init/Android.mk
index 7dae9df..00d2144 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -15,7 +15,8 @@ LOCAL_SRC_FILES:= \
signal_handler.c \
init_parser.c \
ueventd.c \
- ueventd_parser.c
+ ueventd_parser.c \
+ watchdogd.c
ifeq ($(strip $(INIT_BOOTCHART)),true)
LOCAL_SRC_FILES += bootchart.c
@@ -32,18 +33,19 @@ LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
-LOCAL_STATIC_LIBRARIES := libfs_mgr libcutils libc
-
-ifeq ($(HAVE_SELINUX),true)
-LOCAL_STATIC_LIBRARIES += libselinux
-LOCAL_C_INCLUDES += external/libselinux/include
-LOCAL_CFLAGS += -DHAVE_SELINUX
-endif
+LOCAL_STATIC_LIBRARIES := \
+ libfs_mgr \
+ libcutils \
+ libc \
+ libselinux
include $(BUILD_EXECUTABLE)
-# Make a symlink from /sbin/ueventd to /init
-SYMLINKS := $(TARGET_ROOT_OUT)/sbin/ueventd
+# Make a symlink from /sbin/ueventd and /sbin/watchdogd to /init
+SYMLINKS := \
+ $(TARGET_ROOT_OUT)/sbin/ueventd \
+ $(TARGET_ROOT_OUT)/sbin/watchdogd
+
$(SYMLINKS): INIT_BINARY := $(LOCAL_MODULE)
$(SYMLINKS): $(LOCAL_INSTALLED_MODULE) $(LOCAL_PATH)/Android.mk
@echo "Symlink: $@ -> ../$(INIT_BINARY)"
diff --git a/init/builtins.c b/init/builtins.c
index 882ceb5..dc7900e 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -35,10 +35,8 @@
#include <sys/system_properties.h>
#include <fs_mgr.h>
-#ifdef HAVE_SELINUX
#include <selinux/selinux.h>
#include <selinux/label.h>
-#endif
#include "init.h"
#include "keywords.h"
@@ -322,6 +320,14 @@ int do_mkdir(int nargs, char **args)
if (_chown(args[1], uid, gid) < 0) {
return -errno;
}
+
+ /* chown may have cleared S_ISUID and S_ISGID, chmod again */
+ if (mode & (S_ISUID | S_ISGID)) {
+ ret = _chmod(args[1], mode);
+ if (ret == -1) {
+ return -errno;
+ }
+ }
}
return 0;
@@ -339,6 +345,12 @@ static struct {
{ "ro", MS_RDONLY },
{ "rw", 0 },
{ "remount", MS_REMOUNT },
+ { "bind", MS_BIND },
+ { "rec", MS_REC },
+ { "unbindable", MS_UNBINDABLE },
+ { "private", MS_PRIVATE },
+ { "slave", MS_SLAVE },
+ { "shared", MS_SHARED },
{ "defaults", 0 },
{ 0, 0 },
};
@@ -501,24 +513,20 @@ int do_mount_all(int nargs, char **args)
}
int do_setcon(int nargs, char **args) {
-#ifdef HAVE_SELINUX
if (is_selinux_enabled() <= 0)
return 0;
if (setcon(args[1]) < 0) {
return -errno;
}
-#endif
return 0;
}
int do_setenforce(int nargs, char **args) {
-#ifdef HAVE_SELINUX
if (is_selinux_enabled() <= 0)
return 0;
if (security_setenforce(atoi(args[1])) < 0) {
return -errno;
}
-#endif
return 0;
}
@@ -746,36 +754,30 @@ int do_restorecon(int nargs, char **args) {
}
int do_setsebool(int nargs, char **args) {
-#ifdef HAVE_SELINUX
- SELboolean *b = alloca(nargs * sizeof(SELboolean));
- char *v;
- int i;
+ const char *name = args[1];
+ const char *value = args[2];
+ SELboolean b;
+ int ret;
if (is_selinux_enabled() <= 0)
return 0;
- for (i = 1; i < nargs; i++) {
- char *name = args[i];
- v = strchr(name, '=');
- if (!v) {
- ERROR("setsebool: argument %s had no =\n", name);
- return -EINVAL;
- }
- *v++ = 0;
- b[i-1].name = name;
- if (!strcmp(v, "1") || !strcasecmp(v, "true") || !strcasecmp(v, "on"))
- b[i-1].value = 1;
- else if (!strcmp(v, "0") || !strcasecmp(v, "false") || !strcasecmp(v, "off"))
- b[i-1].value = 0;
- else {
- ERROR("setsebool: invalid value %s\n", v);
- return -EINVAL;
- }
+ b.name = name;
+ if (!strcmp(value, "1") || !strcasecmp(value, "true") || !strcasecmp(value, "on"))
+ b.value = 1;
+ else if (!strcmp(value, "0") || !strcasecmp(value, "false") || !strcasecmp(value, "off"))
+ b.value = 0;
+ else {
+ ERROR("setsebool: invalid value %s\n", value);
+ return -EINVAL;
+ }
+
+ if (security_set_boolean_list(1, &b, 0) < 0) {
+ ret = -errno;
+ ERROR("setsebool: could not set %s to %s\n", name, value);
+ return ret;
}
- if (security_set_boolean_list(nargs - 1, b, 0) < 0)
- return -errno;
-#endif
return 0;
}
diff --git a/init/devices.c b/init/devices.c
index e43dbaf..e25034c 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -30,11 +30,9 @@
#include <sys/un.h>
#include <linux/netlink.h>
-#ifdef HAVE_SELINUX
#include <selinux/selinux.h>
#include <selinux/label.h>
#include <selinux/android.h>
-#endif
#include <private/android_filesystem_config.h>
#include <sys/time.h>
@@ -51,10 +49,9 @@
#define SYSFS_PREFIX "/sys"
#define FIRMWARE_DIR1 "/etc/firmware"
#define FIRMWARE_DIR2 "/vendor/firmware"
+#define FIRMWARE_DIR3 "/firmware/image"
-#ifdef HAVE_SELINUX
extern struct selabel_handle *sehandle;
-#endif
static int device_fd = -1;
@@ -86,7 +83,8 @@ struct perm_node {
struct platform_node {
char *name;
- int name_len;
+ char *path;
+ int path_len;
struct listnode list;
};
@@ -192,17 +190,15 @@ static void make_device(const char *path,
unsigned gid;
mode_t mode;
dev_t dev;
-#ifdef HAVE_SELINUX
char *secontext = NULL;
-#endif
mode = get_device_perm(path, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
-#ifdef HAVE_SELINUX
+
if (sehandle) {
selabel_lookup(sehandle, &secontext, path, mode);
setfscreatecon(secontext);
}
-#endif
+
dev = makedev(major, minor);
/* Temporarily change egid to avoid race condition setting the gid of the
* device node. Unforunately changing the euid would prevent creation of
@@ -213,69 +209,76 @@ static void make_device(const char *path,
mknod(path, mode, dev);
chown(path, uid, -1);
setegid(AID_ROOT);
-#ifdef HAVE_SELINUX
+
if (secontext) {
freecon(secontext);
setfscreatecon(NULL);
}
-#endif
}
-static void add_platform_device(const char *name)
+static void add_platform_device(const char *path)
{
- int name_len = strlen(name);
+ int path_len = strlen(path);
struct listnode *node;
struct platform_node *bus;
+ const char *name = path;
+
+ if (!strncmp(path, "/devices/", 9)) {
+ name += 9;
+ if (!strncmp(name, "platform/", 9))
+ name += 9;
+ }
list_for_each_reverse(node, &platform_names) {
bus = node_to_item(node, struct platform_node, list);
- if ((bus->name_len < name_len) &&
- (name[bus->name_len] == '/') &&
- !strncmp(name, bus->name, bus->name_len))
+ if ((bus->path_len < path_len) &&
+ (path[bus->path_len] == '/') &&
+ !strncmp(path, bus->path, bus->path_len))
/* subdevice of an existing platform, ignore it */
return;
}
- INFO("adding platform device %s\n", name);
+ INFO("adding platform device %s (%s)\n", name, path);
bus = calloc(1, sizeof(struct platform_node));
- bus->name = strdup(name);
- bus->name_len = name_len;
+ bus->path = strdup(path);
+ bus->path_len = path_len;
+ bus->name = bus->path + (name - path);
list_add_tail(&platform_names, &bus->list);
}
/*
- * given a name that may start with a platform device, find the length of the
+ * given a path that may start with a platform device, find the length of the
* platform device prefix. If it doesn't start with a platform device, return
* 0.
*/
-static const char *find_platform_device(const char *name)
+static struct platform_node *find_platform_device(const char *path)
{
- int name_len = strlen(name);
+ int path_len = strlen(path);
struct listnode *node;
struct platform_node *bus;
list_for_each_reverse(node, &platform_names) {
bus = node_to_item(node, struct platform_node, list);
- if ((bus->name_len < name_len) &&
- (name[bus->name_len] == '/') &&
- !strncmp(name, bus->name, bus->name_len))
- return bus->name;
+ if ((bus->path_len < path_len) &&
+ (path[bus->path_len] == '/') &&
+ !strncmp(path, bus->path, bus->path_len))
+ return bus;
}
return NULL;
}
-static void remove_platform_device(const char *name)
+static void remove_platform_device(const char *path)
{
struct listnode *node;
struct platform_node *bus;
list_for_each_reverse(node, &platform_names) {
bus = node_to_item(node, struct platform_node, list);
- if (!strcmp(name, bus->name)) {
- INFO("removing platform device %s\n", name);
- free(bus->name);
+ if (!strcmp(path, bus->path)) {
+ INFO("removing platform device %s\n", bus->name);
+ free(bus->path);
list_remove(node);
free(bus);
return;
@@ -361,8 +364,10 @@ static char **get_character_device_symlinks(struct uevent *uevent)
char **links;
int link_num = 0;
int width;
+ struct platform_node *pdev;
- if (strncmp(uevent->path, "/devices/platform/", 18))
+ pdev = find_platform_device(uevent->path);
+ if (!pdev)
return NULL;
links = malloc(sizeof(char *) * 2);
@@ -371,7 +376,7 @@ static char **get_character_device_symlinks(struct uevent *uevent)
memset(links, 0, sizeof(char *) * 2);
/* skip "/devices/platform/<driver>" */
- parent = strchr(uevent->path + 18, '/');
+ parent = strchr(uevent->path + pdev->path_len, '/');
if (!*parent)
goto err;
@@ -408,7 +413,7 @@ err:
static char **parse_platform_block_device(struct uevent *uevent)
{
const char *device;
- const char *path;
+ struct platform_node *pdev;
char *slash;
int width;
char buf[256];
@@ -420,18 +425,16 @@ static char **parse_platform_block_device(struct uevent *uevent)
unsigned int size;
struct stat info;
+ pdev = find_platform_device(uevent->path);
+ if (!pdev)
+ return NULL;
+ device = pdev->name;
+
char **links = malloc(sizeof(char *) * 4);
if (!links)
return NULL;
memset(links, 0, sizeof(char *) * 4);
- /* Drop "/devices/platform/" */
- path = uevent->path;
- device = path + 18;
- device = find_platform_device(device);
- if (!device)
- goto err;
-
INFO("found platform device %s\n", device);
snprintf(link_path, sizeof(link_path), "/dev/block/platform/%s", device);
@@ -453,17 +456,13 @@ static char **parse_platform_block_device(struct uevent *uevent)
links[link_num] = NULL;
}
- slash = strrchr(path, '/');
+ slash = strrchr(uevent->path, '/');
if (asprintf(&links[link_num], "%s/%s", link_path, slash + 1) > 0)
link_num++;
else
links[link_num] = NULL;
return links;
-
-err:
- free(links);
- return NULL;
}
static void handle_device(const char *action, const char *devpath,
@@ -496,12 +495,12 @@ static void handle_device(const char *action, const char *devpath,
static void handle_platform_device_event(struct uevent *uevent)
{
- const char *name = uevent->path + 18; /* length of /devices/platform/ */
+ const char *path = uevent->path;
if (!strcmp(uevent->action, "add"))
- add_platform_device(name);
+ add_platform_device(path);
else if (!strcmp(uevent->action, "remove"))
- remove_platform_device(name);
+ remove_platform_device(path);
}
static const char *parse_device_name(struct uevent *uevent, unsigned int len)
@@ -539,7 +538,7 @@ static void handle_block_device_event(struct uevent *uevent)
snprintf(devpath, sizeof(devpath), "%s%s", base, name);
make_dir(base, 0755);
- if (!strncmp(uevent->path, "/devices/platform/", 18))
+ if (!strncmp(uevent->path, "/devices/", 9))
links = parse_platform_block_device(uevent);
handle_device(uevent->action, devpath, uevent->path, 1,
@@ -638,7 +637,7 @@ static void handle_generic_device_event(struct uevent *uevent)
static void handle_device_event(struct uevent *uevent)
{
- if (!strcmp(uevent->action,"add"))
+ if (!strcmp(uevent->action,"add") || !strcmp(uevent->action, "change"))
fixup_sys_perms(uevent->path);
if (!strncmp(uevent->subsystem, "block", 5)) {
@@ -703,7 +702,7 @@ static int is_booting(void)
static void process_firmware_event(struct uevent *uevent)
{
- char *root, *loading, *data, *file1 = NULL, *file2 = NULL;
+ char *root, *loading, *data, *file1 = NULL, *file2 = NULL, *file3 = NULL;
int l, loading_fd, data_fd, fw_fd;
int booting = is_booting();
@@ -730,6 +729,10 @@ static void process_firmware_event(struct uevent *uevent)
if (l == -1)
goto data_free_out;
+ l = asprintf(&file3, FIRMWARE_DIR3"/%s", uevent->firmware);
+ if (l == -1)
+ goto data_free_out;
+
loading_fd = open(loading, O_WRONLY);
if(loading_fd < 0)
goto file_free_out;
@@ -743,17 +746,20 @@ try_loading_again:
if(fw_fd < 0) {
fw_fd = open(file2, O_RDONLY);
if (fw_fd < 0) {
- if (booting) {
- /* If we're not fully booted, we may be missing
- * filesystems needed for firmware, wait and retry.
- */
- usleep(100000);
- booting = is_booting();
- goto try_loading_again;
+ fw_fd = open(file3, O_RDONLY);
+ if (fw_fd < 0) {
+ if (booting) {
+ /* If we're not fully booted, we may be missing
+ * filesystems needed for firmware, wait and retry.
+ */
+ usleep(100000);
+ booting = is_booting();
+ goto try_loading_again;
+ }
+ INFO("firmware: could not open '%s' %d\n", uevent->firmware, errno);
+ write(loading_fd, "-1", 2);
+ goto data_close_out;
}
- INFO("firmware: could not open '%s' %d\n", uevent->firmware, errno);
- write(loading_fd, "-1", 2);
- goto data_close_out;
}
}
@@ -874,14 +880,14 @@ void device_init(void)
suseconds_t t0, t1;
struct stat info;
int fd;
-#ifdef HAVE_SELINUX
+
sehandle = NULL;
if (is_selinux_enabled() > 0) {
sehandle = selinux_android_file_context_handle();
}
-#endif
- /* is 64K enough? udev uses 16MB! */
- device_fd = uevent_open_socket(64*1024, true);
+
+ /* is 256K enough? udev uses 16MB! */
+ device_fd = uevent_open_socket(256*1024, true);
if(device_fd < 0)
return;
diff --git a/init/init.c b/init/init.c
index b2e39bd..b28b0ab 100755
--- a/init/init.c
+++ b/init/init.c
@@ -32,11 +32,9 @@
#include <sys/socket.h>
#include <sys/un.h>
-#ifdef HAVE_SELINUX
#include <selinux/selinux.h>
#include <selinux/label.h>
#include <selinux/android.h>
-#endif
#include <libgen.h>
@@ -58,11 +56,10 @@
#include "init_parser.h"
#include "util.h"
#include "ueventd.h"
+#include "watchdogd.h"
-#ifdef HAVE_SELINUX
struct selabel_handle *sehandle;
struct selabel_handle *sehandle_prop;
-#endif
static int property_triggers_enabled = 0;
@@ -76,9 +73,7 @@ static char hardware[32];
static unsigned revision = 0;
static char qemu[32];
-#ifdef HAVE_SELINUX
static int selinux_enabled = 1;
-#endif
static struct action *cur_action = NULL;
static struct command *cur_command = NULL;
@@ -162,10 +157,9 @@ void service_start(struct service *svc, const char *dynamic_args)
pid_t pid;
int needs_console;
int n;
-#ifdef HAVE_SELINUX
char *scon = NULL;
int rc;
-#endif
+
/* starting a service removes it from the disabled or reset
* state and immediately takes it out of the restarting
* state if it was in there
@@ -202,33 +196,39 @@ void service_start(struct service *svc, const char *dynamic_args)
return;
}
-#ifdef HAVE_SELINUX
if (is_selinux_enabled() > 0) {
- char *mycon = NULL, *fcon = NULL;
+ if (svc->seclabel) {
+ scon = strdup(svc->seclabel);
+ if (!scon) {
+ ERROR("Out of memory while starting '%s'\n", svc->name);
+ return;
+ }
+ } else {
+ char *mycon = NULL, *fcon = NULL;
- INFO("computing context for service '%s'\n", svc->args[0]);
- rc = getcon(&mycon);
- if (rc < 0) {
- ERROR("could not get context while starting '%s'\n", svc->name);
- return;
- }
+ INFO("computing context for service '%s'\n", svc->args[0]);
+ rc = getcon(&mycon);
+ if (rc < 0) {
+ ERROR("could not get context while starting '%s'\n", svc->name);
+ return;
+ }
- rc = getfilecon(svc->args[0], &fcon);
- if (rc < 0) {
- ERROR("could not get context while starting '%s'\n", svc->name);
- freecon(mycon);
- return;
- }
+ rc = getfilecon(svc->args[0], &fcon);
+ if (rc < 0) {
+ ERROR("could not get context while starting '%s'\n", svc->name);
+ freecon(mycon);
+ return;
+ }
- rc = security_compute_create(mycon, fcon, string_to_security_class("process"), &scon);
- freecon(mycon);
- freecon(fcon);
- if (rc < 0) {
- ERROR("could not get context while starting '%s'\n", svc->name);
- return;
+ rc = security_compute_create(mycon, fcon, string_to_security_class("process"), &scon);
+ freecon(mycon);
+ freecon(fcon);
+ if (rc < 0) {
+ ERROR("could not get context while starting '%s'\n", svc->name);
+ return;
+ }
}
}
-#endif
NOTICE("starting '%s'\n", svc->name);
@@ -250,9 +250,7 @@ void service_start(struct service *svc, const char *dynamic_args)
for (ei = svc->envvars; ei; ei = ei->next)
add_environment(ei->name, ei->value);
-#ifdef HAVE_SELINUX
setsockcreatecon(scon);
-#endif
for (si = svc->sockets; si; si = si->next) {
int socket_type = (
@@ -265,11 +263,9 @@ void service_start(struct service *svc, const char *dynamic_args)
}
}
-#ifdef HAVE_SELINUX
freecon(scon);
scon = NULL;
setsockcreatecon(NULL);
-#endif
if (svc->ioprio_class != IoSchedClass_NONE) {
if (android_set_ioprio(getpid(), svc->ioprio_class, svc->ioprio_pri)) {
@@ -315,15 +311,12 @@ void service_start(struct service *svc, const char *dynamic_args)
_exit(127);
}
}
-
-#ifdef HAVE_SELINUX
if (svc->seclabel) {
if (is_selinux_enabled() > 0 && setexeccon(svc->seclabel) < 0) {
ERROR("cannot setexeccon('%s'): %s\n", svc->seclabel, strerror(errno));
_exit(127);
}
}
-#endif
if (!dynamic_args) {
if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) {
@@ -350,9 +343,7 @@ void service_start(struct service *svc, const char *dynamic_args)
_exit(127);
}
-#ifdef HAVE_SELINUX
freecon(scon);
-#endif
if (pid < 0) {
ERROR("failed to start '%s'\n", svc->name);
@@ -603,11 +594,9 @@ static void import_kernel_nv(char *name, int for_emulator)
*value++ = 0;
if (name_len == 0) return;
-#ifdef HAVE_SELINUX
if (!strcmp(name,"selinux")) {
selinux_enabled = atoi(value);
}
-#endif
if (for_emulator) {
/* in the emulator, export any kernel option with the
@@ -755,9 +744,8 @@ 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, "/data/security/property_contexts" },
{ SELABEL_OPT_PATH, "/property_contexts" },
{ 0, NULL }
};
@@ -814,8 +802,6 @@ int audit_callback(void *data, security_class_t cls, char *buf, size_t len)
return 0;
}
-#endif
-
int main(int argc, char **argv)
{
int fd_count = 0;
@@ -831,6 +817,9 @@ int main(int argc, char **argv)
if (!strcmp(basename(argv[0]), "ueventd"))
return ueventd_main(argc, argv);
+ if (!strcmp(basename(argv[0]), "watchdogd"))
+ return watchdogd_main(argc, argv);
+
/* clear the umask */
umask(0);
@@ -866,7 +855,6 @@ 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);
@@ -891,7 +879,6 @@ int main(int argc, char **argv)
*/
restorecon("/dev");
restorecon("/dev/socket");
-#endif
is_charger = !strcmp(bootmode, "charger");
diff --git a/init/init.h b/init/init.h
index b7e06c9..955e1f0 100644
--- a/init/init.h
+++ b/init/init.h
@@ -95,9 +95,7 @@ struct service {
gid_t supp_gids[NR_SVC_SUPP_GIDS];
size_t nr_supp_gids;
-#ifdef HAVE_SELINUX
char *seclabel;
-#endif
struct socketinfo *sockets;
struct svcenvinfo *envvars;
@@ -136,10 +134,8 @@ void property_changed(const char *name, const char *value);
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
#endif /* _INIT_INIT_H */
diff --git a/init/init_parser.c b/init/init_parser.c
index 5393e52..beb9188 100644
--- a/init/init_parser.c
+++ b/init/init_parser.c
@@ -799,13 +799,11 @@ static void parse_line_service(struct parse_state *state, int nargs, char **args
}
break;
case K_seclabel:
-#ifdef HAVE_SELINUX
if (nargs != 2) {
parse_error(state, "seclabel option requires a label string\n");
} else {
svc->seclabel = args[1];
}
-#endif
break;
default:
diff --git a/init/keywords.h b/init/keywords.h
index 97d4950..f188db5 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -78,7 +78,7 @@ enum {
KEYWORD(setkey, COMMAND, 0, do_setkey)
KEYWORD(setprop, COMMAND, 2, do_setprop)
KEYWORD(setrlimit, COMMAND, 3, do_setrlimit)
- KEYWORD(setsebool, COMMAND, 1, do_setsebool)
+ KEYWORD(setsebool, COMMAND, 2, do_setsebool)
KEYWORD(socket, OPTION, 0, 0)
KEYWORD(start, COMMAND, 1, do_start)
KEYWORD(stop, COMMAND, 1, do_stop)
diff --git a/init/property_service.c b/init/property_service.c
index 5017375..61dd86f 100644..100755
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -40,10 +40,8 @@
#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"
@@ -81,6 +79,7 @@ struct {
{ "sys.", AID_SYSTEM, 0 },
{ "service.", AID_SYSTEM, 0 },
{ "wlan.", AID_SYSTEM, 0 },
+ { "bluetooth.", AID_BLUETOOTH, 0 },
{ "dhcp.", AID_SYSTEM, 0 },
{ "dhcp.", AID_DHCP, 0 },
{ "debug.", AID_SYSTEM, 0 },
@@ -91,6 +90,7 @@ struct {
{ "persist.sys.", AID_SYSTEM, 0 },
{ "persist.service.", AID_SYSTEM, 0 },
{ "persist.security.", AID_SYSTEM, 0 },
+ { "persist.service.bdroid.", AID_BLUETOOTH, 0 },
{ "selinux." , AID_SYSTEM, 0 },
{ NULL, 0, 0 }
};
@@ -123,7 +123,7 @@ static int init_workspace(workspace *w, size_t size)
/* dev is a tmpfs that we can use to carve a shared workspace
* out of, so let's do that...
*/
- fd = open("/dev/__properties__", O_RDWR | O_CREAT, 0600);
+ fd = open("/dev/__properties__", O_RDWR | O_CREAT | O_NOFOLLOW, 0600);
if (fd < 0)
return -1;
@@ -136,7 +136,7 @@ static int init_workspace(workspace *w, size_t size)
close(fd);
- fd = open("/dev/__properties__", O_RDONLY);
+ fd = open("/dev/__properties__", O_RDONLY | O_NOFOLLOW);
if (fd < 0)
return -1;
@@ -199,7 +199,6 @@ static void update_prop_info(prop_info *pi, const char *value, unsigned len)
static int check_mac_perms(const char *name, char *sctx)
{
-#ifdef HAVE_SELINUX
if (is_selinux_enabled() <= 0)
return 1;
@@ -223,15 +222,10 @@ static int check_mac_perms(const char *name, char *sctx)
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
@@ -245,9 +239,6 @@ static int check_control_mac_perms(const char *name, char *sctx)
return 0;
return check_mac_perms(ctl_name, sctx);
-
-#endif
- return 1;
}
/*
@@ -318,13 +309,12 @@ const char* property_get(const char *name)
static void write_persistent_property(const char *name, const char *value)
{
- const char *tempPath = PERSISTENT_PROPERTY_DIR "/.temp";
+ char tempPath[PATH_MAX];
char path[PATH_MAX];
- int fd, length;
-
- snprintf(path, sizeof(path), "%s/%s", PERSISTENT_PROPERTY_DIR, name);
+ int fd;
- fd = open(tempPath, O_WRONLY|O_CREAT|O_TRUNC, 0600);
+ snprintf(tempPath, sizeof(tempPath), "%s/.temp.XXXXXX", PERSISTENT_PROPERTY_DIR);
+ fd = mkstemp(tempPath);
if (fd < 0) {
ERROR("Unable to write persistent property to temp file %s errno: %d\n", tempPath, errno);
return;
@@ -332,6 +322,7 @@ static void write_persistent_property(const char *name, const char *value)
write(fd, value, strlen(value));
close(fd);
+ snprintf(path, sizeof(path), "%s/%s", PERSISTENT_PROPERTY_DIR, name);
if (rename(tempPath, path)) {
unlink(tempPath);
ERROR("Unable to rename persistent property file %s to %s\n", tempPath, path);
@@ -343,8 +334,8 @@ int property_set(const char *name, const char *value)
prop_area *pa;
prop_info *pi;
- int namelen = strlen(name);
- int valuelen = strlen(value);
+ size_t namelen = strlen(name);
+ size_t valuelen = strlen(value);
if(namelen >= PROP_NAME_MAX) return -1;
if(valuelen >= PROP_VALUE_MAX) return -1;
@@ -394,11 +385,9 @@ int property_set(const char *name, const char *value)
* to prevent them from being overwritten by default values.
*/
write_persistent_property(name, value);
-#ifdef HAVE_SELINUX
} else if (strcmp("selinux.reload_policy", name) == 0 &&
strcmp("1", value) == 0) {
selinux_reload_policy();
-#endif
}
property_changed(name, value);
return 0;
@@ -423,13 +412,13 @@ void handle_property_set_fd()
/* Check socket options here */
if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
close(s);
- ERROR("Unable to recieve socket options\n");
+ ERROR("Unable to receive socket options\n");
return;
}
r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), 0));
if(r != sizeof(prop_msg)) {
- ERROR("sys_prop: mis-match msg size recieved: %d expected: %d errno: %d\n",
+ ERROR("sys_prop: mis-match msg size received: %d expected: %d errno: %d\n",
r, sizeof(prop_msg), errno);
close(s);
return;
@@ -440,9 +429,7 @@ 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
@@ -467,10 +454,7 @@ void handle_property_set_fd()
// the property is written to memory.
close(s);
}
-#ifdef HAVE_SELINUX
freecon(source_ctx);
-#endif
-
break;
default:
@@ -528,12 +512,14 @@ static void load_properties_from_file(const char *fn)
static void load_persistent_properties()
{
DIR* dir = opendir(PERSISTENT_PROPERTY_DIR);
+ int dir_fd;
struct dirent* entry;
- char path[PATH_MAX];
char value[PROP_VALUE_MAX];
int fd, length;
+ struct stat sb;
if (dir) {
+ dir_fd = dirfd(dir);
while ((entry = readdir(dir)) != NULL) {
if (strncmp("persist.", entry->d_name, strlen("persist.")))
continue;
@@ -542,20 +528,39 @@ static void load_persistent_properties()
continue;
#endif
/* open the file and read the property value */
- snprintf(path, sizeof(path), "%s/%s", PERSISTENT_PROPERTY_DIR, entry->d_name);
- fd = open(path, O_RDONLY);
- if (fd >= 0) {
- length = read(fd, value, sizeof(value) - 1);
- if (length >= 0) {
- value[length] = 0;
- property_set(entry->d_name, value);
- } else {
- ERROR("Unable to read persistent property file %s errno: %d\n", path, errno);
- }
+ fd = openat(dir_fd, entry->d_name, O_RDONLY | O_NOFOLLOW);
+ if (fd < 0) {
+ ERROR("Unable to open persistent property file \"%s\" errno: %d\n",
+ entry->d_name, errno);
+ continue;
+ }
+ if (fstat(fd, &sb) < 0) {
+ ERROR("fstat on property file \"%s\" failed errno: %d\n", entry->d_name, errno);
close(fd);
+ continue;
+ }
+
+ // File must not be accessible to others, be owned by root/root, and
+ // not be a hard link to any other file.
+ if (((sb.st_mode & (S_IRWXG | S_IRWXO)) != 0)
+ || (sb.st_uid != 0)
+ || (sb.st_gid != 0)
+ || (sb.st_nlink != 1)) {
+ ERROR("skipping insecure property file %s (uid=%lu gid=%lu nlink=%d mode=%o)\n",
+ entry->d_name, sb.st_uid, sb.st_gid, sb.st_nlink, sb.st_mode);
+ close(fd);
+ continue;
+ }
+
+ length = read(fd, value, sizeof(value) - 1);
+ if (length >= 0) {
+ value[length] = 0;
+ property_set(entry->d_name, value);
} else {
- ERROR("Unable to open persistent property file %s errno: %d\n", path, errno);
+ ERROR("Unable to read persistent property file %s errno: %d\n",
+ entry->d_name, errno);
}
+ close(fd);
}
closedir(dir);
} else {
@@ -580,6 +585,16 @@ int properties_inited(void)
return property_area_inited;
}
+static void load_override_properties() {
+#ifdef ALLOW_LOCAL_PROP_OVERRIDE
+ const char *debuggable = property_get("ro.debuggable");
+ if (debuggable && (strcmp(debuggable, "1") == 0)) {
+ load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE);
+ }
+#endif /* ALLOW_LOCAL_PROP_OVERRIDE */
+}
+
+
/* When booting an encrypted system, /data is not mounted when the
* property service is started, so any properties stored there are
* not loaded. Vold triggers init to load these properties once it
@@ -587,9 +602,7 @@ int properties_inited(void)
*/
void load_persist_props(void)
{
-#ifdef ALLOW_LOCAL_PROP_OVERRIDE
- load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE);
-#endif /* ALLOW_LOCAL_PROP_OVERRIDE */
+ load_override_properties();
/* Read persistent properties after all default values have been loaded. */
load_persistent_properties();
}
@@ -600,9 +613,7 @@ void start_property_service(void)
load_properties_from_file(PROP_PATH_SYSTEM_BUILD);
load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);
-#ifdef ALLOW_LOCAL_PROP_OVERRIDE
- load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE);
-#endif /* ALLOW_LOCAL_PROP_OVERRIDE */
+ load_override_properties();
/* Read persistent properties after all default values have been loaded. */
load_persistent_properties();
diff --git a/init/readme.txt b/init/readme.txt
index fe0d15d..7a5997d 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -88,6 +88,13 @@ group <groupname> [ <groupname> ]*
supplemental groups of the process (via setgroups()).
Currently defaults to root. (??? probably should default to nobody)
+seclabel <securitycontext>
+ Change to securitycontext before exec'ing this service.
+ Primarily for use by services run from the rootfs, e.g. ueventd, adbd.
+ Services on the system partition can instead use policy-defined transitions
+ based on their file security context.
+ If not specified and no transition is defined in policy, defaults to the init context.
+
oneshot
Do not restart the service when it exits.
@@ -182,6 +189,21 @@ mount <type> <device> <dir> [ <mountoption> ]*
device by name.
<mountoption>s include "ro", "rw", "remount", "noatime", ...
+restorecon <path>
+ Restore the file named by <path> to the security context specified
+ in the file_contexts configuration.
+ Not required for directories created by the init.rc as these are
+ automatically labeled correctly by init.
+
+setcon <securitycontext>
+ Set the current process security context to the specified string.
+ This is typically only used from early-init to set the init context
+ before any other process is started.
+
+setenforce 0|1
+ Set the SELinux system-wide enforcing status.
+ 0 is permissive (i.e. log but do not deny), 1 is enforcing.
+
setkey
TBD
@@ -191,6 +213,10 @@ setprop <name> <value>
setrlimit <resource> <cur> <max>
Set the rlimit for a resource.
+setsebool <name> <value>
+ Set SELinux boolean <name> to <value>.
+ <value> may be 1|true|on or 0|false|off
+
start <service>
Start a service running if it is not already running.
diff --git a/init/ueventd.c b/init/ueventd.c
index a89e067..a41c31e 100644
--- a/init/ueventd.c
+++ b/init/ueventd.c
@@ -105,7 +105,7 @@ static int get_android_id(const char *id)
for (i = 0; i < ARRAY_SIZE(android_ids); i++)
if (!strcmp(id, android_ids[i].name))
return android_ids[i].aid;
- return 0;
+ return -1;
}
void set_device_permission(int nargs, char **args)
diff --git a/init/util.c b/init/util.c
index 743748b..918bc05 100755
--- a/init/util.c
+++ b/init/util.c
@@ -23,9 +23,7 @@
#include <errno.h>
#include <time.h>
-#ifdef HAVE_SELINUX
#include <selinux/label.h>
-#endif
#include <sys/stat.h>
#include <sys/types.h>
@@ -89,9 +87,7 @@ int create_socket(const char *name, int type, mode_t perm, uid_t uid, gid_t gid)
{
struct sockaddr_un addr;
int fd, ret;
-#ifdef HAVE_SELINUX
char *secon;
-#endif
fd = socket(PF_UNIX, type, 0);
if (fd < 0) {
@@ -110,14 +106,12 @@ int create_socket(const char *name, int type, mode_t perm, uid_t uid, gid_t gid)
goto out_close;
}
-#ifdef HAVE_SELINUX
secon = NULL;
if (sehandle) {
ret = selabel_lookup(sehandle, &secon, addr.sun_path, S_IFSOCK);
if (ret == 0)
setfscreatecon(secon);
}
-#endif
ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
if (ret) {
@@ -125,10 +119,8 @@ int create_socket(const char *name, int type, mode_t perm, uid_t uid, gid_t gid)
goto out_unlink;
}
-#ifdef HAVE_SELINUX
setfscreatecon(NULL);
freecon(secon);
-#endif
chown(addr.sun_path, uid, gid);
chmod(addr.sun_path, perm);
@@ -468,31 +460,27 @@ int make_dir(const char *path, mode_t mode)
{
int rc;
-#ifdef HAVE_SELINUX
char *secontext = NULL;
if (sehandle) {
selabel_lookup(sehandle, &secontext, path, mode);
setfscreatecon(secontext);
}
-#endif
rc = mkdir(path, mode);
-#ifdef HAVE_SELINUX
if (secontext) {
int save_errno = errno;
freecon(secontext);
setfscreatecon(NULL);
errno = save_errno;
}
-#endif
+
return rc;
}
int restorecon(const char *pathname)
{
-#ifdef HAVE_SELINUX
char *secontext = NULL;
struct stat sb;
int i;
@@ -509,6 +497,5 @@ int restorecon(const char *pathname)
return -errno;
}
freecon(secontext);
-#endif
return 0;
}
diff --git a/init/watchdogd.c b/init/watchdogd.c
new file mode 100644
index 0000000..fb53836
--- /dev/null
+++ b/init/watchdogd.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2012 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <linux/watchdog.h>
+
+#include "log.h"
+#include "util.h"
+
+#define DEV_NAME "/dev/watchdog"
+
+int watchdogd_main(int argc, char **argv)
+{
+ int fd;
+ int ret;
+ int interval = 10;
+ int margin = 10;
+ int timeout;
+
+ open_devnull_stdio();
+ klog_init();
+
+ INFO("Starting watchdogd\n");
+
+ if (argc >= 2)
+ interval = atoi(argv[1]);
+
+ if (argc >= 3)
+ margin = atoi(argv[2]);
+
+ timeout = interval + margin;
+
+ fd = open(DEV_NAME, O_RDWR);
+ if (fd < 0) {
+ ERROR("watchdogd: Failed to open %s: %s\n", DEV_NAME, strerror(errno));
+ return 1;
+ }
+
+ ret = ioctl(fd, WDIOC_SETTIMEOUT, &timeout);
+ if (ret) {
+ ERROR("watchdogd: Failed to set timeout to %d: %s\n", timeout, strerror(errno));
+ ret = ioctl(fd, WDIOC_GETTIMEOUT, &timeout);
+ if (ret) {
+ ERROR("watchdogd: Failed to get timeout: %s\n", strerror(errno));
+ } else {
+ if (timeout > margin)
+ interval = timeout - margin;
+ else
+ interval = 1;
+ ERROR("watchdogd: Adjusted interval to timeout returned by driver: timeout %d, interval %d, margin %d\n",
+ timeout, interval, margin);
+ }
+ }
+
+ while(1) {
+ write(fd, "", 1);
+ sleep(interval);
+ }
+}
+
diff --git a/init/watchdogd.h b/init/watchdogd.h
new file mode 100644
index 0000000..8b48ab8
--- /dev/null
+++ b/init/watchdogd.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _INIT_WATCHDOGD_H_
+#define _INIT_WATCHDOGD_H_
+
+int watchdogd_main(int argc, char **argv);
+
+#endif