blob: 33ed05097afcf4f2912814bbc9ceb8d1fd6cc27b [file] [log] [blame]
Tom Cherry2aeb1ad2019-06-26 10:46:20 -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#include "service_parser.h"
18
Tom Cherryb1ffb1d2019-06-26 11:22:52 -070019#include <linux/input.h>
Tom Cherry2aeb1ad2019-06-26 10:46:20 -070020
Tom Cherryb1ffb1d2019-06-26 11:22:52 -070021#include <android-base/logging.h>
22#include <android-base/parseint.h>
23#include <android-base/strings.h>
24#include <hidl-util/FQName.h>
25#include <system/thread_defs.h>
26
27#include "rlimit_parser.h"
Tom Cherry2aeb1ad2019-06-26 10:46:20 -070028#include "util.h"
29
30#if defined(__ANDROID__)
Tom Cherryb1ffb1d2019-06-26 11:22:52 -070031#include <android/api-level.h>
Tom Cherry2aeb1ad2019-06-26 10:46:20 -070032#include <sys/system_properties.h>
33
34#include "selinux.h"
35#else
36#include "host_init_stubs.h"
37#endif
38
Tom Cherryb1ffb1d2019-06-26 11:22:52 -070039using android::base::ParseInt;
40using android::base::Split;
Tom Cherry2aeb1ad2019-06-26 10:46:20 -070041using android::base::StartsWith;
42
43namespace android {
44namespace init {
45
Tom Cherryb1ffb1d2019-06-26 11:22:52 -070046Result<void> ServiceParser::ParseCapabilities(std::vector<std::string>&& args) {
47 service_->capabilities_ = 0;
48
49 if (!CapAmbientSupported()) {
50 return Error()
51 << "capabilities requested but the kernel does not support ambient capabilities";
52 }
53
54 unsigned int last_valid_cap = GetLastValidCap();
55 if (last_valid_cap >= service_->capabilities_->size()) {
56 LOG(WARNING) << "last valid run-time capability is larger than CAP_LAST_CAP";
57 }
58
59 for (size_t i = 1; i < args.size(); i++) {
60 const std::string& arg = args[i];
61 int res = LookupCap(arg);
62 if (res < 0) {
63 return Errorf("invalid capability '{}'", arg);
64 }
65 unsigned int cap = static_cast<unsigned int>(res); // |res| is >= 0.
66 if (cap > last_valid_cap) {
67 return Errorf("capability '{}' not supported by the kernel", arg);
68 }
69 (*service_->capabilities_)[cap] = true;
70 }
71 return {};
72}
73
74Result<void> ServiceParser::ParseClass(std::vector<std::string>&& args) {
75 service_->classnames_ = std::set<std::string>(args.begin() + 1, args.end());
76 return {};
77}
78
79Result<void> ServiceParser::ParseConsole(std::vector<std::string>&& args) {
80 service_->flags_ |= SVC_CONSOLE;
81 service_->proc_attr_.console = args.size() > 1 ? "/dev/" + args[1] : "";
82 return {};
83}
84
85Result<void> ServiceParser::ParseCritical(std::vector<std::string>&& args) {
86 service_->flags_ |= SVC_CRITICAL;
87 return {};
88}
89
90Result<void> ServiceParser::ParseDisabled(std::vector<std::string>&& args) {
91 service_->flags_ |= SVC_DISABLED;
92 service_->flags_ |= SVC_RC_DISABLED;
93 return {};
94}
95
96Result<void> ServiceParser::ParseEnterNamespace(std::vector<std::string>&& args) {
97 if (args[1] != "net") {
98 return Error() << "Init only supports entering network namespaces";
99 }
100 if (!service_->namespaces_.namespaces_to_enter.empty()) {
101 return Error() << "Only one network namespace may be entered";
102 }
103 // Network namespaces require that /sys is remounted, otherwise the old adapters will still be
104 // present. Therefore, they also require mount namespaces.
105 service_->namespaces_.flags |= CLONE_NEWNS;
106 service_->namespaces_.namespaces_to_enter.emplace_back(CLONE_NEWNET, std::move(args[2]));
107 return {};
108}
109
110Result<void> ServiceParser::ParseGroup(std::vector<std::string>&& args) {
111 auto gid = DecodeUid(args[1]);
112 if (!gid) {
113 return Error() << "Unable to decode GID for '" << args[1] << "': " << gid.error();
114 }
115 service_->proc_attr_.gid = *gid;
116
117 for (std::size_t n = 2; n < args.size(); n++) {
118 gid = DecodeUid(args[n]);
119 if (!gid) {
120 return Error() << "Unable to decode GID for '" << args[n] << "': " << gid.error();
121 }
122 service_->proc_attr_.supp_gids.emplace_back(*gid);
123 }
124 return {};
125}
126
127Result<void> ServiceParser::ParsePriority(std::vector<std::string>&& args) {
128 service_->proc_attr_.priority = 0;
129 if (!ParseInt(args[1], &service_->proc_attr_.priority,
130 static_cast<int>(ANDROID_PRIORITY_HIGHEST), // highest is negative
131 static_cast<int>(ANDROID_PRIORITY_LOWEST))) {
132 return Errorf("process priority value must be range {} - {}", ANDROID_PRIORITY_HIGHEST,
133 ANDROID_PRIORITY_LOWEST);
134 }
135 return {};
136}
137
138Result<void> ServiceParser::ParseInterface(std::vector<std::string>&& args) {
139 const std::string& interface_name = args[1];
140 const std::string& instance_name = args[2];
141
142 FQName fq_name;
143 if (!FQName::parse(interface_name, &fq_name)) {
144 return Error() << "Invalid fully-qualified name for interface '" << interface_name << "'";
145 }
146
147 if (!fq_name.isFullyQualified()) {
148 return Error() << "Interface name not fully-qualified '" << interface_name << "'";
149 }
150
151 if (fq_name.isValidValueName()) {
152 return Error() << "Interface name must not be a value name '" << interface_name << "'";
153 }
154
155 const std::string fullname = interface_name + "/" + instance_name;
156
157 for (const auto& svc : *service_list_) {
158 if (svc->interfaces().count(fullname) > 0) {
159 return Error() << "Interface '" << fullname << "' redefined in " << service_->name()
160 << " but is already defined by " << svc->name();
161 }
162 }
163
164 service_->interfaces_.insert(fullname);
165
166 return {};
167}
168
169Result<void> ServiceParser::ParseIoprio(std::vector<std::string>&& args) {
170 if (!ParseInt(args[2], &service_->proc_attr_.ioprio_pri, 0, 7)) {
171 return Error() << "priority value must be range 0 - 7";
172 }
173
174 if (args[1] == "rt") {
175 service_->proc_attr_.ioprio_class = IoSchedClass_RT;
176 } else if (args[1] == "be") {
177 service_->proc_attr_.ioprio_class = IoSchedClass_BE;
178 } else if (args[1] == "idle") {
179 service_->proc_attr_.ioprio_class = IoSchedClass_IDLE;
180 } else {
181 return Error() << "ioprio option usage: ioprio <rt|be|idle> <0-7>";
182 }
183
184 return {};
185}
186
187Result<void> ServiceParser::ParseKeycodes(std::vector<std::string>&& args) {
188 auto it = args.begin() + 1;
189 if (args.size() == 2 && StartsWith(args[1], "$")) {
190 std::string expanded;
191 if (!expand_props(args[1], &expanded)) {
192 return Error() << "Could not expand property '" << args[1] << "'";
193 }
194
195 // If the property is not set, it defaults to none, in which case there are no keycodes
196 // for this service.
197 if (expanded == "none") {
198 return {};
199 }
200
201 args = Split(expanded, ",");
202 it = args.begin();
203 }
204
205 for (; it != args.end(); ++it) {
206 int code;
207 if (ParseInt(*it, &code, 0, KEY_MAX)) {
208 for (auto& key : service_->keycodes_) {
209 if (key == code) return Error() << "duplicate keycode: " << *it;
210 }
211 service_->keycodes_.insert(
212 std::upper_bound(service_->keycodes_.begin(), service_->keycodes_.end(), code),
213 code);
214 } else {
215 return Error() << "invalid keycode: " << *it;
216 }
217 }
218 return {};
219}
220
221Result<void> ServiceParser::ParseOneshot(std::vector<std::string>&& args) {
222 service_->flags_ |= SVC_ONESHOT;
223 return {};
224}
225
226Result<void> ServiceParser::ParseOnrestart(std::vector<std::string>&& args) {
227 args.erase(args.begin());
228 int line = service_->onrestart_.NumCommands() + 1;
229 if (auto result = service_->onrestart_.AddCommand(std::move(args), line); !result) {
230 return Error() << "cannot add Onrestart command: " << result.error();
231 }
232 return {};
233}
234
235Result<void> ServiceParser::ParseNamespace(std::vector<std::string>&& args) {
236 for (size_t i = 1; i < args.size(); i++) {
237 if (args[i] == "pid") {
238 service_->namespaces_.flags |= CLONE_NEWPID;
239 // PID namespaces require mount namespaces.
240 service_->namespaces_.flags |= CLONE_NEWNS;
241 } else if (args[i] == "mnt") {
242 service_->namespaces_.flags |= CLONE_NEWNS;
243 } else {
244 return Error() << "namespace must be 'pid' or 'mnt'";
245 }
246 }
247 return {};
248}
249
250Result<void> ServiceParser::ParseOomScoreAdjust(std::vector<std::string>&& args) {
251 if (!ParseInt(args[1], &service_->oom_score_adjust_, -1000, 1000)) {
252 return Error() << "oom_score_adjust value must be in range -1000 - +1000";
253 }
254 return {};
255}
256
257Result<void> ServiceParser::ParseOverride(std::vector<std::string>&& args) {
258 service_->override_ = true;
259 return {};
260}
261
262Result<void> ServiceParser::ParseMemcgSwappiness(std::vector<std::string>&& args) {
263 if (!ParseInt(args[1], &service_->swappiness_, 0)) {
264 return Error() << "swappiness value must be equal or greater than 0";
265 }
266 return {};
267}
268
269Result<void> ServiceParser::ParseMemcgLimitInBytes(std::vector<std::string>&& args) {
270 if (!ParseInt(args[1], &service_->limit_in_bytes_, 0)) {
271 return Error() << "limit_in_bytes value must be equal or greater than 0";
272 }
273 return {};
274}
275
276Result<void> ServiceParser::ParseMemcgLimitPercent(std::vector<std::string>&& args) {
277 if (!ParseInt(args[1], &service_->limit_percent_, 0)) {
278 return Error() << "limit_percent value must be equal or greater than 0";
279 }
280 return {};
281}
282
283Result<void> ServiceParser::ParseMemcgLimitProperty(std::vector<std::string>&& args) {
284 service_->limit_property_ = std::move(args[1]);
285 return {};
286}
287
288Result<void> ServiceParser::ParseMemcgSoftLimitInBytes(std::vector<std::string>&& args) {
289 if (!ParseInt(args[1], &service_->soft_limit_in_bytes_, 0)) {
290 return Error() << "soft_limit_in_bytes value must be equal or greater than 0";
291 }
292 return {};
293}
294
295Result<void> ServiceParser::ParseProcessRlimit(std::vector<std::string>&& args) {
296 auto rlimit = ParseRlimit(args);
297 if (!rlimit) return rlimit.error();
298
299 service_->proc_attr_.rlimits.emplace_back(*rlimit);
300 return {};
301}
302
303Result<void> ServiceParser::ParseRestartPeriod(std::vector<std::string>&& args) {
304 int period;
305 if (!ParseInt(args[1], &period, 5)) {
306 return Error() << "restart_period value must be an integer >= 5";
307 }
308 service_->restart_period_ = std::chrono::seconds(period);
309 return {};
310}
311
312Result<void> ServiceParser::ParseSeclabel(std::vector<std::string>&& args) {
313 service_->seclabel_ = std::move(args[1]);
314 return {};
315}
316
317Result<void> ServiceParser::ParseSigstop(std::vector<std::string>&& args) {
318 service_->sigstop_ = true;
319 return {};
320}
321
322Result<void> ServiceParser::ParseSetenv(std::vector<std::string>&& args) {
323 service_->environment_vars_.emplace_back(std::move(args[1]), std::move(args[2]));
324 return {};
325}
326
327Result<void> ServiceParser::ParseShutdown(std::vector<std::string>&& args) {
328 if (args[1] == "critical") {
329 service_->flags_ |= SVC_SHUTDOWN_CRITICAL;
330 return {};
331 }
332 return Error() << "Invalid shutdown option";
333}
334
335Result<void> ServiceParser::ParseTimeoutPeriod(std::vector<std::string>&& args) {
336 int period;
337 if (!ParseInt(args[1], &period, 1)) {
338 return Error() << "timeout_period value must be an integer >= 1";
339 }
340 service_->timeout_period_ = std::chrono::seconds(period);
341 return {};
342}
343
344template <typename T>
345Result<void> ServiceParser::AddDescriptor(std::vector<std::string>&& args) {
346 int perm = args.size() > 3 ? std::strtoul(args[3].c_str(), 0, 8) : -1;
347 Result<uid_t> uid = 0;
348 Result<gid_t> gid = 0;
349 std::string context = args.size() > 6 ? args[6] : "";
350
351 if (args.size() > 4) {
352 uid = DecodeUid(args[4]);
353 if (!uid) {
354 return Error() << "Unable to find UID for '" << args[4] << "': " << uid.error();
355 }
356 }
357
358 if (args.size() > 5) {
359 gid = DecodeUid(args[5]);
360 if (!gid) {
361 return Error() << "Unable to find GID for '" << args[5] << "': " << gid.error();
362 }
363 }
364
365 auto descriptor = std::make_unique<T>(args[1], args[2], *uid, *gid, perm, context);
366
367 auto old = std::find_if(
368 service_->descriptors_.begin(), service_->descriptors_.end(),
369 [&descriptor](const auto& other) { return descriptor.get() == other.get(); });
370
371 if (old != service_->descriptors_.end()) {
372 return Error() << "duplicate descriptor " << args[1] << " " << args[2];
373 }
374
375 service_->descriptors_.emplace_back(std::move(descriptor));
376 return {};
377}
378
379// name type perm [ uid gid context ]
380Result<void> ServiceParser::ParseSocket(std::vector<std::string>&& args) {
381 if (!StartsWith(args[2], "dgram") && !StartsWith(args[2], "stream") &&
382 !StartsWith(args[2], "seqpacket")) {
383 return Error() << "socket type must be 'dgram', 'stream' or 'seqpacket'";
384 }
385 return AddDescriptor<SocketInfo>(std::move(args));
386}
387
388// name type perm [ uid gid context ]
389Result<void> ServiceParser::ParseFile(std::vector<std::string>&& args) {
390 if (args[2] != "r" && args[2] != "w" && args[2] != "rw") {
391 return Error() << "file type must be 'r', 'w' or 'rw'";
392 }
393 std::string expanded;
394 if (!expand_props(args[1], &expanded)) {
395 return Error() << "Could not expand property in file path '" << args[1] << "'";
396 }
397 args[1] = std::move(expanded);
398 if ((args[1][0] != '/') || (args[1].find("../") != std::string::npos)) {
399 return Error() << "file name must not be relative";
400 }
401 return AddDescriptor<FileInfo>(std::move(args));
402}
403
404Result<void> ServiceParser::ParseUser(std::vector<std::string>&& args) {
405 auto uid = DecodeUid(args[1]);
406 if (!uid) {
407 return Error() << "Unable to find UID for '" << args[1] << "': " << uid.error();
408 }
409 service_->proc_attr_.uid = *uid;
410 return {};
411}
412
413Result<void> ServiceParser::ParseWritepid(std::vector<std::string>&& args) {
414 args.erase(args.begin());
415 service_->writepid_files_ = std::move(args);
416 return {};
417}
418
419Result<void> ServiceParser::ParseUpdatable(std::vector<std::string>&& args) {
420 service_->updatable_ = true;
421 return {};
422}
423
424class ServiceParser::OptionParserMap : public KeywordMap<OptionParser> {
425 public:
426 OptionParserMap() {}
427
428 private:
429 const Map& map() const override;
430};
431
432const ServiceParser::OptionParserMap::Map& ServiceParser::OptionParserMap::map() const {
433 constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
434 // clang-format off
435 static const Map option_parsers = {
436 {"capabilities",
437 {0, kMax, &ServiceParser::ParseCapabilities}},
438 {"class", {1, kMax, &ServiceParser::ParseClass}},
439 {"console", {0, 1, &ServiceParser::ParseConsole}},
440 {"critical", {0, 0, &ServiceParser::ParseCritical}},
441 {"disabled", {0, 0, &ServiceParser::ParseDisabled}},
442 {"enter_namespace",
443 {2, 2, &ServiceParser::ParseEnterNamespace}},
444 {"file", {2, 2, &ServiceParser::ParseFile}},
445 {"group", {1, NR_SVC_SUPP_GIDS + 1, &ServiceParser::ParseGroup}},
446 {"interface", {2, 2, &ServiceParser::ParseInterface}},
447 {"ioprio", {2, 2, &ServiceParser::ParseIoprio}},
448 {"keycodes", {1, kMax, &ServiceParser::ParseKeycodes}},
449 {"memcg.limit_in_bytes",
450 {1, 1, &ServiceParser::ParseMemcgLimitInBytes}},
451 {"memcg.limit_percent",
452 {1, 1, &ServiceParser::ParseMemcgLimitPercent}},
453 {"memcg.limit_property",
454 {1, 1, &ServiceParser::ParseMemcgLimitProperty}},
455 {"memcg.soft_limit_in_bytes",
456 {1, 1, &ServiceParser::ParseMemcgSoftLimitInBytes}},
457 {"memcg.swappiness",
458 {1, 1, &ServiceParser::ParseMemcgSwappiness}},
459 {"namespace", {1, 2, &ServiceParser::ParseNamespace}},
460 {"oneshot", {0, 0, &ServiceParser::ParseOneshot}},
461 {"onrestart", {1, kMax, &ServiceParser::ParseOnrestart}},
462 {"oom_score_adjust",
463 {1, 1, &ServiceParser::ParseOomScoreAdjust}},
464 {"override", {0, 0, &ServiceParser::ParseOverride}},
465 {"priority", {1, 1, &ServiceParser::ParsePriority}},
466 {"restart_period",
467 {1, 1, &ServiceParser::ParseRestartPeriod}},
468 {"rlimit", {3, 3, &ServiceParser::ParseProcessRlimit}},
469 {"seclabel", {1, 1, &ServiceParser::ParseSeclabel}},
470 {"setenv", {2, 2, &ServiceParser::ParseSetenv}},
471 {"shutdown", {1, 1, &ServiceParser::ParseShutdown}},
472 {"sigstop", {0, 0, &ServiceParser::ParseSigstop}},
473 {"socket", {3, 6, &ServiceParser::ParseSocket}},
474 {"timeout_period",
475 {1, 1, &ServiceParser::ParseTimeoutPeriod}},
476 {"updatable", {0, 0, &ServiceParser::ParseUpdatable}},
477 {"user", {1, 1, &ServiceParser::ParseUser}},
478 {"writepid", {1, kMax, &ServiceParser::ParseWritepid}},
479 };
480 // clang-format on
481 return option_parsers;
482}
483
Tom Cherry2aeb1ad2019-06-26 10:46:20 -0700484Result<void> ServiceParser::ParseSection(std::vector<std::string>&& args,
485 const std::string& filename, int line) {
486 if (args.size() < 3) {
487 return Error() << "services must have a name and a program";
488 }
489
490 const std::string& name = args[1];
491 if (!IsValidName(name)) {
492 return Error() << "invalid service name '" << name << "'";
493 }
494
495 filename_ = filename;
496
497 Subcontext* restart_action_subcontext = nullptr;
498 if (subcontexts_) {
499 for (auto& subcontext : *subcontexts_) {
500 if (StartsWith(filename, subcontext.path_prefix())) {
501 restart_action_subcontext = &subcontext;
502 break;
503 }
504 }
505 }
506
507 std::vector<std::string> str_args(args.begin() + 2, args.end());
508
509 if (SelinuxGetVendorAndroidVersion() <= __ANDROID_API_P__) {
510 if (str_args[0] == "/sbin/watchdogd") {
511 str_args[0] = "/system/bin/watchdogd";
512 }
513 }
514
515 service_ = std::make_unique<Service>(name, restart_action_subcontext, str_args);
516 return {};
517}
518
519Result<void> ServiceParser::ParseLineSection(std::vector<std::string>&& args, int line) {
Tom Cherryb1ffb1d2019-06-26 11:22:52 -0700520 if (!service_) {
521 return {};
522 }
523
524 static const OptionParserMap parser_map;
525 auto parser = parser_map.FindFunction(args);
526
527 if (!parser) return parser.error();
528
529 return std::invoke(*parser, this, std::move(args));
Tom Cherry2aeb1ad2019-06-26 10:46:20 -0700530}
531
532Result<void> ServiceParser::EndSection() {
Tom Cherryb1ffb1d2019-06-26 11:22:52 -0700533 if (!service_) {
534 return {};
535 }
Tom Cherry2aeb1ad2019-06-26 10:46:20 -0700536
Tom Cherryb1ffb1d2019-06-26 11:22:52 -0700537 Service* old_service = service_list_->FindService(service_->name());
538 if (old_service) {
539 if (!service_->is_override()) {
540 return Error() << "ignored duplicate definition of service '" << service_->name()
541 << "'";
Tom Cherry2aeb1ad2019-06-26 10:46:20 -0700542 }
543
Tom Cherryb1ffb1d2019-06-26 11:22:52 -0700544 if (StartsWith(filename_, "/apex/") && !old_service->is_updatable()) {
545 return Error() << "cannot update a non-updatable service '" << service_->name()
546 << "' with a config in APEX";
547 }
548
549 service_list_->RemoveService(*old_service);
550 old_service = nullptr;
Tom Cherry2aeb1ad2019-06-26 10:46:20 -0700551 }
552
Tom Cherryb1ffb1d2019-06-26 11:22:52 -0700553 service_list_->AddService(std::move(service_));
554
Tom Cherry2aeb1ad2019-06-26 10:46:20 -0700555 return {};
556}
557
558bool ServiceParser::IsValidName(const std::string& name) const {
559 // Property names can be any length, but may only contain certain characters.
560 // Property values can contain any characters, but may only be a certain length.
561 // (The latter restriction is needed because `start` and `stop` work by writing
562 // the service name to the "ctl.start" and "ctl.stop" properties.)
563 return IsLegalPropertyName("init.svc." + name) && name.size() <= PROP_VALUE_MAX;
564}
565
566} // namespace init
567} // namespace android