• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "service_parser.h"
18 
19 #include <linux/input.h>
20 #include <stdlib.h>
21 #include <sys/socket.h>
22 
23 #include <algorithm>
24 #include <sstream>
25 
26 #include <android-base/logging.h>
27 #include <android-base/parseint.h>
28 #include <android-base/properties.h>
29 #include <android-base/strings.h>
30 #include <processgroup/processgroup.h>
31 #include <system/thread_defs.h>
32 
33 #include "lmkd_service.h"
34 #include "rlimit_parser.h"
35 #include "service_utils.h"
36 #include "util.h"
37 
38 #ifdef INIT_FULL_SOURCES
39 #include <android/api-level.h>
40 #include <sys/system_properties.h>
41 
42 #include "selinux.h"
43 #else
44 #include "host_init_stubs.h"
45 #endif
46 
47 using android::base::ParseInt;
48 using android::base::Split;
49 using android::base::StartsWith;
50 
51 namespace android {
52 namespace init {
53 
54 #ifdef INIT_FULL_SOURCES
55 // on full sources, we have better information on device to
56 // make this decision
57 constexpr bool kAlwaysErrorUserRoot = false;
58 #else
59 constexpr uint64_t kBuildShippingApiLevel = BUILD_SHIPPING_API_LEVEL + 0 /* +0 if empty */;
60 // on partial sources, the host build, we don't have the specific
61 // vendor API level, but we can enforce things based on the
62 // shipping API level.
63 constexpr bool kAlwaysErrorUserRoot = kBuildShippingApiLevel > __ANDROID_API_V__;
64 #endif
65 
ParseCapabilities(std::vector<std::string> && args)66 Result<void> ServiceParser::ParseCapabilities(std::vector<std::string>&& args) {
67     service_->capabilities_ = 0;
68 
69     if (!CapAmbientSupported()) {
70         return Error()
71                << "capabilities requested but the kernel does not support ambient capabilities";
72     }
73 
74     unsigned int last_valid_cap = GetLastValidCap();
75     if (last_valid_cap >= service_->capabilities_->size()) {
76         LOG(WARNING) << "last valid run-time capability is larger than CAP_LAST_CAP";
77     }
78 
79     for (size_t i = 1; i < args.size(); i++) {
80         const std::string& arg = args[i];
81         int res = LookupCap(arg);
82         if (res < 0) {
83             return Errorf("invalid capability '{}'", arg);
84         }
85         unsigned int cap = static_cast<unsigned int>(res);  // |res| is >= 0.
86         if (cap > last_valid_cap) {
87             return Errorf("capability '{}' not supported by the kernel", arg);
88         }
89         (*service_->capabilities_)[cap] = true;
90     }
91     return {};
92 }
93 
ParseClass(std::vector<std::string> && args)94 Result<void> ServiceParser::ParseClass(std::vector<std::string>&& args) {
95     service_->classnames_ = std::set<std::string>(args.begin() + 1, args.end());
96     return {};
97 }
98 
ParseConsole(std::vector<std::string> && args)99 Result<void> ServiceParser::ParseConsole(std::vector<std::string>&& args) {
100     if (service_->proc_attr_.stdio_to_kmsg) {
101         return Error() << "'console' and 'stdio_to_kmsg' are mutually exclusive";
102     }
103     service_->flags_ |= SVC_CONSOLE;
104     service_->proc_attr_.console = args.size() > 1 ? "/dev/" + args[1] : "";
105     return {};
106 }
107 
ParseCritical(std::vector<std::string> && args)108 Result<void> ServiceParser::ParseCritical(std::vector<std::string>&& args) {
109     std::optional<std::string> fatal_reboot_target;
110     std::optional<std::chrono::minutes> fatal_crash_window;
111 
112     for (auto it = args.begin() + 1; it != args.end(); ++it) {
113         auto arg = android::base::Split(*it, "=");
114         if (arg.size() != 2) {
115             return Error() << "critical: Argument '" << *it << "' is not supported";
116         } else if (arg[0] == "target") {
117             fatal_reboot_target = arg[1];
118         } else if (arg[0] == "window") {
119             int minutes;
120             auto window = ExpandProps(arg[1]);
121             if (!window.ok()) {
122                 return Error() << "critical: Could not expand argument ': " << arg[1];
123             }
124             if (*window == "off") {
125                 return {};
126             }
127             if (!ParseInt(*window, &minutes, 0)) {
128                 return Error() << "critical: 'fatal_crash_window' must be an integer > 0";
129             }
130             fatal_crash_window = std::chrono::minutes(minutes);
131         } else {
132             return Error() << "critical: Argument '" << *it << "' is not supported";
133         }
134     }
135 
136     if (fatal_reboot_target) {
137         service_->fatal_reboot_target_ = *fatal_reboot_target;
138     }
139     if (fatal_crash_window) {
140         service_->fatal_crash_window_ = *fatal_crash_window;
141     }
142     service_->flags_ |= SVC_CRITICAL;
143     return {};
144 }
145 
ParseDisabled(std::vector<std::string> && args)146 Result<void> ServiceParser::ParseDisabled(std::vector<std::string>&& args) {
147     service_->flags_ |= SVC_DISABLED;
148     service_->flags_ |= SVC_RC_DISABLED;
149     return {};
150 }
151 
ParseEnterNamespace(std::vector<std::string> && args)152 Result<void> ServiceParser::ParseEnterNamespace(std::vector<std::string>&& args) {
153     if (args[1] != "net") {
154         return Error() << "Init only supports entering network namespaces";
155     }
156     if (!service_->namespaces_.namespaces_to_enter.empty()) {
157         return Error() << "Only one network namespace may be entered";
158     }
159     // Network namespaces require that /sys is remounted, otherwise the old adapters will still be
160     // present. Therefore, they also require mount namespaces.
161     service_->namespaces_.flags |= CLONE_NEWNS;
162     service_->namespaces_.namespaces_to_enter.emplace_back(CLONE_NEWNET, std::move(args[2]));
163     return {};
164 }
165 
ParseGentleKill(std::vector<std::string> && args)166 Result<void> ServiceParser::ParseGentleKill(std::vector<std::string>&& args) {
167     service_->flags_ |= SVC_GENTLE_KILL;
168     return {};
169 }
170 
ParseGroup(std::vector<std::string> && args)171 Result<void> ServiceParser::ParseGroup(std::vector<std::string>&& args) {
172     auto gid = DecodeUid(args[1]);
173     if (!gid.ok()) {
174         return Error() << "Unable to decode GID for '" << args[1] << "': " << gid.error();
175     }
176     service_->proc_attr_.gid = *gid;
177 
178     for (std::size_t n = 2; n < args.size(); n++) {
179         gid = DecodeUid(args[n]);
180         if (!gid.ok()) {
181             return Error() << "Unable to decode GID for '" << args[n] << "': " << gid.error();
182         }
183         service_->proc_attr_.supp_gids.emplace_back(*gid);
184     }
185     return {};
186 }
187 
ParsePriority(std::vector<std::string> && args)188 Result<void> ServiceParser::ParsePriority(std::vector<std::string>&& args) {
189     service_->proc_attr_.priority = 0;
190     if (!ParseInt(args[1], &service_->proc_attr_.priority,
191                   static_cast<int>(ANDROID_PRIORITY_HIGHEST),  // highest is negative
192                   static_cast<int>(ANDROID_PRIORITY_LOWEST))) {
193         return Errorf("process priority value must be range {} - {}",
194                       static_cast<int>(ANDROID_PRIORITY_HIGHEST),
195                       static_cast<int>(ANDROID_PRIORITY_LOWEST));
196     }
197     return {};
198 }
199 
ParseInterface(std::vector<std::string> && args)200 Result<void> ServiceParser::ParseInterface(std::vector<std::string>&& args) {
201     const std::string& interface_name = args[1];
202     const std::string& instance_name = args[2];
203     const std::string fullname = interface_name + "/" + instance_name;
204 
205     for (const auto& svc : *service_list_) {
206         if (svc->interfaces().count(fullname) > 0 && !service_->is_override()) {
207             return Error() << "Interface '" << fullname << "' redefined in " << service_->name()
208                            << " but is already defined by " << svc->name();
209         }
210     }
211 
212     service_->interfaces_.insert(fullname);
213 
214     return {};
215 }
216 
ParseIoprio(std::vector<std::string> && args)217 Result<void> ServiceParser::ParseIoprio(std::vector<std::string>&& args) {
218     if (!ParseInt(args[2], &service_->proc_attr_.ioprio_pri, 0, 7)) {
219         return Error() << "priority value must be range 0 - 7";
220     }
221 
222     if (args[1] == "rt") {
223         service_->proc_attr_.ioprio_class = IoSchedClass_RT;
224     } else if (args[1] == "be") {
225         service_->proc_attr_.ioprio_class = IoSchedClass_BE;
226     } else if (args[1] == "idle") {
227         service_->proc_attr_.ioprio_class = IoSchedClass_IDLE;
228     } else {
229         return Error() << "ioprio option usage: ioprio <rt|be|idle> <0-7>";
230     }
231 
232     return {};
233 }
234 
ParseKeycodes(std::vector<std::string> && args)235 Result<void> ServiceParser::ParseKeycodes(std::vector<std::string>&& args) {
236     auto it = args.begin() + 1;
237     if (args.size() == 2 && StartsWith(args[1], "$")) {
238         auto expanded = ExpandProps(args[1]);
239         if (!expanded.ok()) {
240             return expanded.error();
241         }
242 
243         // If the property is not set, it defaults to none, in which case there are no keycodes
244         // for this service.
245         if (*expanded == "none") {
246             return {};
247         }
248 
249         args = Split(*expanded, ",");
250         it = args.begin();
251     }
252 
253     for (; it != args.end(); ++it) {
254         int code;
255         if (ParseInt(*it, &code, 0, KEY_MAX)) {
256             for (auto& key : service_->keycodes_) {
257                 if (key == code) return Error() << "duplicate keycode: " << *it;
258             }
259             service_->keycodes_.insert(
260                     std::upper_bound(service_->keycodes_.begin(), service_->keycodes_.end(), code),
261                     code);
262         } else {
263             return Error() << "invalid keycode: " << *it;
264         }
265     }
266     return {};
267 }
268 
ParseOneshot(std::vector<std::string> && args)269 Result<void> ServiceParser::ParseOneshot(std::vector<std::string>&& args) {
270     service_->flags_ |= SVC_ONESHOT;
271     return {};
272 }
273 
ParseOnrestart(std::vector<std::string> && args)274 Result<void> ServiceParser::ParseOnrestart(std::vector<std::string>&& args) {
275     args.erase(args.begin());
276     int line = service_->onrestart_.NumCommands() + 1;
277     if (auto result = service_->onrestart_.AddCommand(std::move(args), line); !result.ok()) {
278         return Error() << "cannot add Onrestart command: " << result.error();
279     }
280     return {};
281 }
282 
ParseNamespace(std::vector<std::string> && args)283 Result<void> ServiceParser::ParseNamespace(std::vector<std::string>&& args) {
284     for (size_t i = 1; i < args.size(); i++) {
285         if (args[i] == "pid") {
286             service_->namespaces_.flags |= CLONE_NEWPID;
287             // PID namespaces require mount namespaces.
288             service_->namespaces_.flags |= CLONE_NEWNS;
289         } else if (args[i] == "mnt") {
290             service_->namespaces_.flags |= CLONE_NEWNS;
291         } else {
292             return Error() << "namespace must be 'pid' or 'mnt'";
293         }
294     }
295     return {};
296 }
297 
ParseOomScoreAdjust(std::vector<std::string> && args)298 Result<void> ServiceParser::ParseOomScoreAdjust(std::vector<std::string>&& args) {
299     if (!ParseInt(args[1], &service_->oom_score_adjust_, MIN_OOM_SCORE_ADJUST,
300                   MAX_OOM_SCORE_ADJUST)) {
301         return Error() << "oom_score_adjust value must be in range " << MIN_OOM_SCORE_ADJUST
302                        << " - +" << MAX_OOM_SCORE_ADJUST;
303     }
304     return {};
305 }
306 
ParseOverride(std::vector<std::string> && args)307 Result<void> ServiceParser::ParseOverride(std::vector<std::string>&& args) {
308     service_->override_ = true;
309     return {};
310 }
311 
ParseSharedKallsyms(std::vector<std::string> && args)312 Result<void> ServiceParser::ParseSharedKallsyms(std::vector<std::string>&& args) {
313     service_->shared_kallsyms_file_ = true;
314     return {};
315 }
316 
ParseMemcgSwappiness(std::vector<std::string> && args)317 Result<void> ServiceParser::ParseMemcgSwappiness(std::vector<std::string>&& args) {
318     LOG(WARNING) << "memcg.swappiness is unsupported with memcg v2 and will be deprecated";
319     if (!ParseInt(args[1], &service_->swappiness_, 0)) {
320         return Error() << "swappiness value must be equal or greater than 0";
321     }
322     return {};
323 }
324 
ParseMemcgLimitInBytes(std::vector<std::string> && args)325 Result<void> ServiceParser::ParseMemcgLimitInBytes(std::vector<std::string>&& args) {
326     if (!ParseInt(args[1], &service_->limit_in_bytes_, 0)) {
327         return Error() << "limit_in_bytes value must be equal or greater than 0";
328     }
329     return {};
330 }
331 
ParseMemcgLimitPercent(std::vector<std::string> && args)332 Result<void> ServiceParser::ParseMemcgLimitPercent(std::vector<std::string>&& args) {
333     if (!ParseInt(args[1], &service_->limit_percent_, 0)) {
334         return Error() << "limit_percent value must be equal or greater than 0";
335     }
336     return {};
337 }
338 
ParseMemcgLimitProperty(std::vector<std::string> && args)339 Result<void> ServiceParser::ParseMemcgLimitProperty(std::vector<std::string>&& args) {
340     service_->limit_property_ = std::move(args[1]);
341     return {};
342 }
343 
ParseMemcgSoftLimitInBytes(std::vector<std::string> && args)344 Result<void> ServiceParser::ParseMemcgSoftLimitInBytes(std::vector<std::string>&& args) {
345     if (!ParseInt(args[1], &service_->soft_limit_in_bytes_, 0)) {
346         return Error() << "soft_limit_in_bytes value must be equal or greater than 0";
347     }
348     return {};
349 }
350 
ParseProcessRlimit(std::vector<std::string> && args)351 Result<void> ServiceParser::ParseProcessRlimit(std::vector<std::string>&& args) {
352     auto rlimit = ParseRlimit(args);
353     if (!rlimit.ok()) return rlimit.error();
354 
355     service_->proc_attr_.rlimits.emplace_back(*rlimit);
356     return {};
357 }
358 
ParseRebootOnFailure(std::vector<std::string> && args)359 Result<void> ServiceParser::ParseRebootOnFailure(std::vector<std::string>&& args) {
360     if (service_->on_failure_reboot_target_) {
361         return Error() << "Only one reboot_on_failure command may be specified";
362     }
363     if (!StartsWith(args[1], "shutdown") && !StartsWith(args[1], "reboot")) {
364         return Error()
365                << "reboot_on_failure commands must begin with either 'shutdown' or 'reboot'";
366     }
367     service_->on_failure_reboot_target_ = std::move(args[1]);
368     return {};
369 }
370 
ParseRestartPeriod(std::vector<std::string> && args)371 Result<void> ServiceParser::ParseRestartPeriod(std::vector<std::string>&& args) {
372     int period;
373     if (!ParseInt(args[1], &period, 0)) {
374         return Error() << "restart_period value must be an integer >= 0";
375     }
376     service_->restart_period_ = std::chrono::seconds(period);
377     return {};
378 }
379 
ParseSeclabel(std::vector<std::string> && args)380 Result<void> ServiceParser::ParseSeclabel(std::vector<std::string>&& args) {
381     service_->seclabel_ = std::move(args[1]);
382     return {};
383 }
384 
ParseSigstop(std::vector<std::string> && args)385 Result<void> ServiceParser::ParseSigstop(std::vector<std::string>&& args) {
386     service_->sigstop_ = true;
387     return {};
388 }
389 
ParseSetenv(std::vector<std::string> && args)390 Result<void> ServiceParser::ParseSetenv(std::vector<std::string>&& args) {
391     service_->environment_vars_.emplace_back(std::move(args[1]), std::move(args[2]));
392     return {};
393 }
394 
ParseShutdown(std::vector<std::string> && args)395 Result<void> ServiceParser::ParseShutdown(std::vector<std::string>&& args) {
396     if (args[1] == "critical") {
397         service_->flags_ |= SVC_SHUTDOWN_CRITICAL;
398         return {};
399     }
400     return Error() << "Invalid shutdown option";
401 }
402 
ParseTaskProfiles(std::vector<std::string> && args)403 Result<void> ServiceParser::ParseTaskProfiles(std::vector<std::string>&& args) {
404     args.erase(args.begin());
405     if (service_->task_profiles_.empty()) {
406         service_->task_profiles_ = std::move(args);
407     } else {
408         // Some task profiles might have been added during writepid conversions
409         service_->task_profiles_.insert(service_->task_profiles_.end(),
410                                         std::make_move_iterator(args.begin()),
411                                         std::make_move_iterator(args.end()));
412         args.clear();
413     }
414     return {};
415 }
416 
ParseTimeoutPeriod(std::vector<std::string> && args)417 Result<void> ServiceParser::ParseTimeoutPeriod(std::vector<std::string>&& args) {
418     int period;
419     if (!ParseInt(args[1], &period, 1)) {
420         return Error() << "timeout_period value must be an integer >= 1";
421     }
422     service_->timeout_period_ = std::chrono::seconds(period);
423     return {};
424 }
425 
426 // name type perm [ uid gid context ]
ParseSocket(std::vector<std::string> && args)427 Result<void> ServiceParser::ParseSocket(std::vector<std::string>&& args) {
428     SocketDescriptor socket;
429     socket.name = std::move(args[1]);
430 
431     auto types = Split(args[2], "+");
432     if (types[0] == "stream") {
433         socket.type = SOCK_STREAM;
434     } else if (types[0] == "dgram") {
435         socket.type = SOCK_DGRAM;
436     } else if (types[0] == "seqpacket") {
437         socket.type = SOCK_SEQPACKET;
438     } else {
439         return Error() << "socket type must be 'dgram', 'stream' or 'seqpacket', got '" << types[0]
440                        << "' instead.";
441     }
442 
443     for (size_t i = 1; i < types.size(); i++) {
444         if (types[i] == "passcred") {
445             socket.passcred = true;
446         } else if (types[i] == "listen") {
447             socket.listen = true;
448         } else {
449             return Error() << "Unknown socket type decoration '" << types[i]
450                            << "'. Known values are ['passcred', 'listen']";
451         }
452     }
453 
454     errno = 0;
455     char* end = nullptr;
456     socket.perm = strtol(args[3].c_str(), &end, 8);
457     if (errno != 0) {
458         return ErrnoError() << "Unable to parse permissions '" << args[3] << "'";
459     }
460     if (end == args[3].c_str() || *end != '\0') {
461         errno = EINVAL;
462         return ErrnoError() << "Unable to parse permissions '" << args[3] << "'";
463     }
464 
465     if (args.size() > 4) {
466         auto uid = DecodeUid(args[4]);
467         if (!uid.ok()) {
468             return Error() << "Unable to find UID for '" << args[4] << "': " << uid.error();
469         }
470         socket.uid = *uid;
471     }
472 
473     if (args.size() > 5) {
474         auto gid = DecodeUid(args[5]);
475         if (!gid.ok()) {
476             return Error() << "Unable to find GID for '" << args[5] << "': " << gid.error();
477         }
478         socket.gid = *gid;
479     }
480 
481     socket.context = args.size() > 6 ? args[6] : "";
482 
483     auto old = std::find_if(service_->sockets_.begin(), service_->sockets_.end(),
484                             [&socket](const auto& other) { return socket.name == other.name; });
485 
486     if (old != service_->sockets_.end()) {
487         return Error() << "duplicate socket descriptor '" << socket.name << "'";
488     }
489 
490     service_->sockets_.emplace_back(std::move(socket));
491 
492     return {};
493 }
494 
ParseStdioToKmsg(std::vector<std::string> && args)495 Result<void> ServiceParser::ParseStdioToKmsg(std::vector<std::string>&& args) {
496     if (service_->flags_ & SVC_CONSOLE) {
497         return Error() << "'stdio_to_kmsg' and 'console' are mutually exclusive";
498     }
499     service_->proc_attr_.stdio_to_kmsg = true;
500     return {};
501 }
502 
503 // name type
ParseFile(std::vector<std::string> && args)504 Result<void> ServiceParser::ParseFile(std::vector<std::string>&& args) {
505     if (args[2] != "r" && args[2] != "w" && args[2] != "rw") {
506         return Error() << "file type must be 'r', 'w' or 'rw'";
507     }
508 
509     FileDescriptor file;
510     file.type = args[2];
511 
512     auto file_name = ExpandProps(args[1]);
513     if (!file_name.ok()) {
514         return Error() << "Could not expand file path ': " << file_name.error();
515     }
516     file.name = *file_name;
517     if (file.name[0] != '/' || file.name.find("../") != std::string::npos) {
518         return Error() << "file name must not be relative";
519     }
520 
521     auto old = std::find_if(service_->files_.begin(), service_->files_.end(),
522                             [&file](const auto& other) { return other.name == file.name; });
523 
524     if (old != service_->files_.end()) {
525         return Error() << "duplicate file descriptor '" << file.name << "'";
526     }
527 
528     service_->files_.emplace_back(std::move(file));
529 
530     return {};
531 }
532 
ParseUser(std::vector<std::string> && args)533 Result<void> ServiceParser::ParseUser(std::vector<std::string>&& args) {
534     auto uid = DecodeUid(args[1]);
535     if (!uid.ok()) {
536         return Error() << "Unable to find UID for '" << args[1] << "': " << uid.error();
537     }
538     service_->proc_attr_.parsed_uid = *uid;
539     return {};
540 }
541 
542 // Convert legacy paths used to migrate processes between cgroups using writepid command.
543 // We can't get these paths from TaskProfiles because profile definitions are changing
544 // when we migrate to cgroups v2 while these hardcoded paths stay the same.
ConvertTaskFileToProfile(const std::string & file)545 static std::optional<const std::string> ConvertTaskFileToProfile(const std::string& file) {
546     static const std::map<const std::string, const std::string> map = {
547             {"/dev/cpuset/camera-daemon/tasks", "CameraServiceCapacity"},
548             {"/dev/cpuset/foreground/tasks", "ProcessCapacityHigh"},
549             {"/dev/cpuset/system-background/tasks", "ServiceCapacityLow"},
550             {"/dev/blkio/background/tasks", "LowIoPriority"},
551     };
552     auto iter = map.find(file);
553     return iter == map.end() ? std::nullopt : std::make_optional<const std::string>(iter->second);
554 }
555 
ParseWritepid(std::vector<std::string> && args)556 Result<void> ServiceParser::ParseWritepid(std::vector<std::string>&& args) {
557     args.erase(args.begin());
558     // Convert any cgroup writes into appropriate task_profiles
559     for (auto iter = args.begin(); iter != args.end();) {
560         auto task_profile = ConvertTaskFileToProfile(*iter);
561         if (task_profile) {
562             LOG(WARNING) << "'writepid " << *iter << "' is converted into 'task_profiles "
563                          << task_profile.value() << "' for service " << service_->name();
564             service_->task_profiles_.push_back(task_profile.value());
565             iter = args.erase(iter);
566         } else {
567             ++iter;
568         }
569     }
570     service_->writepid_files_ = std::move(args);
571     return {};
572 }
573 
ParseUpdatable(std::vector<std::string> && args)574 Result<void> ServiceParser::ParseUpdatable(std::vector<std::string>&& args) {
575     service_->updatable_ = true;
576     return {};
577 }
578 
GetParserMap() const579 const KeywordMap<ServiceParser::OptionParser>& ServiceParser::GetParserMap() const {
580     constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
581     // clang-format off
582     static const KeywordMap<ServiceParser::OptionParser> parser_map = {
583         {"capabilities",            {0,     kMax, &ServiceParser::ParseCapabilities}},
584         {"class",                   {1,     kMax, &ServiceParser::ParseClass}},
585         {"console",                 {0,     1,    &ServiceParser::ParseConsole}},
586         {"critical",                {0,     2,    &ServiceParser::ParseCritical}},
587         {"disabled",                {0,     0,    &ServiceParser::ParseDisabled}},
588         {"enter_namespace",         {2,     2,    &ServiceParser::ParseEnterNamespace}},
589         {"file",                    {2,     2,    &ServiceParser::ParseFile}},
590         {"gentle_kill",             {0,     0,    &ServiceParser::ParseGentleKill}},
591         {"group",                   {1,     NR_SVC_SUPP_GIDS + 1, &ServiceParser::ParseGroup}},
592         {"interface",               {2,     2,    &ServiceParser::ParseInterface}},
593         {"ioprio",                  {2,     2,    &ServiceParser::ParseIoprio}},
594         {"keycodes",                {1,     kMax, &ServiceParser::ParseKeycodes}},
595         {"memcg.limit_in_bytes",    {1,     1,    &ServiceParser::ParseMemcgLimitInBytes}},
596         {"memcg.limit_percent",     {1,     1,    &ServiceParser::ParseMemcgLimitPercent}},
597         {"memcg.limit_property",    {1,     1,    &ServiceParser::ParseMemcgLimitProperty}},
598         {"memcg.soft_limit_in_bytes",
599                                     {1,     1,    &ServiceParser::ParseMemcgSoftLimitInBytes}},
600         {"memcg.swappiness",        {1,     1,    &ServiceParser::ParseMemcgSwappiness}},
601         {"namespace",               {1,     2,    &ServiceParser::ParseNamespace}},
602         {"oneshot",                 {0,     0,    &ServiceParser::ParseOneshot}},
603         {"onrestart",               {1,     kMax, &ServiceParser::ParseOnrestart}},
604         {"oom_score_adjust",        {1,     1,    &ServiceParser::ParseOomScoreAdjust}},
605         {"override",                {0,     0,    &ServiceParser::ParseOverride}},
606         {"priority",                {1,     1,    &ServiceParser::ParsePriority}},
607         {"reboot_on_failure",       {1,     1,    &ServiceParser::ParseRebootOnFailure}},
608         {"restart_period",          {1,     1,    &ServiceParser::ParseRestartPeriod}},
609         {"rlimit",                  {3,     3,    &ServiceParser::ParseProcessRlimit}},
610         {"seclabel",                {1,     1,    &ServiceParser::ParseSeclabel}},
611         {"setenv",                  {2,     2,    &ServiceParser::ParseSetenv}},
612         {"shared_kallsyms",         {0,     0,    &ServiceParser::ParseSharedKallsyms}},
613         {"shutdown",                {1,     1,    &ServiceParser::ParseShutdown}},
614         {"sigstop",                 {0,     0,    &ServiceParser::ParseSigstop}},
615         {"socket",                  {3,     6,    &ServiceParser::ParseSocket}},
616         {"stdio_to_kmsg",           {0,     0,    &ServiceParser::ParseStdioToKmsg}},
617         {"task_profiles",           {1,     kMax, &ServiceParser::ParseTaskProfiles}},
618         {"timeout_period",          {1,     1,    &ServiceParser::ParseTimeoutPeriod}},
619         {"updatable",               {0,     0,    &ServiceParser::ParseUpdatable}},
620         {"user",                    {1,     1,    &ServiceParser::ParseUser}},
621         {"writepid",                {1,     kMax, &ServiceParser::ParseWritepid}},
622     };
623     // clang-format on
624     return parser_map;
625 }
626 
ParseSection(std::vector<std::string> && args,const std::string & filename,int line)627 Result<void> ServiceParser::ParseSection(std::vector<std::string>&& args,
628                                          const std::string& filename, int line) {
629     if (args.size() < 3) {
630         return Error() << "services must have a name and a program";
631     }
632 
633     const std::string& name = args[1];
634     if (!IsValidName(name)) {
635         return Error() << "invalid service name '" << name << "'";
636     }
637 
638     filename_ = filename;
639 
640     Subcontext* restart_action_subcontext = nullptr;
641     if (subcontext_ && subcontext_->PathMatchesSubcontext(filename)) {
642         restart_action_subcontext = subcontext_;
643     }
644 
645     std::vector<std::string> str_args(args.begin() + 2, args.end());
646 
647     if (SelinuxGetVendorAndroidVersion() <= __ANDROID_API_P__) {
648         if (str_args[0] == "/sbin/watchdogd") {
649             str_args[0] = "/system/bin/watchdogd";
650         }
651     }
652     if (SelinuxGetVendorAndroidVersion() <= __ANDROID_API_Q__) {
653         if (str_args[0] == "/charger") {
654             str_args[0] = "/system/bin/charger";
655         }
656     }
657 
658     service_ = std::make_unique<Service>(name, restart_action_subcontext, filename, str_args);
659     return {};
660 }
661 
ParseLineSection(std::vector<std::string> && args,int line)662 Result<void> ServiceParser::ParseLineSection(std::vector<std::string>&& args, int line) {
663     if (!service_) {
664         return {};
665     }
666 
667     auto parser = GetParserMap().Find(args);
668 
669     if (!parser.ok()) return parser.error();
670 
671     return std::invoke(*parser, this, std::move(args));
672 }
673 
EndSection()674 Result<void> ServiceParser::EndSection() {
675     if (!service_) {
676         return {};
677     }
678 
679     if (service_->proc_attr_.parsed_uid == std::nullopt) {
680         if (kAlwaysErrorUserRoot ||
681             android::base::GetIntProperty("ro.vendor.api_level", 0) > 202404) {
682             return Error() << "No user specified for service '" << service_->name()
683                            << "', so it would have been root.";
684         } else {
685             LOG(WARNING) << "No user specified for service '" << service_->name()
686                          << "', so it is root.";
687         }
688     }
689 
690     if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_R__) {
691         if ((service_->flags() & SVC_CRITICAL) != 0 && (service_->flags() & SVC_ONESHOT) != 0) {
692             return Error() << "service '" << service_->name()
693                            << "' can't be both critical and oneshot";
694         }
695     }
696 
697     Service* old_service = service_list_->FindService(service_->name());
698     if (old_service) {
699         if (!service_->is_override()) {
700             return Error() << "ignored duplicate definition of service '" << service_->name()
701                            << "'";
702         }
703 
704         if (StartsWith(filename_, "/apex/") && !old_service->is_updatable()) {
705             return Error() << "cannot update a non-updatable service '" << service_->name()
706                            << "' with a config in APEX";
707         }
708 
709         std::string context = service_->subcontext() ? service_->subcontext()->context() : "";
710         std::string old_context =
711                 old_service->subcontext() ? old_service->subcontext()->context() : "";
712         if (context != old_context) {
713             return Error() << "service '" << service_->name() << "' overrides another service "
714                            << "across the treble boundary.";
715         }
716 
717         service_list_->RemoveService(*old_service);
718         old_service = nullptr;
719     }
720 
721     service_list_->AddService(std::move(service_));
722 
723     return {};
724 }
725 
IsValidName(const std::string & name) const726 bool ServiceParser::IsValidName(const std::string& name) const {
727     // Property names can be any length, but may only contain certain characters.
728     // Property values can contain any characters, but may only be a certain length.
729     // (The latter restriction is needed because `start` and `stop` work by writing
730     // the service name to the "ctl.start" and "ctl.stop" properties.)
731     return IsLegalPropertyName("init.svc." + name) && name.size() <= PROP_VALUE_MAX;
732 }
733 
734 }  // namespace init
735 }  // namespace android
736