summaryrefslogtreecommitdiffstats
path: root/init/builtins.cpp
diff options
context:
space:
mode:
authorTom Cherry <tomcherry@google.com>2017-09-12 15:58:47 -0700
committerTom Cherry <tomcherry@google.com>2017-09-29 13:06:26 -0700
commitcb0f9bbc855097e0c8248643015b837255fd569a (patch)
treecc42fe9dc7a6011c2b9e9ee0fd26f9f2454e1746 /init/builtins.cpp
parent9c568d0fc0e290529180e3fc0452f0ac489e5053 (diff)
downloadsystem_core-cb0f9bbc855097e0c8248643015b837255fd569a.tar.gz
system_core-cb0f9bbc855097e0c8248643015b837255fd569a.tar.bz2
system_core-cb0f9bbc855097e0c8248643015b837255fd569a.zip
init: run vendor commands in a separate SELinux context
One of the major aspects of treble is the compartmentalization of system and vendor components, however init leaves a huge gap here, as vendor init scripts run in the same context as system init scripts and thus can access and modify the same properties, files, etc as the system can. This change is meant to close that gap. It forks a separate 'subcontext' init that runs in a different SELinux context with permissions that match what vendors should have access to. Commands get sent over a socket to this 'subcontext' init that then runs them in this SELinux context and returns the result. Note that not all commands run in the subcontext; some commands such as those dealing with services only make sense in the context of the main init process. Bug: 62875318 Test: init unit tests, boot bullhead, boot sailfish Change-Id: Idf4a4ebf98842d27b8627f901f961ab9eb412aee
Diffstat (limited to 'init/builtins.cpp')
-rw-r--r--init/builtins.cpp197
1 files changed, 100 insertions, 97 deletions
diff --git a/init/builtins.cpp b/init/builtins.cpp
index be245732b..60c0007c0 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -66,6 +66,7 @@
#include "reboot.h"
#include "rlimit_parser.h"
#include "service.h"
+#include "subcontext.h"
#include "util.h"
using namespace std::literals::string_literals;
@@ -95,36 +96,36 @@ static void ForEachServiceInClass(const std::string& classname, F function) {
}
}
-static Result<Success> do_class_start(const std::vector<std::string>& args) {
+static Result<Success> do_class_start(const BuiltinArguments& args) {
// Starting a class does not start services which are explicitly disabled.
// They must be started individually.
ForEachServiceInClass(args[1], &Service::StartIfNotDisabled);
return Success();
}
-static Result<Success> do_class_stop(const std::vector<std::string>& args) {
+static Result<Success> do_class_stop(const BuiltinArguments& args) {
ForEachServiceInClass(args[1], &Service::Stop);
return Success();
}
-static Result<Success> do_class_reset(const std::vector<std::string>& args) {
+static Result<Success> do_class_reset(const BuiltinArguments& args) {
ForEachServiceInClass(args[1], &Service::Reset);
return Success();
}
-static Result<Success> do_class_restart(const std::vector<std::string>& args) {
+static Result<Success> do_class_restart(const BuiltinArguments& args) {
ForEachServiceInClass(args[1], &Service::Restart);
return Success();
}
-static Result<Success> do_domainname(const std::vector<std::string>& args) {
+static Result<Success> do_domainname(const BuiltinArguments& args) {
if (auto result = WriteFile("/proc/sys/kernel/domainname", args[1]); !result) {
return Error() << "Unable to write to /proc/sys/kernel/domainname: " << result.error();
}
return Success();
}
-static Result<Success> do_enable(const std::vector<std::string>& args) {
+static Result<Success> do_enable(const BuiltinArguments& args) {
Service* svc = ServiceList::GetInstance().FindService(args[1]);
if (!svc) return Error() << "Could not find service";
@@ -135,8 +136,8 @@ static Result<Success> do_enable(const std::vector<std::string>& args) {
return Success();
}
-static Result<Success> do_exec(const std::vector<std::string>& args) {
- auto service = Service::MakeTemporaryOneshotService(args);
+static Result<Success> do_exec(const BuiltinArguments& args) {
+ auto service = Service::MakeTemporaryOneshotService(args.args);
if (!service) {
return Error() << "Could not create exec service";
}
@@ -148,8 +149,8 @@ static Result<Success> do_exec(const std::vector<std::string>& args) {
return Success();
}
-static Result<Success> do_exec_background(const std::vector<std::string>& args) {
- auto service = Service::MakeTemporaryOneshotService(args);
+static Result<Success> do_exec_background(const BuiltinArguments& args) {
+ auto service = Service::MakeTemporaryOneshotService(args.args);
if (!service) {
return Error() << "Could not create exec background service";
}
@@ -161,7 +162,7 @@ static Result<Success> do_exec_background(const std::vector<std::string>& args)
return Success();
}
-static Result<Success> do_exec_start(const std::vector<std::string>& args) {
+static Result<Success> do_exec_start(const BuiltinArguments& args) {
Service* service = ServiceList::GetInstance().FindService(args[1]);
if (!service) {
return Error() << "Service not found";
@@ -174,21 +175,21 @@ static Result<Success> do_exec_start(const std::vector<std::string>& args) {
return Success();
}
-static Result<Success> do_export(const std::vector<std::string>& args) {
+static Result<Success> do_export(const BuiltinArguments& args) {
if (setenv(args[1].c_str(), args[2].c_str(), 1) == -1) {
return ErrnoError() << "setenv() failed";
}
return Success();
}
-static Result<Success> do_hostname(const std::vector<std::string>& args) {
+static Result<Success> do_hostname(const BuiltinArguments& args) {
if (auto result = WriteFile("/proc/sys/kernel/hostname", args[1]); !result) {
return Error() << "Unable to write to /proc/sys/kernel/hostname: " << result.error();
}
return Success();
}
-static Result<Success> do_ifup(const std::vector<std::string>& args) {
+static Result<Success> do_ifup(const BuiltinArguments& args) {
struct ifreq ifr;
strlcpy(ifr.ifr_name, args[1].c_str(), IFNAMSIZ);
@@ -209,7 +210,7 @@ static Result<Success> do_ifup(const std::vector<std::string>& args) {
return Success();
}
-static Result<Success> do_insmod(const std::vector<std::string>& args) {
+static Result<Success> do_insmod(const BuiltinArguments& args) {
int flags = 0;
auto it = args.begin() + 1;
@@ -231,7 +232,7 @@ static Result<Success> do_insmod(const std::vector<std::string>& args) {
}
// mkdir <path> [mode] [owner] [group]
-static Result<Success> do_mkdir(const std::vector<std::string>& args) {
+static Result<Success> do_mkdir(const BuiltinArguments& args) {
mode_t mode = 0755;
if (args.size() >= 3) {
mode = std::strtoul(args[2].c_str(), 0, 8);
@@ -287,7 +288,7 @@ static Result<Success> do_mkdir(const std::vector<std::string>& args) {
}
/* umount <path> */
-static Result<Success> do_umount(const std::vector<std::string>& args) {
+static Result<Success> do_umount(const BuiltinArguments& args) {
if (umount(args[1].c_str()) < 0) {
return ErrnoError() << "umount() failed";
}
@@ -319,7 +320,7 @@ static struct {
#define DATA_MNT_POINT "/data"
/* mount <type> <device> <path> <flags ...> <options> */
-static Result<Success> do_mount(const std::vector<std::string>& args) {
+static Result<Success> do_mount(const BuiltinArguments& args) {
const char* options = nullptr;
unsigned flags = 0;
bool wait = false;
@@ -511,7 +512,7 @@ static Result<Success> queue_fs_event(int code) {
* This function might request a reboot, in which case it will
* not return.
*/
-static Result<Success> do_mount_all(const std::vector<std::string>& args) {
+static Result<Success> do_mount_all(const BuiltinArguments& args) {
std::size_t na = 0;
bool import_rc = true;
bool queue_event = true;
@@ -544,7 +545,7 @@ static Result<Success> do_mount_all(const std::vector<std::string>& args) {
if (import_rc) {
/* Paths of .rc files are specified at the 2nd argument and beyond */
- import_late(args, 2, path_arg_end);
+ import_late(args.args, 2, path_arg_end);
}
if (queue_event) {
@@ -559,7 +560,7 @@ static Result<Success> do_mount_all(const std::vector<std::string>& args) {
return Success();
}
-static Result<Success> do_swapon_all(const std::vector<std::string>& args) {
+static Result<Success> do_swapon_all(const BuiltinArguments& args) {
struct fstab *fstab;
int ret;
@@ -571,13 +572,13 @@ static Result<Success> do_swapon_all(const std::vector<std::string>& args) {
return Success();
}
-static Result<Success> do_setprop(const std::vector<std::string>& args) {
+static Result<Success> do_setprop(const BuiltinArguments& args) {
property_set(args[1], args[2]);
return Success();
}
-static Result<Success> do_setrlimit(const std::vector<std::string>& args) {
- auto rlimit = ParseRlimit(args);
+static Result<Success> do_setrlimit(const BuiltinArguments& args) {
+ auto rlimit = ParseRlimit(args.args);
if (!rlimit) return rlimit.error();
if (setrlimit(rlimit->first, &rlimit->second) == -1) {
@@ -586,7 +587,7 @@ static Result<Success> do_setrlimit(const std::vector<std::string>& args) {
return Success();
}
-static Result<Success> do_start(const std::vector<std::string>& args) {
+static Result<Success> do_start(const BuiltinArguments& args) {
Service* svc = ServiceList::GetInstance().FindService(args[1]);
if (!svc) return Error() << "service " << args[1] << " not found";
if (auto result = svc->Start(); !result) {
@@ -595,26 +596,26 @@ static Result<Success> do_start(const std::vector<std::string>& args) {
return Success();
}
-static Result<Success> do_stop(const std::vector<std::string>& args) {
+static Result<Success> do_stop(const BuiltinArguments& args) {
Service* svc = ServiceList::GetInstance().FindService(args[1]);
if (!svc) return Error() << "service " << args[1] << " not found";
svc->Stop();
return Success();
}
-static Result<Success> do_restart(const std::vector<std::string>& args) {
+static Result<Success> do_restart(const BuiltinArguments& args) {
Service* svc = ServiceList::GetInstance().FindService(args[1]);
if (!svc) return Error() << "service " << args[1] << " not found";
svc->Restart();
return Success();
}
-static Result<Success> do_trigger(const std::vector<std::string>& args) {
+static Result<Success> do_trigger(const BuiltinArguments& args) {
ActionManager::GetInstance().QueueEventTrigger(args[1]);
return Success();
}
-static Result<Success> do_symlink(const std::vector<std::string>& args) {
+static Result<Success> do_symlink(const BuiltinArguments& args) {
if (symlink(args[1].c_str(), args[2].c_str()) < 0) {
// The symlink builtin is often used to create symlinks for older devices to be backwards
// compatible with new paths, therefore we skip reporting this error.
@@ -626,21 +627,21 @@ static Result<Success> do_symlink(const std::vector<std::string>& args) {
return Success();
}
-static Result<Success> do_rm(const std::vector<std::string>& args) {
+static Result<Success> do_rm(const BuiltinArguments& args) {
if (unlink(args[1].c_str()) < 0) {
return ErrnoError() << "unlink() failed";
}
return Success();
}
-static Result<Success> do_rmdir(const std::vector<std::string>& args) {
+static Result<Success> do_rmdir(const BuiltinArguments& args) {
if (rmdir(args[1].c_str()) < 0) {
return ErrnoError() << "rmdir() failed";
}
return Success();
}
-static Result<Success> do_sysclktz(const std::vector<std::string>& args) {
+static Result<Success> do_sysclktz(const BuiltinArguments& args) {
struct timezone tz = {};
if (!android::base::ParseInt(args[1], &tz.tz_minuteswest)) {
return Error() << "Unable to parse mins_west_of_gmt";
@@ -652,7 +653,7 @@ static Result<Success> do_sysclktz(const std::vector<std::string>& args) {
return Success();
}
-static Result<Success> do_verity_load_state(const std::vector<std::string>& args) {
+static Result<Success> do_verity_load_state(const BuiltinArguments& args) {
int mode = -1;
bool loaded = fs_mgr_load_verity_state(&mode);
if (loaded && mode != VERITY_MODE_DEFAULT) {
@@ -668,14 +669,14 @@ static void verity_update_property(fstab_rec *fstab, const char *mount_point,
property_set("partition."s + mount_point + ".verified", std::to_string(mode));
}
-static Result<Success> do_verity_update_state(const std::vector<std::string>& args) {
+static Result<Success> do_verity_update_state(const BuiltinArguments& args) {
if (!fs_mgr_update_verity_state(verity_update_property)) {
return Error() << "fs_mgr_update_verity_state() failed";
}
return Success();
}
-static Result<Success> do_write(const std::vector<std::string>& args) {
+static Result<Success> do_write(const BuiltinArguments& args) {
if (auto result = WriteFile(args[1], args[2]); !result) {
return Error() << "Unable to write to file '" << args[1] << "': " << result.error();
}
@@ -706,7 +707,7 @@ static Result<Success> readahead_file(const std::string& filename, bool fully) {
return Success();
}
-static Result<Success> do_readahead(const std::vector<std::string>& args) {
+static Result<Success> do_readahead(const BuiltinArguments& args) {
struct stat sb;
if (stat(args[1].c_str(), &sb)) {
@@ -765,7 +766,7 @@ static Result<Success> do_readahead(const std::vector<std::string>& args) {
return Success();
}
-static Result<Success> do_copy(const std::vector<std::string>& args) {
+static Result<Success> do_copy(const BuiltinArguments& args) {
auto file_contents = ReadFile(args[1]);
if (!file_contents) {
return Error() << "Could not read input file '" << args[1] << "': " << file_contents.error();
@@ -777,7 +778,7 @@ static Result<Success> do_copy(const std::vector<std::string>& args) {
return Success();
}
-static Result<Success> do_chown(const std::vector<std::string>& args) {
+static Result<Success> do_chown(const BuiltinArguments& args) {
auto uid = DecodeUid(args[1]);
if (!uid) {
return Error() << "Unable to decode UID for '" << args[1] << "': " << uid.error();
@@ -814,7 +815,7 @@ static mode_t get_mode(const char *s) {
return mode;
}
-static Result<Success> do_chmod(const std::vector<std::string>& args) {
+static Result<Success> do_chmod(const BuiltinArguments& args) {
mode_t mode = get_mode(args[1].c_str());
if (fchmodat(AT_FDCWD, args[2].c_str(), mode, AT_SYMLINK_NOFOLLOW) < 0) {
return ErrnoError() << "fchmodat() failed";
@@ -822,7 +823,7 @@ static Result<Success> do_chmod(const std::vector<std::string>& args) {
return Success();
}
-static Result<Success> do_restorecon(const std::vector<std::string>& args) {
+static Result<Success> do_restorecon(const BuiltinArguments& args) {
int ret = 0;
struct flag_type {const char* name; int value;};
@@ -864,13 +865,13 @@ static Result<Success> do_restorecon(const std::vector<std::string>& args) {
return Success();
}
-static Result<Success> do_restorecon_recursive(const std::vector<std::string>& args) {
- std::vector<std::string> non_const_args(args);
+static Result<Success> do_restorecon_recursive(const BuiltinArguments& args) {
+ std::vector<std::string> non_const_args(args.args);
non_const_args.insert(std::next(non_const_args.begin()), "--recursive");
- return do_restorecon(non_const_args);
+ return do_restorecon({std::move(non_const_args), args.context});
}
-static Result<Success> do_loglevel(const std::vector<std::string>& args) {
+static Result<Success> do_loglevel(const BuiltinArguments& args) {
// TODO: support names instead/as well?
int log_level = -1;
android::base::ParseInt(args[1], &log_level);
@@ -891,17 +892,17 @@ static Result<Success> do_loglevel(const std::vector<std::string>& args) {
return Success();
}
-static Result<Success> do_load_persist_props(const std::vector<std::string>& args) {
+static Result<Success> do_load_persist_props(const BuiltinArguments& args) {
load_persist_props();
return Success();
}
-static Result<Success> do_load_system_props(const std::vector<std::string>& args) {
+static Result<Success> do_load_system_props(const BuiltinArguments& args) {
load_system_props();
return Success();
}
-static Result<Success> do_wait(const std::vector<std::string>& args) {
+static Result<Success> do_wait(const BuiltinArguments& args) {
auto timeout = kCommandRetryTimeout;
if (args.size() == 3) {
int timeout_int;
@@ -918,7 +919,7 @@ static Result<Success> do_wait(const std::vector<std::string>& args) {
return Success();
}
-static Result<Success> do_wait_for_prop(const std::vector<std::string>& args) {
+static Result<Success> do_wait_for_prop(const BuiltinArguments& args) {
const char* name = args[1].c_str();
const char* value = args[2].c_str();
size_t value_len = strlen(value);
@@ -939,7 +940,7 @@ static bool is_file_crypto() {
return android::base::GetProperty("ro.crypto.type", "") == "file";
}
-static Result<Success> do_installkey(const std::vector<std::string>& args) {
+static Result<Success> do_installkey(const BuiltinArguments& args) {
if (!is_file_crypto()) return Success();
auto unencrypted_dir = args[1] + e4crypt_unencrypted_folder;
@@ -948,64 +949,66 @@ static Result<Success> do_installkey(const std::vector<std::string>& args) {
}
std::vector<std::string> exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs",
"enablefilecrypto"};
- return do_exec(exec_args);
+ return do_exec({std::move(exec_args), args.context});
}
-static Result<Success> do_init_user0(const std::vector<std::string>& args) {
+static Result<Success> do_init_user0(const BuiltinArguments& args) {
std::vector<std::string> exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs",
"init_user0"};
- return do_exec(exec_args);
+ return do_exec({std::move(exec_args), args.context});
}
const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
// clang-format off
static const Map builtin_functions = {
- {"bootchart", {1, 1, do_bootchart}},
- {"chmod", {2, 2, do_chmod}},
- {"chown", {2, 3, do_chown}},
- {"class_reset", {1, 1, do_class_reset}},
- {"class_restart", {1, 1, do_class_restart}},
- {"class_start", {1, 1, do_class_start}},
- {"class_stop", {1, 1, do_class_stop}},
- {"copy", {2, 2, do_copy}},
- {"domainname", {1, 1, do_domainname}},
- {"enable", {1, 1, do_enable}},
- {"exec", {1, kMax, do_exec}},
- {"exec_background", {1, kMax, do_exec_background}},
- {"exec_start", {1, 1, do_exec_start}},
- {"export", {2, 2, do_export}},
- {"hostname", {1, 1, do_hostname}},
- {"ifup", {1, 1, do_ifup}},
- {"init_user0", {0, 0, do_init_user0}},
- {"insmod", {1, kMax, do_insmod}},
- {"installkey", {1, 1, do_installkey}},
- {"load_persist_props", {0, 0, do_load_persist_props}},
- {"load_system_props", {0, 0, do_load_system_props}},
- {"loglevel", {1, 1, do_loglevel}},
- {"mkdir", {1, 4, do_mkdir}},
- {"mount_all", {1, kMax, do_mount_all}},
- {"mount", {3, kMax, do_mount}},
- {"umount", {1, 1, do_umount}},
- {"readahead", {1, 2, do_readahead}},
- {"restart", {1, 1, do_restart}},
- {"restorecon", {1, kMax, do_restorecon}},
- {"restorecon_recursive", {1, kMax, do_restorecon_recursive}},
- {"rm", {1, 1, do_rm}},
- {"rmdir", {1, 1, do_rmdir}},
- {"setprop", {2, 2, do_setprop}},
- {"setrlimit", {3, 3, do_setrlimit}},
- {"start", {1, 1, do_start}},
- {"stop", {1, 1, do_stop}},
- {"swapon_all", {1, 1, do_swapon_all}},
- {"symlink", {2, 2, do_symlink}},
- {"sysclktz", {1, 1, do_sysclktz}},
- {"trigger", {1, 1, do_trigger}},
- {"verity_load_state", {0, 0, do_verity_load_state}},
- {"verity_update_state", {0, 0, do_verity_update_state}},
- {"wait", {1, 2, do_wait}},
- {"wait_for_prop", {2, 2, do_wait_for_prop}},
- {"write", {2, 2, do_write}},
+ {"bootchart", {1, 1, {false, do_bootchart}}},
+ {"chmod", {2, 2, {true, do_chmod}}},
+ {"chown", {2, 3, {true, do_chown}}},
+ {"class_reset", {1, 1, {false, do_class_reset}}},
+ {"class_restart", {1, 1, {false, do_class_restart}}},
+ {"class_start", {1, 1, {false, do_class_start}}},
+ {"class_stop", {1, 1, {false, do_class_stop}}},
+ {"copy", {2, 2, {true, do_copy}}},
+ {"domainname", {1, 1, {true, do_domainname}}},
+ {"enable", {1, 1, {false, do_enable}}},
+ {"exec", {1, kMax, {false, do_exec}}},
+ {"exec_background", {1, kMax, {false, do_exec_background}}},
+ {"exec_start", {1, 1, {false, do_exec_start}}},
+ {"export", {2, 2, {false, do_export}}},
+ {"hostname", {1, 1, {true, do_hostname}}},
+ {"ifup", {1, 1, {true, do_ifup}}},
+ {"init_user0", {0, 0, {false, do_init_user0}}},
+ {"insmod", {1, kMax, {true, do_insmod}}},
+ {"installkey", {1, 1, {false, do_installkey}}},
+ {"load_persist_props", {0, 0, {false, do_load_persist_props}}},
+ {"load_system_props", {0, 0, {false, do_load_system_props}}},
+ {"loglevel", {1, 1, {false, do_loglevel}}},
+ {"mkdir", {1, 4, {true, do_mkdir}}},
+ {"mount_all", {1, kMax, {false, do_mount_all}}},
+ {"mount", {3, kMax, {false, do_mount}}},
+ {"umount", {1, 1, {false, do_umount}}},
+ {"readahead", {1, 2, {true, do_readahead}}},
+ {"restart", {1, 1, {false, do_restart}}},
+ {"restorecon", {1, kMax, {true, do_restorecon}}},
+ {"restorecon_recursive", {1, kMax, {true, do_restorecon_recursive}}},
+ {"rm", {1, 1, {true, do_rm}}},
+ {"rmdir", {1, 1, {true, do_rmdir}}},
+ // TODO: setprop should be run in the subcontext, but property service needs to be split
+ // out from init before that is possible.
+ {"setprop", {2, 2, {false, do_setprop}}},
+ {"setrlimit", {3, 3, {false, do_setrlimit}}},
+ {"start", {1, 1, {false, do_start}}},
+ {"stop", {1, 1, {false, do_stop}}},
+ {"swapon_all", {1, 1, {false, do_swapon_all}}},
+ {"symlink", {2, 2, {true, do_symlink}}},
+ {"sysclktz", {1, 1, {false, do_sysclktz}}},
+ {"trigger", {1, 1, {false, do_trigger}}},
+ {"verity_load_state", {0, 0, {false, do_verity_load_state}}},
+ {"verity_update_state", {0, 0, {false, do_verity_update_state}}},
+ {"wait", {1, 2, {true, do_wait}}},
+ {"wait_for_prop", {2, 2, {true, do_wait_for_prop}}},
+ {"write", {2, 2, {true, do_write}}},
};
// clang-format on
return builtin_functions;