blob: d1a84f30610125c3a0fc6604fa97863ce1eee3e0 [file] [log] [blame]
Tom Cherry4772f1d2019-07-30 09:34:41 -07001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17// Note that these check functions cannot check expanded arguments from properties, since they will
18// not know what those properties would be at runtime. They will be passed an empty string in the
19// situation that the input line had a property expansion without a default value, since an empty
20// string is otherwise an impossible value. They should therefore disregard checking empty
21// arguments.
22
23#include "check_builtins.h"
24
25#include <sys/time.h>
26
27#include <android-base/logging.h>
Mark Salyzynffa52e92020-05-14 09:20:30 -070028#include <android-base/parsedouble.h>
Tom Cherry4772f1d2019-07-30 09:34:41 -070029#include <android-base/parseint.h>
30#include <android-base/strings.h>
31
32#include "builtin_arguments.h"
Tom Cherryb5f2ec02019-11-08 17:54:27 -080033#include "host_init_verifier.h"
Daniel Normand2533c32019-08-02 15:13:50 -070034#include "interface_utils.h"
Tom Cherryb5f2ec02019-11-08 17:54:27 -080035#include "property_type.h"
Tom Cherry4772f1d2019-07-30 09:34:41 -070036#include "rlimit_parser.h"
37#include "service.h"
38#include "util.h"
39
40using android::base::ParseInt;
41using android::base::StartsWith;
42
43#define ReturnIfAnyArgsEmpty() \
44 for (const auto& arg : args) { \
45 if (arg.empty()) { \
46 return {}; \
47 } \
48 }
49
50namespace android {
51namespace init {
52
53Result<void> check_chown(const BuiltinArguments& args) {
54 if (!args[1].empty()) {
55 auto uid = DecodeUid(args[1]);
Bernie Innocenticecebbb2020-02-06 03:49:33 +090056 if (!uid.ok()) {
Tom Cherry4772f1d2019-07-30 09:34:41 -070057 return Error() << "Unable to decode UID for '" << args[1] << "': " << uid.error();
58 }
59 }
60
61 // GID is optional and pushes the index of path out by one if specified.
62 if (args.size() == 4 && !args[2].empty()) {
63 auto gid = DecodeUid(args[2]);
Bernie Innocenticecebbb2020-02-06 03:49:33 +090064 if (!gid.ok()) {
Tom Cherry4772f1d2019-07-30 09:34:41 -070065 return Error() << "Unable to decode GID for '" << args[2] << "': " << gid.error();
66 }
67 }
68
69 return {};
70}
71
72Result<void> check_exec(const BuiltinArguments& args) {
73 ReturnIfAnyArgsEmpty();
74
75 auto result = Service::MakeTemporaryOneshotService(args.args);
Bernie Innocenticecebbb2020-02-06 03:49:33 +090076 if (!result.ok()) {
Tom Cherry4772f1d2019-07-30 09:34:41 -070077 return result.error();
78 }
79
80 return {};
81}
82
83Result<void> check_exec_background(const BuiltinArguments& args) {
84 return check_exec(std::move(args));
85}
86
Tom Cherry7896e7a2019-09-04 15:26:52 -070087Result<void> check_exec_reboot_on_failure(const BuiltinArguments& args) {
88 BuiltinArguments remaining_args(args.context);
89
90 remaining_args.args = std::vector<std::string>(args.begin() + 1, args.end());
91 remaining_args.args[0] = args[0];
92
93 return check_exec(remaining_args);
94}
95
Daniel Normand2533c32019-08-02 15:13:50 -070096Result<void> check_interface_restart(const BuiltinArguments& args) {
Bernie Innocenticecebbb2020-02-06 03:49:33 +090097 if (auto result = IsKnownInterface(args[1]); !result.ok()) {
Daniel Normand2533c32019-08-02 15:13:50 -070098 return result.error();
99 }
100 return {};
101}
102
103Result<void> check_interface_start(const BuiltinArguments& args) {
104 return check_interface_restart(std::move(args));
105}
106
107Result<void> check_interface_stop(const BuiltinArguments& args) {
108 return check_interface_restart(std::move(args));
109}
110
Tom Cherry4772f1d2019-07-30 09:34:41 -0700111Result<void> check_load_system_props(const BuiltinArguments& args) {
112 return Error() << "'load_system_props' is deprecated";
113}
114
115Result<void> check_loglevel(const BuiltinArguments& args) {
116 ReturnIfAnyArgsEmpty();
117
118 int log_level = -1;
119 ParseInt(args[1], &log_level);
120 if (log_level < 0 || log_level > 7) {
121 return Error() << "loglevel must be in the range of 0-7";
122 }
123 return {};
124}
125
126Result<void> check_mkdir(const BuiltinArguments& args) {
Paul Crowley68258e82019-10-28 07:55:03 -0700127 auto options = ParseMkdir(args.args);
Bernie Innocenticecebbb2020-02-06 03:49:33 +0900128 if (!options.ok()) {
Paul Crowley68258e82019-10-28 07:55:03 -0700129 return options.error();
Tom Cherry4772f1d2019-07-30 09:34:41 -0700130 }
Tom Cherry4772f1d2019-07-30 09:34:41 -0700131 return {};
132}
133
134Result<void> check_restorecon(const BuiltinArguments& args) {
135 ReturnIfAnyArgsEmpty();
136
137 auto restorecon_info = ParseRestorecon(args.args);
Bernie Innocenticecebbb2020-02-06 03:49:33 +0900138 if (!restorecon_info.ok()) {
Tom Cherry4772f1d2019-07-30 09:34:41 -0700139 return restorecon_info.error();
140 }
141
142 return {};
143}
144
145Result<void> check_restorecon_recursive(const BuiltinArguments& args) {
146 return check_restorecon(std::move(args));
147}
148
149Result<void> check_setprop(const BuiltinArguments& args) {
150 const std::string& name = args[1];
151 if (name.empty()) {
152 return {};
153 }
154 const std::string& value = args[2];
155
156 if (!IsLegalPropertyName(name)) {
157 return Error() << "'" << name << "' is not a legal property name";
158 }
159
160 if (!value.empty()) {
Bernie Innocenticecebbb2020-02-06 03:49:33 +0900161 if (auto result = IsLegalPropertyValue(name, value); !result.ok()) {
Tom Cherry4772f1d2019-07-30 09:34:41 -0700162 return result.error();
163 }
164 }
165
166 if (StartsWith(name, "ctl.")) {
167 return Error()
168 << "Do not set ctl. properties from init; call the Service functions directly";
169 }
170
171 static constexpr const char kRestoreconProperty[] = "selinux.restorecon_recursive";
172 if (name == kRestoreconProperty) {
173 return Error() << "Do not set '" << kRestoreconProperty
174 << "' from init; use the restorecon builtin directly";
175 }
176
Tom Cherryb5f2ec02019-11-08 17:54:27 -0800177 const char* target_context = nullptr;
178 const char* type = nullptr;
179 property_info_area->GetPropertyInfo(name.c_str(), &target_context, &type);
180
181 if (!CheckType(type, value)) {
182 return Error() << "Property type check failed, value doesn't match expected type '"
183 << (type ?: "(null)") << "'";
184 }
185
Tom Cherry4772f1d2019-07-30 09:34:41 -0700186 return {};
187}
188
189Result<void> check_setrlimit(const BuiltinArguments& args) {
190 ReturnIfAnyArgsEmpty();
191
192 auto rlimit = ParseRlimit(args.args);
Bernie Innocenticecebbb2020-02-06 03:49:33 +0900193 if (!rlimit.ok()) return rlimit.error();
Tom Cherry4772f1d2019-07-30 09:34:41 -0700194 return {};
195}
196
197Result<void> check_sysclktz(const BuiltinArguments& args) {
198 ReturnIfAnyArgsEmpty();
199
200 struct timezone tz = {};
201 if (!android::base::ParseInt(args[1], &tz.tz_minuteswest)) {
202 return Error() << "Unable to parse mins_west_of_gmt";
203 }
204 return {};
205}
206
207Result<void> check_wait(const BuiltinArguments& args) {
208 if (args.size() == 3 && !args[2].empty()) {
Mark Salyzynffa52e92020-05-14 09:20:30 -0700209 double timeout_double;
210 if (!android::base::ParseDouble(args[2], &timeout_double, 0)) {
Tom Cherry4772f1d2019-07-30 09:34:41 -0700211 return Error() << "failed to parse timeout";
212 }
213 }
214 return {};
215}
216
217Result<void> check_wait_for_prop(const BuiltinArguments& args) {
218 return check_setprop(std::move(args));
219}
220
221} // namespace init
222} // namespace android