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 #include <property_info_parser/property_info_parser.h>
32
33 #include "builtin_arguments.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 using android::properties::BuildTrie;
43 using android::properties::PropertyInfoArea;
44 using android::properties::PropertyInfoEntry;
45
46 #define ReturnIfAnyArgsEmpty() \
47 for (const auto& arg : args) { \
48 if (arg.empty()) { \
49 return {}; \
50 } \
51 }
52
53 namespace android {
54 namespace init {
55
56 const PropertyInfoArea* property_info_area;
57
InitializeHostPropertyInfoArea(const std::vector<PropertyInfoEntry> & property_infos)58 Result<void> InitializeHostPropertyInfoArea(const std::vector<PropertyInfoEntry>& property_infos) {
59 static std::string serialized_contexts;
60 std::string trie_error;
61 if (!BuildTrie(property_infos, "u:object_r:default_prop:s0", "string", &serialized_contexts,
62 &trie_error)) {
63 return Error() << "Unable to serialize property contexts: " << trie_error;
64 }
65
66 property_info_area = reinterpret_cast<const PropertyInfoArea*>(serialized_contexts.c_str());
67 return {};
68 }
69
check_stub(const BuiltinArguments & args)70 static Result<void> check_stub(const BuiltinArguments& args) {
71 return {};
72 }
73
74 #include "generated_stub_builtin_function_map.h"
75
check_chown(const BuiltinArguments & args)76 Result<void> check_chown(const BuiltinArguments& args) {
77 if (!args[1].empty()) {
78 auto uid = DecodeUid(args[1]);
79 if (!uid.ok()) {
80 return Error() << "Unable to decode UID for '" << args[1] << "': " << uid.error();
81 }
82 }
83
84 // GID is optional and pushes the index of path out by one if specified.
85 if (args.size() == 4 && !args[2].empty()) {
86 auto gid = DecodeUid(args[2]);
87 if (!gid.ok()) {
88 return Error() << "Unable to decode GID for '" << args[2] << "': " << gid.error();
89 }
90 }
91
92 return {};
93 }
94
check_exec(const BuiltinArguments & args)95 Result<void> check_exec(const BuiltinArguments& args) {
96 ReturnIfAnyArgsEmpty();
97
98 auto result = Service::MakeTemporaryOneshotService(args.args);
99 if (!result.ok()) {
100 return result.error();
101 }
102
103 return {};
104 }
105
check_exec_background(const BuiltinArguments & args)106 Result<void> check_exec_background(const BuiltinArguments& args) {
107 return check_exec(std::move(args));
108 }
109
check_exec_reboot_on_failure(const BuiltinArguments & args)110 Result<void> check_exec_reboot_on_failure(const BuiltinArguments& args) {
111 BuiltinArguments remaining_args{.context = args.context};
112
113 remaining_args.args = std::vector<std::string>(args.begin() + 1, args.end());
114 remaining_args.args[0] = args[0];
115
116 return check_exec(remaining_args);
117 }
118
check_interface_restart(const BuiltinArguments & args)119 Result<void> check_interface_restart(const BuiltinArguments& args) {
120 if (auto result = IsKnownInterface(args[1]); !result.ok()) {
121 return result.error();
122 }
123 return {};
124 }
125
check_interface_start(const BuiltinArguments & args)126 Result<void> check_interface_start(const BuiltinArguments& args) {
127 return check_interface_restart(std::move(args));
128 }
129
check_interface_stop(const BuiltinArguments & args)130 Result<void> check_interface_stop(const BuiltinArguments& args) {
131 return check_interface_restart(std::move(args));
132 }
133
check_load_system_props(const BuiltinArguments & args)134 Result<void> check_load_system_props(const BuiltinArguments& args) {
135 return Error() << "'load_system_props' is deprecated";
136 }
137
check_loglevel(const BuiltinArguments & args)138 Result<void> check_loglevel(const BuiltinArguments& args) {
139 ReturnIfAnyArgsEmpty();
140
141 int log_level = -1;
142 ParseInt(args[1], &log_level);
143 if (log_level < 0 || log_level > 7) {
144 return Error() << "loglevel must be in the range of 0-7";
145 }
146 return {};
147 }
148
check_mount_all(const BuiltinArguments & args)149 Result<void> check_mount_all(const BuiltinArguments& args) {
150 auto options = ParseMountAll(args.args);
151 if (!options.ok()) {
152 return options.error();
153 }
154 return {};
155 }
156
check_mkdir(const BuiltinArguments & args)157 Result<void> check_mkdir(const BuiltinArguments& args) {
158 auto options = ParseMkdir(args.args);
159 if (!options.ok()) {
160 return options.error();
161 }
162 return {};
163 }
164
check_restorecon(const BuiltinArguments & args)165 Result<void> check_restorecon(const BuiltinArguments& args) {
166 ReturnIfAnyArgsEmpty();
167
168 auto restorecon_info = ParseRestorecon(args.args);
169 if (!restorecon_info.ok()) {
170 return restorecon_info.error();
171 }
172
173 return {};
174 }
175
check_restorecon_recursive(const BuiltinArguments & args)176 Result<void> check_restorecon_recursive(const BuiltinArguments& args) {
177 return check_restorecon(std::move(args));
178 }
179
check_setprop(const BuiltinArguments & args)180 Result<void> check_setprop(const BuiltinArguments& args) {
181 const std::string& name = args[1];
182 if (name.empty()) {
183 return {};
184 }
185 const std::string& value = args[2];
186
187 if (!IsLegalPropertyName(name)) {
188 return Error() << "'" << name << "' is not a legal property name";
189 }
190
191 if (!value.empty()) {
192 if (auto result = IsLegalPropertyValue(name, value); !result.ok()) {
193 return result.error();
194 }
195 }
196
197 if (StartsWith(name, "ctl.")) {
198 return Error()
199 << "Do not set ctl. properties from init; call the Service functions directly";
200 }
201
202 static constexpr const char kRestoreconProperty[] = "selinux.restorecon_recursive";
203 if (name == kRestoreconProperty) {
204 return Error() << "Do not set '" << kRestoreconProperty
205 << "' from init; use the restorecon builtin directly";
206 }
207
208 const char* target_context = nullptr;
209 const char* type = nullptr;
210 property_info_area->GetPropertyInfo(name.c_str(), &target_context, &type);
211
212 if (!CheckType(type, value)) {
213 return Error() << "Property type check failed, value doesn't match expected type '"
214 << (type ?: "(null)") << "'";
215 }
216
217 return {};
218 }
219
check_setrlimit(const BuiltinArguments & args)220 Result<void> check_setrlimit(const BuiltinArguments& args) {
221 ReturnIfAnyArgsEmpty();
222
223 auto rlimit = ParseRlimit(args.args);
224 if (!rlimit.ok()) return rlimit.error();
225 return {};
226 }
227
check_swapon_all(const BuiltinArguments & args)228 Result<void> check_swapon_all(const BuiltinArguments& args) {
229 auto options = ParseSwaponAll(args.args);
230 if (!options.ok()) {
231 return options.error();
232 }
233 return {};
234 }
235
check_sysclktz(const BuiltinArguments & args)236 Result<void> check_sysclktz(const BuiltinArguments& args) {
237 ReturnIfAnyArgsEmpty();
238
239 struct timezone tz = {};
240 if (!android::base::ParseInt(args[1], &tz.tz_minuteswest)) {
241 return Error() << "Unable to parse mins_west_of_gmt";
242 }
243 return {};
244 }
245
check_umount_all(const BuiltinArguments & args)246 Result<void> check_umount_all(const BuiltinArguments& args) {
247 auto options = ParseUmountAll(args.args);
248 if (!options.ok()) {
249 return options.error();
250 }
251 return {};
252 }
253
check_wait(const BuiltinArguments & args)254 Result<void> check_wait(const BuiltinArguments& args) {
255 if (args.size() == 3 && !args[2].empty()) {
256 double timeout_double;
257 if (!android::base::ParseDouble(args[2], &timeout_double, 0)) {
258 return Error() << "failed to parse timeout";
259 }
260 }
261 return {};
262 }
263
check_wait_for_prop(const BuiltinArguments & args)264 Result<void> check_wait_for_prop(const BuiltinArguments& args) {
265 return check_setprop(std::move(args));
266 }
267
268 } // namespace init
269 } // namespace android
270