1 /*
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>
28 #include <android-base/parsedouble.h>
29 #include <android-base/parseint.h>
30 #include <android-base/strings.h>
31
32 #include "builtin_arguments.h"
33 #include "host_init_verifier.h"
34 #include "interface_utils.h"
35 #include "property_type.h"
36 #include "rlimit_parser.h"
37 #include "service.h"
38 #include "util.h"
39
40 using android::base::ParseInt;
41 using android::base::StartsWith;
42
43 #define ReturnIfAnyArgsEmpty() \
44 for (const auto& arg : args) { \
45 if (arg.empty()) { \
46 return {}; \
47 } \
48 }
49
50 namespace android {
51 namespace init {
52
check_chown(const BuiltinArguments & args)53 Result<void> check_chown(const BuiltinArguments& args) {
54 if (!args[1].empty()) {
55 auto uid = DecodeUid(args[1]);
56 if (!uid.ok()) {
57 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]);
64 if (!gid.ok()) {
65 return Error() << "Unable to decode GID for '" << args[2] << "': " << gid.error();
66 }
67 }
68
69 return {};
70 }
71
check_exec(const BuiltinArguments & args)72 Result<void> check_exec(const BuiltinArguments& args) {
73 ReturnIfAnyArgsEmpty();
74
75 auto result = Service::MakeTemporaryOneshotService(args.args);
76 if (!result.ok()) {
77 return result.error();
78 }
79
80 return {};
81 }
82
check_exec_background(const BuiltinArguments & args)83 Result<void> check_exec_background(const BuiltinArguments& args) {
84 return check_exec(std::move(args));
85 }
86
check_exec_reboot_on_failure(const BuiltinArguments & args)87 Result<void> check_exec_reboot_on_failure(const BuiltinArguments& args) {
88 BuiltinArguments remaining_args{.context = 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
check_interface_restart(const BuiltinArguments & args)96 Result<void> check_interface_restart(const BuiltinArguments& args) {
97 if (auto result = IsKnownInterface(args[1]); !result.ok()) {
98 return result.error();
99 }
100 return {};
101 }
102
check_interface_start(const BuiltinArguments & args)103 Result<void> check_interface_start(const BuiltinArguments& args) {
104 return check_interface_restart(std::move(args));
105 }
106
check_interface_stop(const BuiltinArguments & args)107 Result<void> check_interface_stop(const BuiltinArguments& args) {
108 return check_interface_restart(std::move(args));
109 }
110
check_load_system_props(const BuiltinArguments & args)111 Result<void> check_load_system_props(const BuiltinArguments& args) {
112 return Error() << "'load_system_props' is deprecated";
113 }
114
check_loglevel(const BuiltinArguments & args)115 Result<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
check_mount_all(const BuiltinArguments & args)126 Result<void> check_mount_all(const BuiltinArguments& args) {
127 auto options = ParseMountAll(args.args);
128 if (!options.ok()) {
129 return options.error();
130 }
131 return {};
132 }
133
check_mkdir(const BuiltinArguments & args)134 Result<void> check_mkdir(const BuiltinArguments& args) {
135 auto options = ParseMkdir(args.args);
136 if (!options.ok()) {
137 return options.error();
138 }
139 return {};
140 }
141
check_restorecon(const BuiltinArguments & args)142 Result<void> check_restorecon(const BuiltinArguments& args) {
143 ReturnIfAnyArgsEmpty();
144
145 auto restorecon_info = ParseRestorecon(args.args);
146 if (!restorecon_info.ok()) {
147 return restorecon_info.error();
148 }
149
150 return {};
151 }
152
check_restorecon_recursive(const BuiltinArguments & args)153 Result<void> check_restorecon_recursive(const BuiltinArguments& args) {
154 return check_restorecon(std::move(args));
155 }
156
check_setprop(const BuiltinArguments & args)157 Result<void> check_setprop(const BuiltinArguments& args) {
158 const std::string& name = args[1];
159 if (name.empty()) {
160 return {};
161 }
162 const std::string& value = args[2];
163
164 if (!IsLegalPropertyName(name)) {
165 return Error() << "'" << name << "' is not a legal property name";
166 }
167
168 if (!value.empty()) {
169 if (auto result = IsLegalPropertyValue(name, value); !result.ok()) {
170 return result.error();
171 }
172 }
173
174 if (StartsWith(name, "ctl.")) {
175 return Error()
176 << "Do not set ctl. properties from init; call the Service functions directly";
177 }
178
179 static constexpr const char kRestoreconProperty[] = "selinux.restorecon_recursive";
180 if (name == kRestoreconProperty) {
181 return Error() << "Do not set '" << kRestoreconProperty
182 << "' from init; use the restorecon builtin directly";
183 }
184
185 const char* target_context = nullptr;
186 const char* type = nullptr;
187 property_info_area->GetPropertyInfo(name.c_str(), &target_context, &type);
188
189 if (!CheckType(type, value)) {
190 return Error() << "Property type check failed, value doesn't match expected type '"
191 << (type ?: "(null)") << "'";
192 }
193
194 return {};
195 }
196
check_setrlimit(const BuiltinArguments & args)197 Result<void> check_setrlimit(const BuiltinArguments& args) {
198 ReturnIfAnyArgsEmpty();
199
200 auto rlimit = ParseRlimit(args.args);
201 if (!rlimit.ok()) return rlimit.error();
202 return {};
203 }
204
check_swapon_all(const BuiltinArguments & args)205 Result<void> check_swapon_all(const BuiltinArguments& args) {
206 auto options = ParseSwaponAll(args.args);
207 if (!options.ok()) {
208 return options.error();
209 }
210 return {};
211 }
212
check_sysclktz(const BuiltinArguments & args)213 Result<void> check_sysclktz(const BuiltinArguments& args) {
214 ReturnIfAnyArgsEmpty();
215
216 struct timezone tz = {};
217 if (!android::base::ParseInt(args[1], &tz.tz_minuteswest)) {
218 return Error() << "Unable to parse mins_west_of_gmt";
219 }
220 return {};
221 }
222
check_umount_all(const BuiltinArguments & args)223 Result<void> check_umount_all(const BuiltinArguments& args) {
224 auto options = ParseUmountAll(args.args);
225 if (!options.ok()) {
226 return options.error();
227 }
228 return {};
229 }
230
check_wait(const BuiltinArguments & args)231 Result<void> check_wait(const BuiltinArguments& args) {
232 if (args.size() == 3 && !args[2].empty()) {
233 double timeout_double;
234 if (!android::base::ParseDouble(args[2], &timeout_double, 0)) {
235 return Error() << "failed to parse timeout";
236 }
237 }
238 return {};
239 }
240
check_wait_for_prop(const BuiltinArguments & args)241 Result<void> check_wait_for_prop(const BuiltinArguments& args) {
242 return check_setprop(std::move(args));
243 }
244
245 } // namespace init
246 } // namespace android
247