xref: /aosp_15_r20/system/core/init/service_parser.cpp (revision 00c7fec1bb09f3284aad6a6f96d2f63dfc3650ad)
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 
ParseMemcgSwappiness(std::vector<std::string> && args)312 Result<void> ServiceParser::ParseMemcgSwappiness(std::vector<std::string>&& args) {
313     if (!ParseInt(args[1], &service_->swappiness_, 0)) {
314         return Error() << "swappiness value must be equal or greater than 0";
315     }
316     return {};
317 }
318 
ParseMemcgLimitInBytes(std::vector<std::string> && args)319 Result<void> ServiceParser::ParseMemcgLimitInBytes(std::vector<std::string>&& args) {
320     if (!ParseInt(args[1], &service_->limit_in_bytes_, 0)) {
321         return Error() << "limit_in_bytes value must be equal or greater than 0";
322     }
323     return {};
324 }
325 
ParseMemcgLimitPercent(std::vector<std::string> && args)326 Result<void> ServiceParser::ParseMemcgLimitPercent(std::vector<std::string>&& args) {
327     if (!ParseInt(args[1], &service_->limit_percent_, 0)) {
328         return Error() << "limit_percent value must be equal or greater than 0";
329     }
330     return {};
331 }
332 
ParseMemcgLimitProperty(std::vector<std::string> && args)333 Result<void> ServiceParser::ParseMemcgLimitProperty(std::vector<std::string>&& args) {
334     service_->limit_property_ = std::move(args[1]);
335     return {};
336 }
337 
ParseMemcgSoftLimitInBytes(std::vector<std::string> && args)338 Result<void> ServiceParser::ParseMemcgSoftLimitInBytes(std::vector<std::string>&& args) {
339     if (!ParseInt(args[1], &service_->soft_limit_in_bytes_, 0)) {
340         return Error() << "soft_limit_in_bytes value must be equal or greater than 0";
341     }
342     return {};
343 }
344 
ParseProcessRlimit(std::vector<std::string> && args)345 Result<void> ServiceParser::ParseProcessRlimit(std::vector<std::string>&& args) {
346     auto rlimit = ParseRlimit(args);
347     if (!rlimit.ok()) return rlimit.error();
348 
349     service_->proc_attr_.rlimits.emplace_back(*rlimit);
350     return {};
351 }
352 
ParseRebootOnFailure(std::vector<std::string> && args)353 Result<void> ServiceParser::ParseRebootOnFailure(std::vector<std::string>&& args) {
354     if (service_->on_failure_reboot_target_) {
355         return Error() << "Only one reboot_on_failure command may be specified";
356     }
357     if (!StartsWith(args[1], "shutdown") && !StartsWith(args[1], "reboot")) {
358         return Error()
359                << "reboot_on_failure commands must begin with either 'shutdown' or 'reboot'";
360     }
361     service_->on_failure_reboot_target_ = std::move(args[1]);
362     return {};
363 }
364 
ParseRestartPeriod(std::vector<std::string> && args)365 Result<void> ServiceParser::ParseRestartPeriod(std::vector<std::string>&& args) {
366     int period;
367     if (!ParseInt(args[1], &period, 0)) {
368         return Error() << "restart_period value must be an integer >= 0";
369     }
370     service_->restart_period_ = std::chrono::seconds(period);
371     return {};
372 }
373 
ParseSeclabel(std::vector<std::string> && args)374 Result<void> ServiceParser::ParseSeclabel(std::vector<std::string>&& args) {
375     service_->seclabel_ = std::move(args[1]);
376     return {};
377 }
378 
ParseSigstop(std::vector<std::string> && args)379 Result<void> ServiceParser::ParseSigstop(std::vector<std::string>&& args) {
380     service_->sigstop_ = true;
381     return {};
382 }
383 
ParseSetenv(std::vector<std::string> && args)384 Result<void> ServiceParser::ParseSetenv(std::vector<std::string>&& args) {
385     service_->environment_vars_.emplace_back(std::move(args[1]), std::move(args[2]));
386     return {};
387 }
388 
ParseShutdown(std::vector<std::string> && args)389 Result<void> ServiceParser::ParseShutdown(std::vector<std::string>&& args) {
390     if (args[1] == "critical") {
391         service_->flags_ |= SVC_SHUTDOWN_CRITICAL;
392         return {};
393     }
394     return Error() << "Invalid shutdown option";
395 }
396 
ParseTaskProfiles(std::vector<std::string> && args)397 Result<void> ServiceParser::ParseTaskProfiles(std::vector<std::string>&& args) {
398     args.erase(args.begin());
399     if (service_->task_profiles_.empty()) {
400         service_->task_profiles_ = std::move(args);
401     } else {
402         // Some task profiles might have been added during writepid conversions
403         service_->task_profiles_.insert(service_->task_profiles_.end(),
404                                         std::make_move_iterator(args.begin()),
405                                         std::make_move_iterator(args.end()));
406         args.clear();
407     }
408     return {};
409 }
410 
ParseTimeoutPeriod(std::vector<std::string> && args)411 Result<void> ServiceParser::ParseTimeoutPeriod(std::vector<std::string>&& args) {
412     int period;
413     if (!ParseInt(args[1], &period, 1)) {
414         return Error() << "timeout_period value must be an integer >= 1";
415     }
416     service_->timeout_period_ = std::chrono::seconds(period);
417     return {};
418 }
419 
420 // name type perm [ uid gid context ]
ParseSocket(std::vector<std::string> && args)421 Result<void> ServiceParser::ParseSocket(std::vector<std::string>&& args) {
422     SocketDescriptor socket;
423     socket.name = std::move(args[1]);
424 
425     auto types = Split(args[2], "+");
426     if (types[0] == "stream") {
427         socket.type = SOCK_STREAM;
428     } else if (types[0] == "dgram") {
429         socket.type = SOCK_DGRAM;
430     } else if (types[0] == "seqpacket") {
431         socket.type = SOCK_SEQPACKET;
432     } else {
433         return Error() << "socket type must be 'dgram', 'stream' or 'seqpacket', got '" << types[0]
434                        << "' instead.";
435     }
436 
437     for (size_t i = 1; i < types.size(); i++) {
438         if (types[i] == "passcred") {
439             socket.passcred = true;
440         } else if (types[i] == "listen") {
441             socket.listen = true;
442         } else {
443             return Error() << "Unknown socket type decoration '" << types[i]
444                            << "'. Known values are ['passcred', 'listen']";
445         }
446     }
447 
448     errno = 0;
449     char* end = nullptr;
450     socket.perm = strtol(args[3].c_str(), &end, 8);
451     if (errno != 0) {
452         return ErrnoError() << "Unable to parse permissions '" << args[3] << "'";
453     }
454     if (end == args[3].c_str() || *end != '\0') {
455         errno = EINVAL;
456         return ErrnoError() << "Unable to parse permissions '" << args[3] << "'";
457     }
458 
459     if (args.size() > 4) {
460         auto uid = DecodeUid(args[4]);
461         if (!uid.ok()) {
462             return Error() << "Unable to find UID for '" << args[4] << "': " << uid.error();
463         }
464         socket.uid = *uid;
465     }
466 
467     if (args.size() > 5) {
468         auto gid = DecodeUid(args[5]);
469         if (!gid.ok()) {
470             return Error() << "Unable to find GID for '" << args[5] << "': " << gid.error();
471         }
472         socket.gid = *gid;
473     }
474 
475     socket.context = args.size() > 6 ? args[6] : "";
476 
477     auto old = std::find_if(service_->sockets_.begin(), service_->sockets_.end(),
478                             [&socket](const auto& other) { return socket.name == other.name; });
479 
480     if (old != service_->sockets_.end()) {
481         return Error() << "duplicate socket descriptor '" << socket.name << "'";
482     }
483 
484     service_->sockets_.emplace_back(std::move(socket));
485 
486     return {};
487 }
488 
ParseStdioToKmsg(std::vector<std::string> && args)489 Result<void> ServiceParser::ParseStdioToKmsg(std::vector<std::string>&& args) {
490     if (service_->flags_ & SVC_CONSOLE) {
491         return Error() << "'stdio_to_kmsg' and 'console' are mutually exclusive";
492     }
493     service_->proc_attr_.stdio_to_kmsg = true;
494     return {};
495 }
496 
497 // name type
ParseFile(std::vector<std::string> && args)498 Result<void> ServiceParser::ParseFile(std::vector<std::string>&& args) {
499     if (args[2] != "r" && args[2] != "w" && args[2] != "rw") {
500         return Error() << "file type must be 'r', 'w' or 'rw'";
501     }
502 
503     FileDescriptor file;
504     file.type = args[2];
505 
506     auto file_name = ExpandProps(args[1]);
507     if (!file_name.ok()) {
508         return Error() << "Could not expand file path ': " << file_name.error();
509     }
510     file.name = *file_name;
511     if (file.name[0] != '/' || file.name.find("../") != std::string::npos) {
512         return Error() << "file name must not be relative";
513     }
514 
515     auto old = std::find_if(service_->files_.begin(), service_->files_.end(),
516                             [&file](const auto& other) { return other.name == file.name; });
517 
518     if (old != service_->files_.end()) {
519         return Error() << "duplicate file descriptor '" << file.name << "'";
520     }
521 
522     service_->files_.emplace_back(std::move(file));
523 
524     return {};
525 }
526 
ParseUser(std::vector<std::string> && args)527 Result<void> ServiceParser::ParseUser(std::vector<std::string>&& args) {
528     auto uid = DecodeUid(args[1]);
529     if (!uid.ok()) {
530         return Error() << "Unable to find UID for '" << args[1] << "': " << uid.error();
531     }
532     service_->proc_attr_.parsed_uid = *uid;
533     return {};
534 }
535 
536 // Convert legacy paths used to migrate processes between cgroups using writepid command.
537 // We can't get these paths from TaskProfiles because profile definitions are changing
538 // when we migrate to cgroups v2 while these hardcoded paths stay the same.
ConvertTaskFileToProfile(const std::string & file)539 static std::optional<const std::string> ConvertTaskFileToProfile(const std::string& file) {
540     static const std::map<const std::string, const std::string> map = {
541             {"/dev/cpuset/camera-daemon/tasks", "CameraServiceCapacity"},
542             {"/dev/cpuset/foreground/tasks", "ProcessCapacityHigh"},
543             {"/dev/cpuset/system-background/tasks", "ServiceCapacityLow"},
544             {"/dev/blkio/background/tasks", "LowIoPriority"},
545     };
546     auto iter = map.find(file);
547     return iter == map.end() ? std::nullopt : std::make_optional<const std::string>(iter->second);
548 }
549 
ParseWritepid(std::vector<std::string> && args)550 Result<void> ServiceParser::ParseWritepid(std::vector<std::string>&& args) {
551     args.erase(args.begin());
552     // Convert any cgroup writes into appropriate task_profiles
553     for (auto iter = args.begin(); iter != args.end();) {
554         auto task_profile = ConvertTaskFileToProfile(*iter);
555         if (task_profile) {
556             LOG(WARNING) << "'writepid " << *iter << "' is converted into 'task_profiles "
557                          << task_profile.value() << "' for service " << service_->name();
558             service_->task_profiles_.push_back(task_profile.value());
559             iter = args.erase(iter);
560         } else {
561             ++iter;
562         }
563     }
564     service_->writepid_files_ = std::move(args);
565     return {};
566 }
567 
ParseUpdatable(std::vector<std::string> && args)568 Result<void> ServiceParser::ParseUpdatable(std::vector<std::string>&& args) {
569     service_->updatable_ = true;
570     return {};
571 }
572 
GetParserMap() const573 const KeywordMap<ServiceParser::OptionParser>& ServiceParser::GetParserMap() const {
574     constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
575     // clang-format off
576     static const KeywordMap<ServiceParser::OptionParser> parser_map = {
577         {"capabilities",            {0,     kMax, &ServiceParser::ParseCapabilities}},
578         {"class",                   {1,     kMax, &ServiceParser::ParseClass}},
579         {"console",                 {0,     1,    &ServiceParser::ParseConsole}},
580         {"critical",                {0,     2,    &ServiceParser::ParseCritical}},
581         {"disabled",                {0,     0,    &ServiceParser::ParseDisabled}},
582         {"enter_namespace",         {2,     2,    &ServiceParser::ParseEnterNamespace}},
583         {"file",                    {2,     2,    &ServiceParser::ParseFile}},
584         {"gentle_kill",             {0,     0,    &ServiceParser::ParseGentleKill}},
585         {"group",                   {1,     NR_SVC_SUPP_GIDS + 1, &ServiceParser::ParseGroup}},
586         {"interface",               {2,     2,    &ServiceParser::ParseInterface}},
587         {"ioprio",                  {2,     2,    &ServiceParser::ParseIoprio}},
588         {"keycodes",                {1,     kMax, &ServiceParser::ParseKeycodes}},
589         {"memcg.limit_in_bytes",    {1,     1,    &ServiceParser::ParseMemcgLimitInBytes}},
590         {"memcg.limit_percent",     {1,     1,    &ServiceParser::ParseMemcgLimitPercent}},
591         {"memcg.limit_property",    {1,     1,    &ServiceParser::ParseMemcgLimitProperty}},
592         {"memcg.soft_limit_in_bytes",
593                                     {1,     1,    &ServiceParser::ParseMemcgSoftLimitInBytes}},
594         {"memcg.swappiness",        {1,     1,    &ServiceParser::ParseMemcgSwappiness}},
595         {"namespace",               {1,     2,    &ServiceParser::ParseNamespace}},
596         {"oneshot",                 {0,     0,    &ServiceParser::ParseOneshot}},
597         {"onrestart",               {1,     kMax, &ServiceParser::ParseOnrestart}},
598         {"oom_score_adjust",        {1,     1,    &ServiceParser::ParseOomScoreAdjust}},
599         {"override",                {0,     0,    &ServiceParser::ParseOverride}},
600         {"priority",                {1,     1,    &ServiceParser::ParsePriority}},
601         {"reboot_on_failure",       {1,     1,    &ServiceParser::ParseRebootOnFailure}},
602         {"restart_period",          {1,     1,    &ServiceParser::ParseRestartPeriod}},
603         {"rlimit",                  {3,     3,    &ServiceParser::ParseProcessRlimit}},
604         {"seclabel",                {1,     1,    &ServiceParser::ParseSeclabel}},
605         {"setenv",                  {2,     2,    &ServiceParser::ParseSetenv}},
606         {"shutdown",                {1,     1,    &ServiceParser::ParseShutdown}},
607         {"sigstop",                 {0,     0,    &ServiceParser::ParseSigstop}},
608         {"socket",                  {3,     6,    &ServiceParser::ParseSocket}},
609         {"stdio_to_kmsg",           {0,     0,    &ServiceParser::ParseStdioToKmsg}},
610         {"task_profiles",           {1,     kMax, &ServiceParser::ParseTaskProfiles}},
611         {"timeout_period",          {1,     1,    &ServiceParser::ParseTimeoutPeriod}},
612         {"updatable",               {0,     0,    &ServiceParser::ParseUpdatable}},
613         {"user",                    {1,     1,    &ServiceParser::ParseUser}},
614         {"writepid",                {1,     kMax, &ServiceParser::ParseWritepid}},
615     };
616     // clang-format on
617     return parser_map;
618 }
619 
ParseSection(std::vector<std::string> && args,const std::string & filename,int line)620 Result<void> ServiceParser::ParseSection(std::vector<std::string>&& args,
621                                          const std::string& filename, int line) {
622     if (args.size() < 3) {
623         return Error() << "services must have a name and a program";
624     }
625 
626     const std::string& name = args[1];
627     if (!IsValidName(name)) {
628         return Error() << "invalid service name '" << name << "'";
629     }
630 
631     filename_ = filename;
632 
633     Subcontext* restart_action_subcontext = nullptr;
634     if (subcontext_ && subcontext_->PathMatchesSubcontext(filename)) {
635         restart_action_subcontext = subcontext_;
636     }
637 
638     std::vector<std::string> str_args(args.begin() + 2, args.end());
639 
640     if (SelinuxGetVendorAndroidVersion() <= __ANDROID_API_P__) {
641         if (str_args[0] == "/sbin/watchdogd") {
642             str_args[0] = "/system/bin/watchdogd";
643         }
644     }
645     if (SelinuxGetVendorAndroidVersion() <= __ANDROID_API_Q__) {
646         if (str_args[0] == "/charger") {
647             str_args[0] = "/system/bin/charger";
648         }
649     }
650 
651     service_ = std::make_unique<Service>(name, restart_action_subcontext, filename, str_args);
652     return {};
653 }
654 
ParseLineSection(std::vector<std::string> && args,int line)655 Result<void> ServiceParser::ParseLineSection(std::vector<std::string>&& args, int line) {
656     if (!service_) {
657         return {};
658     }
659 
660     auto parser = GetParserMap().Find(args);
661 
662     if (!parser.ok()) return parser.error();
663 
664     return std::invoke(*parser, this, std::move(args));
665 }
666 
EndSection()667 Result<void> ServiceParser::EndSection() {
668     if (!service_) {
669         return {};
670     }
671 
672     if (service_->proc_attr_.parsed_uid == std::nullopt) {
673         if (kAlwaysErrorUserRoot ||
674             android::base::GetIntProperty("ro.vendor.api_level", 0) > 202404) {
675             return Error() << "No user specified for service '" << service_->name()
676                            << "', so it would have been root.";
677         } else {
678             LOG(WARNING) << "No user specified for service '" << service_->name()
679                          << "', so it is root.";
680         }
681     }
682 
683     if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_R__) {
684         if ((service_->flags() & SVC_CRITICAL) != 0 && (service_->flags() & SVC_ONESHOT) != 0) {
685             return Error() << "service '" << service_->name()
686                            << "' can't be both critical and oneshot";
687         }
688     }
689 
690     Service* old_service = service_list_->FindService(service_->name());
691     if (old_service) {
692         if (!service_->is_override()) {
693             return Error() << "ignored duplicate definition of service '" << service_->name()
694                            << "'";
695         }
696 
697         if (StartsWith(filename_, "/apex/") && !old_service->is_updatable()) {
698             return Error() << "cannot update a non-updatable service '" << service_->name()
699                            << "' with a config in APEX";
700         }
701 
702         std::string context = service_->subcontext() ? service_->subcontext()->context() : "";
703         std::string old_context =
704                 old_service->subcontext() ? old_service->subcontext()->context() : "";
705         if (context != old_context) {
706             return Error() << "service '" << service_->name() << "' overrides another service "
707                            << "across the treble boundary.";
708         }
709 
710         service_list_->RemoveService(*old_service);
711         old_service = nullptr;
712     }
713 
714     service_list_->AddService(std::move(service_));
715 
716     return {};
717 }
718 
IsValidName(const std::string & name) const719 bool ServiceParser::IsValidName(const std::string& name) const {
720     // Property names can be any length, but may only contain certain characters.
721     // Property values can contain any characters, but may only be a certain length.
722     // (The latter restriction is needed because `start` and `stop` work by writing
723     // the service name to the "ctl.start" and "ctl.stop" properties.)
724     return IsLegalPropertyName("init.svc." + name) && name.size() <= PROP_VALUE_MAX;
725 }
726 
727 }  // namespace init
728 }  // namespace android
729