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(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