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