summaryrefslogtreecommitdiffstats
path: root/init
diff options
context:
space:
mode:
Diffstat (limited to 'init')
-rw-r--r--init/Android.mk1
-rw-r--r--init/builtins.c16
-rw-r--r--init/devices.c94
-rw-r--r--init/init.c56
-rw-r--r--init/init.h5
-rw-r--r--init/init_parser.c21
-rw-r--r--init/keywords.h2
-rw-r--r--init/logo.c163
-rw-r--r--init/parser.h1
-rw-r--r--init/property_service.c31
-rw-r--r--init/readme.txt13
-rw-r--r--init/signal_handler.c10
-rw-r--r--init/ueventd.c2
-rw-r--r--init/ueventd.h15
-rw-r--r--init/ueventd_keywords.h15
-rw-r--r--init/ueventd_parser.c181
-rw-r--r--init/ueventd_parser.h3
-rw-r--r--init/util.c91
-rw-r--r--init/util.h2
19 files changed, 433 insertions, 289 deletions
diff --git a/init/Android.mk b/init/Android.mk
index abfc68a..1f43ba6 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -10,7 +10,6 @@ LOCAL_SRC_FILES:= \
property_service.c \
util.c \
parser.c \
- logo.c \
keychords.c \
signal_handler.c \
init_parser.c \
diff --git a/init/builtins.c b/init/builtins.c
index e8c8f91..e2932d5 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -797,12 +797,24 @@ int do_chmod(int nargs, char **args) {
int do_restorecon(int nargs, char **args) {
int i;
+ int ret = 0;
for (i = 1; i < nargs; i++) {
if (restorecon(args[i]) < 0)
- return -errno;
+ ret = -errno;
}
- return 0;
+ return ret;
+}
+
+int do_restorecon_recursive(int nargs, char **args) {
+ int i;
+ int ret = 0;
+
+ for (i = 1; i < nargs; i++) {
+ if (restorecon_recursive(args[i]) < 0)
+ ret = -errno;
+ }
+ return ret;
}
int do_setsebool(int nargs, char **args) {
diff --git a/init/devices.c b/init/devices.c
index 1893642..f7df453 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -33,6 +33,7 @@
#include <selinux/selinux.h>
#include <selinux/label.h>
#include <selinux/android.h>
+#include <selinux/avc.h>
#include <private/android_filesystem_config.h>
#include <sys/time.h>
@@ -43,6 +44,7 @@
#include <cutils/uevent.h>
#include "devices.h"
+#include "ueventd_parser.h"
#include "util.h"
#include "log.h"
@@ -529,8 +531,11 @@ static const char *parse_device_name(struct uevent *uevent, unsigned int len)
name++;
/* too-long names would overrun our buffer */
- if(strlen(name) > len)
+ if(strlen(name) > len) {
+ ERROR("DEVPATH=%s exceeds %u-character limit on filename; ignoring event\n",
+ name, len);
return NULL;
+ }
return name;
}
@@ -556,37 +561,76 @@ static void handle_block_device_event(struct uevent *uevent)
uevent->major, uevent->minor, links);
}
+#define DEVPATH_LEN 96
+
+static bool assemble_devpath(char *devpath, const char *dirname,
+ const char *devname)
+{
+ int s = snprintf(devpath, DEVPATH_LEN, "%s/%s", dirname, devname);
+ if (s < 0) {
+ ERROR("failed to assemble device path (%s); ignoring event\n",
+ strerror(errno));
+ return false;
+ } else if (s >= DEVPATH_LEN) {
+ ERROR("%s/%s exceeds %u-character limit on path; ignoring event\n",
+ dirname, devname, DEVPATH_LEN);
+ return false;
+ }
+ return true;
+}
+
+static void mkdir_recursive_for_devpath(const char *devpath)
+{
+ char dir[DEVPATH_LEN];
+ char *slash;
+
+ strcpy(dir, devpath);
+ slash = strrchr(dir, '/');
+ *slash = '\0';
+ mkdir_recursive(dir, 0755);
+}
+
static void handle_generic_device_event(struct uevent *uevent)
{
char *base;
const char *name;
- char devpath[96] = {0};
+ char devpath[DEVPATH_LEN] = {0};
char **links = NULL;
name = parse_device_name(uevent, 64);
if (!name)
return;
- if (!strncmp(uevent->subsystem, "usb", 3)) {
+ struct ueventd_subsystem *subsystem =
+ ueventd_subsystem_find_by_name(uevent->subsystem);
+
+ if (subsystem) {
+ const char *devname;
+
+ switch (subsystem->devname_src) {
+ case DEVNAME_UEVENT_DEVNAME:
+ devname = uevent->device_name;
+ break;
+
+ case DEVNAME_UEVENT_DEVPATH:
+ devname = name;
+ break;
+
+ default:
+ ERROR("%s subsystem's devpath option is not set; ignoring event\n",
+ uevent->subsystem);
+ return;
+ }
+
+ if (!assemble_devpath(devpath, subsystem->dirname, devname))
+ return;
+ mkdir_recursive_for_devpath(devpath);
+ } else if (!strncmp(uevent->subsystem, "usb", 3)) {
if (!strcmp(uevent->subsystem, "usb")) {
if (uevent->device_name) {
- /*
- * create device node provided by kernel if present
- * see drivers/base/core.c
- */
- char *p = devpath;
- snprintf(devpath, sizeof(devpath), "/dev/%s", uevent->device_name);
- /* skip leading /dev/ */
- p += 5;
- /* build directories */
- while (*p) {
- if (*p == '/') {
- *p = 0;
- make_dir(devpath, 0755);
- *p = '/';
- }
- p++;
- }
+ if (!assemble_devpath(devpath, "/dev", uevent->device_name))
+ return;
+ mkdir_recursive_for_devpath(devpath);
}
else {
/* This imitates the file system that would be created
@@ -830,6 +874,15 @@ void handle_device_fd()
struct uevent uevent;
parse_event(msg, &uevent);
+ if (sehandle && selinux_status_updated() > 0) {
+ struct selabel_handle *sehandle2;
+ sehandle2 = selinux_android_file_context_handle();
+ if (sehandle2) {
+ selabel_close(sehandle);
+ sehandle = sehandle2;
+ }
+ }
+
handle_device_event(&uevent);
handle_firmware_event(&uevent);
}
@@ -896,6 +949,7 @@ void device_init(void)
sehandle = NULL;
if (is_selinux_enabled() > 0) {
sehandle = selinux_android_file_context_handle();
+ selinux_status_open(true);
}
/* is 256K enough? udev uses 16MB! */
diff --git a/init/init.c b/init/init.c
index bd7799e..00f4558 100644
--- a/init/init.c
+++ b/init/init.c
@@ -221,6 +221,9 @@ void service_start(struct service *svc, const char *dynamic_args)
}
rc = security_compute_create(mycon, fcon, string_to_security_class("process"), &scon);
+ if (rc == 0 && !strcmp(scon, mycon)) {
+ ERROR("Warning! Service %s needs a SELinux domain defined; please fix!\n", svc->name);
+ }
freecon(mycon);
freecon(fcon);
if (rc < 0) {
@@ -250,14 +253,12 @@ void service_start(struct service *svc, const char *dynamic_args)
for (ei = svc->envvars; ei; ei = ei->next)
add_environment(ei->name, ei->value);
- setsockcreatecon(scon);
-
for (si = svc->sockets; si; si = si->next) {
int socket_type = (
!strcmp(si->type, "stream") ? SOCK_STREAM :
(!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));
int s = create_socket(si->name, socket_type,
- si->perm, si->uid, si->gid);
+ si->perm, si->uid, si->gid, si->socketcon ?: scon);
if (s >= 0) {
publish_socket(si->name, s);
}
@@ -265,7 +266,6 @@ void service_start(struct service *svc, const char *dynamic_args)
freecon(scon);
scon = NULL;
- setsockcreatecon(NULL);
if (svc->ioprio_class != IoSchedClass_NONE) {
if (android_set_ioprio(getpid(), svc->ioprio_class, svc->ioprio_pri)) {
@@ -623,7 +623,7 @@ static int mix_hwrng_into_linux_rng_action(int nargs, char **args)
total_bytes_written += chunk_size;
}
- INFO("Mixed %d bytes from /dev/hw_random into /dev/urandom",
+ INFO("Mixed %zu bytes from /dev/hw_random into /dev/urandom",
total_bytes_written);
result = 0;
@@ -657,29 +657,28 @@ static int console_init_action(int nargs, char **args)
have_console = 1;
close(fd);
- if( load_565rle_image(INIT_IMAGE_FILE) ) {
- fd = open("/dev/tty0", O_WRONLY);
- if (fd >= 0) {
- const char *msg;
- msg = "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- "\n" // console is 40 cols x 30 lines
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- " A N D R O I D ";
- write(fd, msg, strlen(msg));
- close(fd);
- }
+ fd = open("/dev/tty0", O_WRONLY);
+ if (fd >= 0) {
+ const char *msg;
+ msg = "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n" // console is 40 cols x 30 lines
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ " A N D R O I D ";
+ write(fd, msg, strlen(msg));
+ close(fd);
}
+
return 0;
}
@@ -868,6 +867,7 @@ struct selabel_handle* selinux_android_prop_context_handle(void)
void selinux_init_all_handles(void)
{
sehandle = selinux_android_file_context_handle();
+ selinux_android_set_sehandle(sehandle);
sehandle_prop = selinux_android_prop_context_handle();
}
@@ -1132,7 +1132,7 @@ int main(int argc, char **argv)
continue;
for (i = 0; i < fd_count; i++) {
- if (ufds[i].revents == POLLIN) {
+ if (ufds[i].revents & POLLIN) {
if (ufds[i].fd == get_property_set_fd())
handle_property_set_fd();
else if (ufds[i].fd == get_keychord_fd())
diff --git a/init/init.h b/init/init.h
index aa6a4ab..736b75b 100644
--- a/init/init.h
+++ b/init/init.h
@@ -55,6 +55,7 @@ struct socketinfo {
uid_t uid;
gid_t gid;
int perm;
+ const char *socketcon;
};
struct svcenvinfo {
@@ -132,10 +133,6 @@ void service_restart(struct service *svc);
void service_start(struct service *svc, const char *dynamic_args);
void property_changed(const char *name, const char *value);
-#define INIT_IMAGE_FILE "/initlogo.rle"
-
-int load_565rle_image( char *file_name );
-
extern struct selabel_handle *sehandle;
extern struct selabel_handle *sehandle_prop;
extern int selinux_reload_policy(void);
diff --git a/init/init_parser.c b/init/init_parser.c
index 776c699..f49e698 100644
--- a/init/init_parser.c
+++ b/init/init_parser.c
@@ -60,7 +60,7 @@ static void parse_line_action(struct parse_state *state, int nargs, char **args)
#define KEYWORD(symbol, flags, nargs, func) \
[ K_##symbol ] = { #symbol, func, nargs + 1, flags, },
-struct {
+static struct {
const char *name;
int (*func)(int nargs, char **args);
unsigned char nargs;
@@ -76,7 +76,7 @@ struct {
#define kw_func(kw) (keyword_info[kw].func)
#define kw_nargs(kw) (keyword_info[kw].nargs)
-int lookup_keyword(const char *s)
+static int lookup_keyword(const char *s)
{
switch (*s++) {
case 'c':
@@ -135,6 +135,7 @@ int lookup_keyword(const char *s)
case 'r':
if (!strcmp(s, "estart")) return K_restart;
if (!strcmp(s, "estorecon")) return K_restorecon;
+ if (!strcmp(s, "estorecon_recursive")) return K_restorecon_recursive;
if (!strcmp(s, "mdir")) return K_rmdir;
if (!strcmp(s, "m")) return K_rm;
break;
@@ -169,7 +170,7 @@ int lookup_keyword(const char *s)
return K_UNKNOWN;
}
-void parse_line_no_op(struct parse_state *state, int nargs, char **args)
+static void parse_line_no_op(struct parse_state *state, int nargs, char **args)
{
}
@@ -292,7 +293,7 @@ err:
return -1;
}
-void parse_import(struct parse_state *state, int nargs, char **args)
+static void parse_import(struct parse_state *state, int nargs, char **args)
{
struct listnode *import_list = state->priv;
struct import *import;
@@ -317,7 +318,7 @@ void parse_import(struct parse_state *state, int nargs, char **args)
INFO("found import '%s', adding to import list", import->filename);
}
-void parse_new_section(struct parse_state *state, int kw,
+static void parse_new_section(struct parse_state *state, int kw,
int nargs, char **args)
{
printf("[ %s %s ]\n", args[0],
@@ -552,12 +553,14 @@ void queue_all_property_triggers()
if (length > PROP_NAME_MAX) {
ERROR("property name too long in trigger %s", act->name);
} else {
+ int ret;
memcpy(prop_name, name, length);
prop_name[length] = 0;
/* does the property exist, and match the trigger value? */
- property_get(prop_name, value);
- if (!strcmp(equals + 1, value) ||!strcmp(equals + 1, "*")) {
+ ret = property_get(prop_name, value);
+ if (ret > 0 && (!strcmp(equals + 1, value) ||
+ !strcmp(equals + 1, "*"))) {
action_add_queue_tail(act);
}
}
@@ -771,7 +774,7 @@ static void parse_line_service(struct parse_state *state, int nargs, char **args
svc->envvars = ei;
break;
}
- case K_socket: {/* name type perm [ uid gid ] */
+ case K_socket: {/* name type perm [ uid gid context ] */
struct socketinfo *si;
if (nargs < 4) {
parse_error(state, "socket option requires name, type, perm arguments\n");
@@ -794,6 +797,8 @@ static void parse_line_service(struct parse_state *state, int nargs, char **args
si->uid = decode_uid(args[4]);
if (nargs > 5)
si->gid = decode_uid(args[5]);
+ if (nargs > 6)
+ si->socketcon = args[6];
si->next = svc->sockets;
svc->sockets = si;
break;
diff --git a/init/keywords.h b/init/keywords.h
index 5a44df3..97fe50c 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -17,6 +17,7 @@ int do_mount(int nargs, char **args);
int do_powerctl(int nargs, char **args);
int do_restart(int nargs, char **args);
int do_restorecon(int nargs, char **args);
+int do_restorecon_recursive(int nargs, char **args);
int do_rm(int nargs, char **args);
int do_rmdir(int nargs, char **args);
int do_setcon(int nargs, char **args);
@@ -71,6 +72,7 @@ enum {
KEYWORD(powerctl, COMMAND, 1, do_powerctl)
KEYWORD(restart, COMMAND, 1, do_restart)
KEYWORD(restorecon, COMMAND, 1, do_restorecon)
+ KEYWORD(restorecon_recursive, COMMAND, 1, do_restorecon_recursive)
KEYWORD(rm, COMMAND, 1, do_rm)
KEYWORD(rmdir, COMMAND, 1, do_rmdir)
KEYWORD(seclabel, OPTION, 0, 0)
diff --git a/init/logo.c b/init/logo.c
deleted file mode 100644
index 614224c..0000000
--- a/init/logo.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2008 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 <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <linux/fb.h>
-#include <linux/kd.h>
-
-#include "log.h"
-
-#ifdef ANDROID
-#include <cutils/memory.h>
-#else
-void android_memset16(void *_ptr, unsigned short val, unsigned count)
-{
- unsigned short *ptr = _ptr;
- count >>= 1;
- while(count--)
- *ptr++ = val;
-}
-#endif
-
-struct FB {
- unsigned short *bits;
- unsigned size;
- int fd;
- struct fb_fix_screeninfo fi;
- struct fb_var_screeninfo vi;
-};
-
-#define fb_width(fb) ((fb)->vi.xres)
-#define fb_height(fb) ((fb)->vi.yres)
-#define fb_size(fb) ((fb)->vi.xres * (fb)->vi.yres * 2)
-
-static int fb_open(struct FB *fb)
-{
- fb->fd = open("/dev/graphics/fb0", O_RDWR);
- if (fb->fd < 0)
- return -1;
-
- if (ioctl(fb->fd, FBIOGET_FSCREENINFO, &fb->fi) < 0)
- goto fail;
- if (ioctl(fb->fd, FBIOGET_VSCREENINFO, &fb->vi) < 0)
- goto fail;
-
- fb->bits = mmap(0, fb_size(fb), PROT_READ | PROT_WRITE,
- MAP_SHARED, fb->fd, 0);
- if (fb->bits == MAP_FAILED)
- goto fail;
-
- return 0;
-
-fail:
- close(fb->fd);
- return -1;
-}
-
-static void fb_close(struct FB *fb)
-{
- munmap(fb->bits, fb_size(fb));
- close(fb->fd);
-}
-
-/* there's got to be a more portable way to do this ... */
-static void fb_update(struct FB *fb)
-{
- fb->vi.yoffset = 1;
- ioctl(fb->fd, FBIOPUT_VSCREENINFO, &fb->vi);
- fb->vi.yoffset = 0;
- ioctl(fb->fd, FBIOPUT_VSCREENINFO, &fb->vi);
-}
-
-static int vt_set_mode(int graphics)
-{
- int fd, r;
- fd = open("/dev/tty0", O_RDWR | O_SYNC);
- if (fd < 0)
- return -1;
- r = ioctl(fd, KDSETMODE, (void*) (graphics ? KD_GRAPHICS : KD_TEXT));
- close(fd);
- return r;
-}
-
-/* 565RLE image format: [count(2 bytes), rle(2 bytes)] */
-
-int load_565rle_image(char *fn)
-{
- struct FB fb;
- struct stat s;
- unsigned short *data, *bits, *ptr;
- unsigned count, max;
- int fd;
-
- if (vt_set_mode(1))
- return -1;
-
- fd = open(fn, O_RDONLY);
- if (fd < 0) {
- ERROR("cannot open '%s'\n", fn);
- goto fail_restore_text;
- }
-
- if (fstat(fd, &s) < 0) {
- goto fail_close_file;
- }
-
- data = mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0);
- if (data == MAP_FAILED)
- goto fail_close_file;
-
- if (fb_open(&fb))
- goto fail_unmap_data;
-
- max = fb_width(&fb) * fb_height(&fb);
- ptr = data;
- count = s.st_size;
- bits = fb.bits;
- while (count > 3) {
- unsigned n = ptr[0];
- if (n > max)
- break;
- android_memset16(bits, ptr[1], n << 1);
- bits += n;
- max -= n;
- ptr += 2;
- count -= 4;
- }
-
- munmap(data, s.st_size);
- fb_update(&fb);
- fb_close(&fb);
- close(fd);
- unlink(fn);
- return 0;
-
-fail_unmap_data:
- munmap(data, s.st_size);
-fail_close_file:
- close(fd);
-fail_restore_text:
- vt_set_mode(0);
- return -1;
-}
-
diff --git a/init/parser.h b/init/parser.h
index 0a5802a..a58272a 100644
--- a/init/parser.h
+++ b/init/parser.h
@@ -33,7 +33,6 @@ struct parse_state
void *priv;
};
-int lookup_keyword(const char *s);
void DUMP(void);
int next_token(struct parse_state *state);
void parse_error(struct parse_state *state, const char *fmt, ...);
diff --git a/init/property_service.c b/init/property_service.c
index 9ac2781..ac63377 100644
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -81,6 +81,7 @@ struct {
{ "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 },
@@ -92,6 +93,7 @@ struct {
{ "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 }
@@ -166,7 +168,7 @@ static int check_mac_perms(const char *name, char *sctx)
if (selabel_lookup(sehandle_prop, &tctx, name, 1) != 0)
goto err;
- if (selinux_check_access(sctx, tctx, class, perm, name) == 0)
+ if (selinux_check_access(sctx, tctx, class, perm, (void*) name) == 0)
result = 1;
freecon(tctx);
@@ -380,7 +382,7 @@ void handle_property_set_fd()
r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), 0));
if(r != sizeof(prop_msg)) {
- ERROR("sys_prop: mis-match msg size received: %d expected: %d errno: %d\n",
+ ERROR("sys_prop: mis-match msg size received: %d expected: %zu errno: %d\n",
r, sizeof(prop_msg), errno);
close(s);
return;
@@ -437,10 +439,13 @@ void get_property_workspace(int *fd, int *sz)
*sz = pa_workspace.size;
}
-static void load_properties(char *data)
+static void load_properties(char *data, char *prefix)
{
char *key, *value, *eol, *sol, *tmp;
+ size_t plen;
+ if (prefix)
+ plen = strlen(prefix);
sol = data;
while((eol = strchr(sol, '\n'))) {
key = sol;
@@ -456,6 +461,9 @@ static void load_properties(char *data)
tmp = value - 2;
while((tmp > key) && isspace(*tmp)) *tmp-- = 0;
+ if (prefix && strncmp(key, prefix, plen))
+ continue;
+
while(isspace(*value)) value++;
tmp = eol - 2;
while((tmp > value) && isspace(*tmp)) *tmp-- = 0;
@@ -464,7 +472,7 @@ static void load_properties(char *data)
}
}
-static void load_properties_from_file(const char *fn)
+static void load_properties_from_file(const char *fn, char *prefix)
{
char *data;
unsigned sz;
@@ -472,7 +480,7 @@ static void load_properties_from_file(const char *fn)
data = read_file(fn, &sz);
if(data != 0) {
- load_properties(data);
+ load_properties(data, prefix);
free(data);
}
}
@@ -514,7 +522,7 @@ static void load_persistent_properties()
|| (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",
+ 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);
close(fd);
continue;
@@ -545,7 +553,7 @@ void property_init(void)
void property_load_boot_defaults(void)
{
- load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT);
+ load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT, NULL);
}
int properties_inited(void)
@@ -560,7 +568,7 @@ static void load_override_properties() {
ret = property_get("ro.debuggable", debuggable);
if (ret && (strcmp(debuggable, "1") == 0)) {
- load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE);
+ load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE, NULL);
}
#endif /* ALLOW_LOCAL_PROP_OVERRIDE */
}
@@ -582,13 +590,14 @@ void start_property_service(void)
{
int fd;
- load_properties_from_file(PROP_PATH_SYSTEM_BUILD);
- load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);
+ 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_override_properties();
/* Read persistent properties after all default values have been loaded. */
load_persistent_properties();
- fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0);
+ fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0, NULL);
if(fd < 0) return;
fcntl(fd, F_SETFD, FD_CLOEXEC);
fcntl(fd, F_SETFL, O_NONBLOCK);
diff --git a/init/readme.txt b/init/readme.txt
index 7a5997d..42a09cb 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -70,10 +70,13 @@ disabled
setenv <name> <value>
Set the environment variable <name> to <value> in the launched process.
-socket <name> <type> <perm> [ <user> [ <group> ] ]
+socket <name> <type> <perm> [ <user> [ <group> [ <context> ] ] ]
Create a unix domain socket named /dev/socket/<name> and pass
its fd to the launched process. <type> must be "dgram", "stream" or "seqpacket".
User and group default to 0.
+ Context is the SELinux security context for the socket.
+ It defaults to the service security context, as specified by seclabel or
+ computed based on the service executable file security context.
user <username>
Change to username before exec'ing this service.
@@ -189,12 +192,18 @@ mount <type> <device> <dir> [ <mountoption> ]*
device by name.
<mountoption>s include "ro", "rw", "remount", "noatime", ...
-restorecon <path>
+restorecon <path> [ <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.
+restorecon_recursive <path> [ <path> ]*
+ Recursively restore the directory tree named by <path> to the
+ security contexts specified in the file_contexts configuration.
+ Do NOT use this with paths leading to shell-writable or app-writable
+ directories, e.g. /data/local/tmp, /data/data or any prefix thereof.
+
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
diff --git a/init/signal_handler.c b/init/signal_handler.c
index d31ad63..7e8e1a7 100644
--- a/init/signal_handler.c
+++ b/init/signal_handler.c
@@ -57,7 +57,15 @@ static int wait_for_one_process(int block)
svc = service_find_by_pid(pid);
if (!svc) {
- ERROR("untracked pid %d exited\n", pid);
+ if (WIFEXITED(status)) {
+ ERROR("untracked pid %d exited with status %d\n", pid, WEXITSTATUS(status));
+ } else if (WIFSIGNALED(status)) {
+ ERROR("untracked pid %d killed by signal %d\n", pid, WTERMSIG(status));
+ } else if (WIFSTOPPED(status)) {
+ ERROR("untracked pid %d stopped by signal %d\n", pid, WSTOPSIG(status));
+ } else {
+ ERROR("untracked pid %d state changed\n", pid);
+ }
return 0;
}
diff --git a/init/ueventd.c b/init/ueventd.c
index a41c31e..3d01836 100644
--- a/init/ueventd.c
+++ b/init/ueventd.c
@@ -94,7 +94,7 @@ int ueventd_main(int argc, char **argv)
nr = poll(&ufd, 1, -1);
if (nr <= 0)
continue;
- if (ufd.revents == POLLIN)
+ if (ufd.revents & POLLIN)
handle_device_fd();
}
}
diff --git a/init/ueventd.h b/init/ueventd.h
index 9066e47..0a454c5 100644
--- a/init/ueventd.h
+++ b/init/ueventd.h
@@ -17,6 +17,21 @@
#ifndef _INIT_UEVENTD_H_
#define _INIT_UEVENTD_H_
+#include <cutils/list.h>
+#include <sys/types.h>
+
+struct ueventd_subsystem {
+ struct listnode slist;
+
+ const char *name;
+ enum {
+ DEVNAME_UNKNOWN = 0,
+ DEVNAME_UEVENT_DEVNAME,
+ DEVNAME_UEVENT_DEVPATH,
+ } devname_src;
+ const char *dirname;
+};
+
int ueventd_main(int argc, char **argv);
#endif
diff --git a/init/ueventd_keywords.h b/init/ueventd_keywords.h
new file mode 100644
index 0000000..88e8f01
--- /dev/null
+++ b/init/ueventd_keywords.h
@@ -0,0 +1,15 @@
+#ifndef KEYWORD
+#define __MAKE_KEYWORD_ENUM__
+#define KEYWORD(symbol, flags, nargs) K_##symbol,
+enum {
+ K_UNKNOWN,
+#endif
+ KEYWORD(subsystem, SECTION, 1)
+ KEYWORD(devname, OPTION, 1)
+ KEYWORD(dirname, OPTION, 1)
+#ifdef __MAKE_KEYWORD_ENUM__
+ KEYWORD_COUNT,
+};
+#undef __MAKE_KEYWORD_ENUM__
+#undef KEYWORD
+#endif
diff --git a/init/ueventd_parser.c b/init/ueventd_parser.c
index 3e60df5..e447006 100644
--- a/init/ueventd_parser.c
+++ b/init/ueventd_parser.c
@@ -14,18 +14,189 @@
* limitations under the License.
*/
+#include <ctype.h>
+#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <stdarg.h>
+#include <stdlib.h>
#include <string.h>
+#include "ueventd.h"
#include "ueventd_parser.h"
#include "parser.h"
#include "log.h"
#include "util.h"
+static list_declare(subsystem_list);
+
static void parse_line_device(struct parse_state *state, int nargs, char **args);
+#define SECTION 0x01
+#define OPTION 0x02
+
+#include "ueventd_keywords.h"
+
+#define KEYWORD(symbol, flags, nargs) \
+ [ K_##symbol ] = { #symbol, nargs + 1, flags, },
+
+static struct {
+ const char *name;
+ unsigned char nargs;
+ unsigned char flags;
+} keyword_info[KEYWORD_COUNT] = {
+ [ K_UNKNOWN ] = { "unknown", 0, 0 },
+#include "ueventd_keywords.h"
+};
+#undef KEYWORD
+
+#define kw_is(kw, type) (keyword_info[kw].flags & (type))
+#define kw_nargs(kw) (keyword_info[kw].nargs)
+
+static int lookup_keyword(const char *s)
+{
+ switch (*s++) {
+ case 'd':
+ if (!strcmp(s, "evname")) return K_devname;
+ if (!strcmp(s, "irname")) return K_dirname;
+ break;
+ case 's':
+ if (!strcmp(s, "ubsystem")) return K_subsystem;
+ break;
+ }
+ return K_UNKNOWN;
+}
+
+static void parse_line_no_op(struct parse_state *state __attribute__((unused)),
+ int nargs __attribute__((unused)), char **args __attribute__((unused)))
+{
+}
+
+static int valid_name(const char *name)
+{
+ while (*name) {
+ if (!isalnum(*name) && (*name != '_') && (*name != '-')) {
+ return 0;
+ }
+ name++;
+ }
+ return 1;
+}
+
+struct ueventd_subsystem *ueventd_subsystem_find_by_name(const char *name)
+{
+ struct listnode *node;
+ struct ueventd_subsystem *s;
+
+ list_for_each(node, &subsystem_list) {
+ s = node_to_item(node, struct ueventd_subsystem, slist);
+ if (!strcmp(s->name, name)) {
+ return s;
+ }
+ }
+ return 0;
+}
+
+static void *parse_subsystem(struct parse_state *state,
+ int nargs __attribute__((unused)), char **args)
+{
+ struct ueventd_subsystem *s;
+
+ if (!valid_name(args[1])) {
+ parse_error(state, "invalid subsystem name '%s'\n", args[1]);
+ return 0;
+ }
+
+ s = ueventd_subsystem_find_by_name(args[1]);
+ if (s) {
+ parse_error(state, "ignored duplicate definition of subsystem '%s'\n",
+ args[1]);
+ return 0;
+ }
+
+ s = calloc(1, sizeof(*s));
+ if (!s) {
+ parse_error(state, "out of memory\n");
+ return 0;
+ }
+ s->name = args[1];
+ s->dirname = "/dev";
+ list_add_tail(&subsystem_list, &s->slist);
+ return s;
+}
+
+static void parse_line_subsystem(struct parse_state *state, int nargs,
+ char **args)
+{
+ struct ueventd_subsystem *s = state->context;
+ int kw;
+
+ if (nargs == 0) {
+ return;
+ }
+
+ kw = lookup_keyword(args[0]);
+ switch (kw) {
+ case K_devname:
+ if (!strcmp(args[1], "uevent_devname"))
+ s->devname_src = DEVNAME_UEVENT_DEVNAME;
+ else if (!strcmp(args[1], "uevent_devpath"))
+ s->devname_src = DEVNAME_UEVENT_DEVPATH;
+ else
+ parse_error(state, "invalid devname '%s'\n", args[1]);
+ break;
+
+ case K_dirname:
+ if (args[1][0] == '/')
+ s->dirname = args[1];
+ else
+ parse_error(state, "dirname '%s' does not start with '/'\n",
+ args[1]);
+ break;
+
+ default:
+ parse_error(state, "invalid option '%s'\n", args[0]);
+ }
+}
+
+static void parse_new_section(struct parse_state *state, int kw,
+ int nargs, char **args)
+{
+ printf("[ %s %s ]\n", args[0],
+ nargs > 1 ? args[1] : "");
+
+ switch(kw) {
+ case K_subsystem:
+ state->context = parse_subsystem(state, nargs, args);
+ if (state->context) {
+ state->parse_line = parse_line_subsystem;
+ return;
+ }
+ break;
+ }
+ state->parse_line = parse_line_no_op;
+}
+
+static void parse_line(struct parse_state *state, char **args, int nargs)
+{
+ int kw = lookup_keyword(args[0]);
+ int kw_nargs = kw_nargs(kw);
+
+ if (nargs < kw_nargs) {
+ parse_error(state, "%s requires %d %s\n", args[0], kw_nargs - 1,
+ kw_nargs > 2 ? "arguments" : "argument");
+ return;
+ }
+
+ if (kw_is(kw, SECTION)) {
+ parse_new_section(state, kw, nargs, args);
+ } else if (kw_is(kw, OPTION)) {
+ state->parse_line(state, nargs, args);
+ } else {
+ parse_line_device(state, nargs, args);
+ }
+}
+
static void parse_config(const char *fn, char *s)
{
struct parse_state state;
@@ -36,18 +207,19 @@ static void parse_config(const char *fn, char *s)
state.line = 1;
state.ptr = s;
state.nexttoken = 0;
- state.parse_line = parse_line_device;
+ state.parse_line = parse_line_no_op;
for (;;) {
int token = next_token(&state);
switch (token) {
case T_EOF:
- state.parse_line(&state, 0, 0);
+ parse_line(&state, args, nargs);
return;
case T_NEWLINE:
if (nargs) {
- state.parse_line(&state, nargs, args);
+ parse_line(&state, args, nargs);
nargs = 0;
}
+ state.line++;
break;
case T_TEXT:
if (nargs < UEVENTD_PARSER_MAXARGS) {
@@ -69,7 +241,8 @@ int ueventd_parse_config_file(const char *fn)
return 0;
}
-static void parse_line_device(struct parse_state* state, int nargs, char **args)
+static void parse_line_device(struct parse_state *state __attribute__((unused)),
+ int nargs, char **args)
{
set_device_permission(nargs, args);
}
diff --git a/init/ueventd_parser.h b/init/ueventd_parser.h
index 3684285..907cc49 100644
--- a/init/ueventd_parser.h
+++ b/init/ueventd_parser.h
@@ -17,9 +17,12 @@
#ifndef _INIT_UEVENTD_PARSER_H_
#define _INIT_UEVENTD_PARSER_H_
+#include "ueventd.h"
+
#define UEVENTD_PARSER_MAXARGS 5
int ueventd_parse_config_file(const char *fn);
void set_device_permission(int nargs, char **args);
+struct ueventd_subsystem *ueventd_subsystem_find_by_name(const char *name);
#endif
diff --git a/init/util.c b/init/util.c
index 1908b3a..e772342 100644
--- a/init/util.c
+++ b/init/util.c
@@ -25,6 +25,7 @@
#include <ftw.h>
#include <selinux/label.h>
+#include <selinux/android.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -84,11 +85,15 @@ unsigned int decode_uid(const char *s)
* daemon. We communicate the file descriptor's value via the environment
* variable ANDROID_SOCKET_ENV_PREFIX<name> ("ANDROID_SOCKET_foo").
*/
-int create_socket(const char *name, int type, mode_t perm, uid_t uid, gid_t gid)
+int create_socket(const char *name, int type, mode_t perm, uid_t uid,
+ gid_t gid, const char *socketcon)
{
struct sockaddr_un addr;
int fd, ret;
- char *secon;
+ char *filecon;
+
+ if (socketcon)
+ setsockcreatecon(socketcon);
fd = socket(PF_UNIX, type, 0);
if (fd < 0) {
@@ -96,6 +101,9 @@ int create_socket(const char *name, int type, mode_t perm, uid_t uid, gid_t gid)
return -1;
}
+ if (socketcon)
+ setsockcreatecon(NULL);
+
memset(&addr, 0 , sizeof(addr));
addr.sun_family = AF_UNIX;
snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s",
@@ -107,11 +115,11 @@ int create_socket(const char *name, int type, mode_t perm, uid_t uid, gid_t gid)
goto out_close;
}
- secon = NULL;
+ filecon = NULL;
if (sehandle) {
- ret = selabel_lookup(sehandle, &secon, addr.sun_path, S_IFSOCK);
+ ret = selabel_lookup(sehandle, &filecon, addr.sun_path, S_IFSOCK);
if (ret == 0)
- setfscreatecon(secon);
+ setfscreatecon(filecon);
}
ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
@@ -121,7 +129,7 @@ int create_socket(const char *name, int type, mode_t perm, uid_t uid, gid_t gid)
}
setfscreatecon(NULL);
- freecon(secon);
+ freecon(filecon);
chown(addr.sun_path, uid, gid);
chmod(addr.sun_path, perm);
@@ -398,7 +406,9 @@ void open_devnull_stdio(void)
void get_hardware_name(char *hardware, unsigned int *revision)
{
- char data[1024];
+ const char *cpuinfo = "/proc/cpuinfo";
+ char *data = NULL;
+ size_t len = 0, limit = 1024;
int fd, n;
char *x, *hw, *rev;
@@ -406,14 +416,32 @@ void get_hardware_name(char *hardware, unsigned int *revision)
if (hardware[0])
return;
- fd = open("/proc/cpuinfo", O_RDONLY);
+ fd = open(cpuinfo, O_RDONLY);
if (fd < 0) return;
- n = read(fd, data, 1023);
- close(fd);
- if (n < 0) return;
+ for (;;) {
+ x = realloc(data, limit);
+ if (!x) {
+ ERROR("Failed to allocate memory to read %s\n", cpuinfo);
+ goto done;
+ }
+ data = x;
+
+ n = read(fd, data + len, limit - len);
+ if (n < 0) {
+ ERROR("Failed reading %s: %s (%d)\n", cpuinfo, strerror(errno), errno);
+ goto done;
+ }
+ len += n;
- data[n] = 0;
+ if (len < limit)
+ break;
+
+ /* We filled the buffer, so increase size and loop to read more */
+ limit *= 2;
+ }
+
+ data[len] = 0;
hw = strstr(data, "\nHardware");
rev = strstr(data, "\nRevision");
@@ -438,18 +466,22 @@ void get_hardware_name(char *hardware, unsigned int *revision)
*revision = strtoul(x + 2, 0, 16);
}
}
+
+done:
+ close(fd);
+ free(data);
}
void import_kernel_cmdline(int in_qemu,
void (*import_kernel_nv)(char *name, int in_qemu))
{
- char cmdline[1024];
+ char cmdline[2048];
char *ptr;
int fd;
fd = open("/proc/cmdline", O_RDONLY);
if (fd >= 0) {
- int n = read(fd, cmdline, 1023);
+ int n = read(fd, cmdline, sizeof(cmdline) - 1);
if (n < 0) n = 0;
/* get rid of trailing newline, it happens */
@@ -493,37 +525,12 @@ int make_dir(const char *path, mode_t mode)
return rc;
}
-int restorecon(const char *pathname)
+int restorecon(const char* pathname)
{
- char *secontext = NULL;
- struct stat sb;
- int i;
-
- if (is_selinux_enabled() <= 0 || !sehandle)
- return 0;
-
- if (lstat(pathname, &sb) < 0)
- return -errno;
- if (selabel_lookup(sehandle, &secontext, pathname, sb.st_mode) < 0)
- return -errno;
- if (lsetfilecon(pathname, secontext) < 0) {
- freecon(secontext);
- return -errno;
- }
- freecon(secontext);
- return 0;
-}
-
-static int nftw_restorecon(const char* filename, const struct stat* statptr,
- int fileflags, struct FTW* pftw)
-{
- restorecon(filename);
- return 0;
+ return selinux_android_restorecon(pathname);
}
int restorecon_recursive(const char* pathname)
{
- int fd_limit = 20;
- int flags = FTW_DEPTH | FTW_MOUNT | FTW_PHYS;
- return nftw(pathname, nftw_restorecon, fd_limit, flags);
+ return selinux_android_restorecon_recursive(pathname);
}
diff --git a/init/util.h b/init/util.h
index 6bca4e6..04b8129 100644
--- a/init/util.h
+++ b/init/util.h
@@ -26,7 +26,7 @@ static const char *coldboot_done = "/dev/.coldboot_done";
int mtd_name_to_number(const char *name);
int create_socket(const char *name, int type, mode_t perm,
- uid_t uid, gid_t gid);
+ uid_t uid, gid_t gid, const char *socketcon);
void *read_file(const char *fn, unsigned *_sz);
time_t gettime(void);
unsigned int decode_uid(const char *s);