blob: bef6966be6c37fcb3f868fc0f6121f3985538e84 [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>
28#include <android-base/parseint.h>
29#include <android-base/strings.h>
30
31#include "builtin_arguments.h"
Tom Cherryb5f2ec02019-11-08 17:54:27 -080032#include "host_init_verifier.h"
Daniel Normand2533c32019-08-02 15:13:50 -070033#include "interface_utils.h"
Tom Cherryb5f2ec02019-11-08 17:54:27 -080034#include "property_type.h"
Tom Cherry4772f1d2019-07-30 09:34:41 -070035#include "rlimit_parser.h"
36#include "service.h"
37#include "util.h"
38
39using android::base::ParseInt;
40using android::base::StartsWith;
41
42#define ReturnIfAnyArgsEmpty() \
43 for (const auto& arg : args) { \
44 if (arg.empty()) { \
45 return {}; \
46 } \
47 }
48
49namespace android {
50namespace init {
51
52Result<void> check_chown(const BuiltinArguments& args) {
53 if (!args[1].empty()) {
54 auto uid = DecodeUid(args[1]);
55 if (!uid) {
56 return Error() << "Unable to decode UID for '" << args[1] << "': " << uid.error();
57 }
58 }
59
60 // GID is optional and pushes the index of path out by one if specified.
61 if (args.size() == 4 && !args[2].empty()) {
62 auto gid = DecodeUid(args[2]);
63 if (!gid) {
64 return Error() << "Unable to decode GID for '" << args[2] << "': " << gid.error();
65 }
66 }
67
68 return {};
69}
70
71Result<void> check_exec(const BuiltinArguments& args) {
72 ReturnIfAnyArgsEmpty();
73
74 auto result = Service::MakeTemporaryOneshotService(args.args);
75 if (!result) {
76 return result.error();
77 }
78
79 return {};
80}
81
82Result<void> check_exec_background(const BuiltinArguments& args) {
83 return check_exec(std::move(args));
84}
85
Tom Cherry7896e7a2019-09-04 15:26:52 -070086Result<void> check_exec_reboot_on_failure(const BuiltinArguments& args) {
87 BuiltinArguments remaining_args(args.context);
88
89 remaining_args.args = std::vector<std::string>(args.begin() + 1, args.end());
90 remaining_args.args[0] = args[0];
91
92 return check_exec(remaining_args);
93}
94
Daniel Normand2533c32019-08-02 15:13:50 -070095Result<void> check_interface_restart(const BuiltinArguments& args) {
96 if (auto result = IsKnownInterface(args[1]); !result) {
97 return result.error();
98 }
99 return {};
100}
101
102Result<void> check_interface_start(const BuiltinArguments& args) {
103 return check_interface_restart(std::move(args));
104}
105
106Result<void> check_interface_stop(const BuiltinArguments& args) {
107 return check_interface_restart(std::move(args));
108}
109
Tom Cherry4772f1d2019-07-30 09:34:41 -0700110Result<void> check_load_system_props(const BuiltinArguments& args) {
111 return Error() << "'load_system_props' is deprecated";
112}
113
114Result<void> check_loglevel(const BuiltinArguments& args) {
115 ReturnIfAnyArgsEmpty();
116
117 int log_level = -1;
118 ParseInt(args[1], &log_level);
119 if (log_level < 0 || log_level > 7) {
120 return Error() << "loglevel must be in the range of 0-7";
121 }
122 return {};
123}
124
125Result<void> check_mkdir(const BuiltinArguments& args) {
Paul Crowley68258e82019-10-28 07:55:03 -0700126 auto options = ParseMkdir(args.args);
127 if (!options) {
128 return options.error();
Tom Cherry4772f1d2019-07-30 09:34:41 -0700129 }
Tom Cherry4772f1d2019-07-30 09:34:41 -0700130 return {};
131}
132
133Result<void> check_restorecon(const BuiltinArguments& args) {
134 ReturnIfAnyArgsEmpty();
135
136 auto restorecon_info = ParseRestorecon(args.args);
137 if (!restorecon_info) {
138 return restorecon_info.error();
139 }
140
141 return {};
142}
143
144Result<void> check_restorecon_recursive(const BuiltinArguments& args) {
145 return check_restorecon(std::move(args));
146}
147
148Result<void> check_setprop(const BuiltinArguments& args) {
149 const std::string& name = args[1];
150 if (name.empty()) {
151 return {};
152 }
153 const std::string& value = args[2];
154
155 if (!IsLegalPropertyName(name)) {
156 return Error() << "'" << name << "' is not a legal property name";
157 }
158
159 if (!value.empty()) {
160 if (auto result = IsLegalPropertyValue(name, value); !result) {
161 return result.error();
162 }
163 }
164
165 if (StartsWith(name, "ctl.")) {
166 return Error()
167 << "Do not set ctl. properties from init; call the Service functions directly";
168 }
169
170 static constexpr const char kRestoreconProperty[] = "selinux.restorecon_recursive";
171 if (name == kRestoreconProperty) {
172 return Error() << "Do not set '" << kRestoreconProperty
173 << "' from init; use the restorecon builtin directly";
174 }
175
Tom Cherryb5f2ec02019-11-08 17:54:27 -0800176 const char* target_context = nullptr;
177 const char* type = nullptr;
178 property_info_area->GetPropertyInfo(name.c_str(), &target_context, &type);
179
180 if (!CheckType(type, value)) {
181 return Error() << "Property type check failed, value doesn't match expected type '"
182 << (type ?: "(null)") << "'";
183 }
184
Tom Cherry4772f1d2019-07-30 09:34:41 -0700185 return {};
186}
187
188Result<void> check_setrlimit(const BuiltinArguments& args) {
189 ReturnIfAnyArgsEmpty();
190
191 auto rlimit = ParseRlimit(args.args);
192 if (!rlimit) return rlimit.error();
193 return {};
194}
195
196Result<void> check_sysclktz(const BuiltinArguments& args) {
197 ReturnIfAnyArgsEmpty();
198
199 struct timezone tz = {};
200 if (!android::base::ParseInt(args[1], &tz.tz_minuteswest)) {
201 return Error() << "Unable to parse mins_west_of_gmt";
202 }
203 return {};
204}
205
206Result<void> check_wait(const BuiltinArguments& args) {
207 if (args.size() == 3 && !args[2].empty()) {
208 int timeout_int;
209 if (!android::base::ParseInt(args[2], &timeout_int)) {
210 return Error() << "failed to parse timeout";
211 }
212 }
213 return {};
214}
215
216Result<void> check_wait_for_prop(const BuiltinArguments& args) {
217 return check_setprop(std::move(args));
218}
219
220} // namespace init
221} // namespace android