diff options
author | Treehugger Robot | 2016-07-11 12:08:45 -0500 |
---|---|---|
committer | Gerrit Code Review | 2016-07-11 12:08:45 -0500 |
commit | 82d2bcc21e4a9cc347c9c0598e12b2419561db0b (patch) | |
tree | b462e3e36c3b24d6ad9682bfd7e629c32486159b | |
parent | 5d420e791bf468531749131dd32bf15b81d5dfc0 (diff) | |
parent | 344d01f99f6049565e4342b4c4202bd9ab96340b (diff) | |
download | platform-system-core-82d2bcc21e4a9cc347c9c0598e12b2419561db0b.tar.gz platform-system-core-82d2bcc21e4a9cc347c9c0598e12b2419561db0b.tar.xz platform-system-core-82d2bcc21e4a9cc347c9c0598e12b2419561db0b.zip |
Merge "Refactor Service::Start method."
-rw-r--r-- | init/service.cpp | 210 | ||||
-rw-r--r-- | init/service.h | 2 |
2 files changed, 112 insertions, 100 deletions
diff --git a/init/service.cpp b/init/service.cpp index 03c00640f..c63667772 100644 --- a/init/service.cpp +++ b/init/service.cpp | |||
@@ -52,6 +52,43 @@ using android::base::WriteStringToFile; | |||
52 | #define CRITICAL_CRASH_THRESHOLD 4 // if we crash >4 times ... | 52 | #define CRITICAL_CRASH_THRESHOLD 4 // if we crash >4 times ... |
53 | #define CRITICAL_CRASH_WINDOW (4*60) // ... in 4 minutes, goto recovery | 53 | #define CRITICAL_CRASH_WINDOW (4*60) // ... in 4 minutes, goto recovery |
54 | 54 | ||
55 | static std::string ComputeContextFromExecutable(std::string& service_name, | ||
56 | const std::string& service_path) { | ||
57 | std::string computed_context; | ||
58 | |||
59 | char* raw_con = nullptr; | ||
60 | char* raw_filecon = nullptr; | ||
61 | |||
62 | if (getcon(&raw_con) == -1) { | ||
63 | LOG(ERROR) << "could not get context while starting '" << service_name << "'"; | ||
64 | return ""; | ||
65 | } | ||
66 | std::unique_ptr<char> mycon(raw_con); | ||
67 | |||
68 | if (getfilecon(service_path.c_str(), &raw_filecon) == -1) { | ||
69 | LOG(ERROR) << "could not get file context while starting '" << service_name << "'"; | ||
70 | return ""; | ||
71 | } | ||
72 | std::unique_ptr<char> filecon(raw_filecon); | ||
73 | |||
74 | char* new_con = nullptr; | ||
75 | int rc = security_compute_create(mycon.get(), filecon.get(), | ||
76 | string_to_security_class("process"), &new_con); | ||
77 | if (rc == 0) { | ||
78 | computed_context = new_con; | ||
79 | free(new_con); | ||
80 | } | ||
81 | if (rc == 0 && computed_context == mycon.get()) { | ||
82 | LOG(ERROR) << "service " << service_name << " does not have a SELinux domain defined"; | ||
83 | return ""; | ||
84 | } | ||
85 | if (rc < 0) { | ||
86 | LOG(ERROR) << "could not get context while starting '" << service_name << "'"; | ||
87 | return ""; | ||
88 | } | ||
89 | return computed_context; | ||
90 | } | ||
91 | |||
55 | static void SetUpPidNamespace(const std::string& service_name) { | 92 | static void SetUpPidNamespace(const std::string& service_name) { |
56 | constexpr unsigned int kSafeFlags = MS_NODEV | MS_NOEXEC | MS_NOSUID; | 93 | constexpr unsigned int kSafeFlags = MS_NODEV | MS_NOEXEC | MS_NOSUID; |
57 | 94 | ||
@@ -92,6 +129,19 @@ static void SetUpPidNamespace(const std::string& service_name) { | |||
92 | } | 129 | } |
93 | } | 130 | } |
94 | 131 | ||
132 | static void ExpandArgs(const std::vector<std::string>& args, std::vector<char*>* strs) { | ||
133 | std::vector<std::string> expanded_args; | ||
134 | expanded_args.resize(args.size()); | ||
135 | strs->push_back(const_cast<char*>(args[0].c_str())); | ||
136 | for (std::size_t i = 1; i < args.size(); ++i) { | ||
137 | if (!expand_props(args[i], &expanded_args[i])) { | ||
138 | LOG(FATAL) << args[0] << ": cannot expand '" << args[i] << "'"; | ||
139 | } | ||
140 | strs->push_back(const_cast<char*>(expanded_args[i].c_str())); | ||
141 | } | ||
142 | strs->push_back(nullptr); | ||
143 | } | ||
144 | |||
95 | SocketInfo::SocketInfo() : uid(0), gid(0), perm(0) { | 145 | SocketInfo::SocketInfo() : uid(0), gid(0), perm(0) { |
96 | } | 146 | } |
97 | 147 | ||
@@ -154,6 +204,50 @@ void Service::KillProcessGroup(int signal) { | |||
154 | killProcessGroup(uid_, pid_, signal); | 204 | killProcessGroup(uid_, pid_, signal); |
155 | } | 205 | } |
156 | 206 | ||
207 | void Service::CreateSockets(const std::string& context) { | ||
208 | for (const auto& si : sockets_) { | ||
209 | int socket_type = ((si.type == "stream" ? SOCK_STREAM : | ||
210 | (si.type == "dgram" ? SOCK_DGRAM : | ||
211 | SOCK_SEQPACKET))); | ||
212 | const char* socketcon = !si.socketcon.empty() ? si.socketcon.c_str() : context.c_str(); | ||
213 | |||
214 | int s = create_socket(si.name.c_str(), socket_type, si.perm, si.uid, si.gid, socketcon); | ||
215 | if (s >= 0) { | ||
216 | PublishSocket(si.name, s); | ||
217 | } | ||
218 | } | ||
219 | } | ||
220 | |||
221 | void Service::SetProcessAttributes() { | ||
222 | setpgid(0, getpid()); | ||
223 | |||
224 | if (gid_) { | ||
225 | if (setgid(gid_) != 0) { | ||
226 | PLOG(FATAL) << "setgid failed"; | ||
227 | } | ||
228 | } | ||
229 | if (!supp_gids_.empty()) { | ||
230 | if (setgroups(supp_gids_.size(), &supp_gids_[0]) != 0) { | ||
231 | PLOG(FATAL) << "setgroups failed"; | ||
232 | } | ||
233 | } | ||
234 | if (uid_) { | ||
235 | if (setuid(uid_) != 0) { | ||
236 | PLOG(FATAL) << "setuid failed"; | ||
237 | } | ||
238 | } | ||
239 | if (!seclabel_.empty()) { | ||
240 | if (setexeccon(seclabel_.c_str()) < 0) { | ||
241 | PLOG(FATAL) << "cannot setexeccon('" << seclabel_ << "')"; | ||
242 | } | ||
243 | } | ||
244 | if (priority_ != 0) { | ||
245 | if (setpriority(PRIO_PROCESS, 0, priority_) != 0) { | ||
246 | PLOG(FATAL) << "setpriority failed"; | ||
247 | } | ||
248 | } | ||
249 | } | ||
250 | |||
157 | bool Service::Reap() { | 251 | bool Service::Reap() { |
158 | if (!(flags_ & SVC_ONESHOT) || (flags_ & SVC_RESTART)) { | 252 | if (!(flags_ & SVC_ONESHOT) || (flags_ & SVC_RESTART)) { |
159 | KillProcessGroup(SIGKILL); | 253 | KillProcessGroup(SIGKILL); |
@@ -441,50 +535,18 @@ bool Service::Start() { | |||
441 | if (!seclabel_.empty()) { | 535 | if (!seclabel_.empty()) { |
442 | scon = seclabel_; | 536 | scon = seclabel_; |
443 | } else { | 537 | } else { |
444 | char* mycon = nullptr; | 538 | LOG(INFO) << "computing context for service '" << name_ << "'"; |
445 | char* fcon = nullptr; | 539 | scon = ComputeContextFromExecutable(name_, args_[0]); |
446 | 540 | if (scon == "") { | |
447 | LOG(INFO) << "computing context for service '" << args_[0] << "'"; | ||
448 | int rc = getcon(&mycon); | ||
449 | if (rc < 0) { | ||
450 | LOG(ERROR) << "could not get context while starting '" << name_ << "'"; | ||
451 | return false; | ||
452 | } | ||
453 | |||
454 | rc = getfilecon(args_[0].c_str(), &fcon); | ||
455 | if (rc < 0) { | ||
456 | LOG(ERROR) << "could not get file context while starting '" << name_ << "'"; | ||
457 | free(mycon); | ||
458 | return false; | ||
459 | } | ||
460 | |||
461 | char* ret_scon = nullptr; | ||
462 | rc = security_compute_create(mycon, fcon, string_to_security_class("process"), | ||
463 | &ret_scon); | ||
464 | if (rc == 0) { | ||
465 | scon = ret_scon; | ||
466 | free(ret_scon); | ||
467 | } | ||
468 | if (rc == 0 && scon == mycon) { | ||
469 | LOG(ERROR) << "Service " << name_ << " does not have a SELinux domain defined."; | ||
470 | free(mycon); | ||
471 | free(fcon); | ||
472 | return false; | ||
473 | } | ||
474 | free(mycon); | ||
475 | free(fcon); | ||
476 | if (rc < 0) { | ||
477 | LOG(ERROR) << "could not get context while starting '" << name_ << "'"; | ||
478 | return false; | 541 | return false; |
479 | } | 542 | } |
480 | } | 543 | } |
481 | 544 | ||
482 | LOG(VERBOSE) << "Starting service '" << name_ << "'..."; | 545 | LOG(VERBOSE) << "starting service '" << name_ << "'..."; |
483 | 546 | ||
484 | pid_t pid = -1; | 547 | pid_t pid = -1; |
485 | if (namespace_flags_) { | 548 | if (namespace_flags_) { |
486 | pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, | 549 | pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr); |
487 | nullptr); | ||
488 | } else { | 550 | } else { |
489 | pid = fork(); | 551 | pid = fork(); |
490 | } | 552 | } |
@@ -502,19 +564,7 @@ bool Service::Start() { | |||
502 | add_environment(ei.name.c_str(), ei.value.c_str()); | 564 | add_environment(ei.name.c_str(), ei.value.c_str()); |
503 | } | 565 | } |
504 | 566 | ||
505 | for (const auto& si : sockets_) { | 567 | CreateSockets(scon); |
506 | int socket_type = ((si.type == "stream" ? SOCK_STREAM : | ||
507 | (si.type == "dgram" ? SOCK_DGRAM : | ||
508 | SOCK_SEQPACKET))); | ||
509 | const char* socketcon = | ||
510 | !si.socketcon.empty() ? si.socketcon.c_str() : scon.c_str(); | ||
511 | |||
512 | int s = create_socket(si.name.c_str(), socket_type, si.perm, | ||
513 | si.uid, si.gid, socketcon); | ||
514 | if (s >= 0) { | ||
515 | PublishSocket(si.name, s); | ||
516 | } | ||
517 | } | ||
518 | 568 | ||
519 | std::string pid_str = StringPrintf("%d", getpid()); | 569 | std::string pid_str = StringPrintf("%d", getpid()); |
520 | for (const auto& file : writepid_files_) { | 570 | for (const auto& file : writepid_files_) { |
@@ -525,7 +575,7 @@ bool Service::Start() { | |||
525 | 575 | ||
526 | if (ioprio_class_ != IoSchedClass_NONE) { | 576 | if (ioprio_class_ != IoSchedClass_NONE) { |
527 | if (android_set_ioprio(getpid(), ioprio_class_, ioprio_pri_)) { | 577 | if (android_set_ioprio(getpid(), ioprio_class_, ioprio_pri_)) { |
528 | PLOG(ERROR) << "Failed to set pid " << getpid() | 578 | PLOG(ERROR) << "failed to set pid " << getpid() |
529 | << " ioprio=" << ioprio_class_ << "," << ioprio_pri_; | 579 | << " ioprio=" << ioprio_class_ << "," << ioprio_pri_; |
530 | } | 580 | } |
531 | } | 581 | } |
@@ -537,53 +587,12 @@ bool Service::Start() { | |||
537 | ZapStdio(); | 587 | ZapStdio(); |
538 | } | 588 | } |
539 | 589 | ||
540 | setpgid(0, getpid()); | 590 | // As requested, set our gid, supplemental gids, uid, context, and |
591 | // priority. Aborts on failure. | ||
592 | SetProcessAttributes(); | ||
541 | 593 | ||
542 | // As requested, set our gid, supplemental gids, and uid. | ||
543 | if (gid_) { | ||
544 | if (setgid(gid_) != 0) { | ||
545 | PLOG(ERROR) << "setgid failed"; | ||
546 | _exit(127); | ||
547 | } | ||
548 | } | ||
549 | if (!supp_gids_.empty()) { | ||
550 | if (setgroups(supp_gids_.size(), &supp_gids_[0]) != 0) { | ||
551 | PLOG(ERROR) << "setgroups failed"; | ||
552 | _exit(127); | ||
553 | } | ||
554 | } | ||
555 | if (uid_) { | ||
556 | if (setuid(uid_) != 0) { | ||
557 | PLOG(ERROR) << "setuid failed"; | ||
558 | _exit(127); | ||
559 | } | ||
560 | } | ||
561 | if (!seclabel_.empty()) { | ||
562 | if (setexeccon(seclabel_.c_str()) < 0) { | ||
563 | PLOG(ERROR) << "cannot setexeccon('" << seclabel_ << "')"; | ||
564 | _exit(127); | ||
565 | } | ||
566 | } | ||
567 | if (priority_ != 0) { | ||
568 | if (setpriority(PRIO_PROCESS, 0, priority_) != 0) { | ||
569 | PLOG(ERROR) << "setpriority failed"; | ||
570 | _exit(127); | ||
571 | } | ||
572 | } | ||
573 | |||
574 | std::vector<std::string> expanded_args; | ||
575 | std::vector<char*> strs; | 594 | std::vector<char*> strs; |
576 | expanded_args.resize(args_.size()); | 595 | ExpandArgs(args_, &strs); |
577 | strs.push_back(const_cast<char*>(args_[0].c_str())); | ||
578 | for (std::size_t i = 1; i < args_.size(); ++i) { | ||
579 | if (!expand_props(args_[i], &expanded_args[i])) { | ||
580 | LOG(ERROR) << args_[0] << ": cannot expand '" << args_[i] << "'"; | ||
581 | _exit(127); | ||
582 | } | ||
583 | strs.push_back(const_cast<char*>(expanded_args[i].c_str())); | ||
584 | } | ||
585 | strs.push_back(nullptr); | ||
586 | |||
587 | if (execve(strs[0], (char**) &strs[0], (char**) ENV) < 0) { | 596 | if (execve(strs[0], (char**) &strs[0], (char**) ENV) < 0) { |
588 | PLOG(ERROR) << "cannot execve('" << strs[0] << "')"; | 597 | PLOG(ERROR) << "cannot execve('" << strs[0] << "')"; |
589 | } | 598 | } |
@@ -603,13 +612,14 @@ bool Service::Start() { | |||
603 | 612 | ||
604 | errno = -createProcessGroup(uid_, pid_); | 613 | errno = -createProcessGroup(uid_, pid_); |
605 | if (errno != 0) { | 614 | if (errno != 0) { |
606 | PLOG(ERROR) << "createProcessGroup(" << uid_ << ", " << pid_ << ") failed for service '" << name_ << "'"; | 615 | PLOG(ERROR) << "createProcessGroup(" << uid_ << ", " << pid_ << ") failed for service '" |
616 | << name_ << "'"; | ||
607 | } | 617 | } |
608 | 618 | ||
609 | if ((flags_ & SVC_EXEC) != 0) { | 619 | if ((flags_ & SVC_EXEC) != 0) { |
610 | LOG(INFO) << android::base::StringPrintf("SVC_EXEC pid %d (uid %d gid %d+%zu context %s) started; waiting...", | 620 | LOG(INFO) << android::base::StringPrintf( |
611 | pid_, uid_, gid_, supp_gids_.size(), | 621 | "SVC_EXEC pid %d (uid %d gid %d+%zu context %s) started; waiting...", pid_, uid_, gid_, |
612 | !seclabel_.empty() ? seclabel_.c_str() : "default"); | 622 | supp_gids_.size(), !seclabel_.empty() ? seclabel_.c_str() : "default"); |
613 | } | 623 | } |
614 | 624 | ||
615 | NotifyStateChange("running"); | 625 | NotifyStateChange("running"); |
diff --git a/init/service.h b/init/service.h index 38c5d64c6..aa73aaf84 100644 --- a/init/service.h +++ b/init/service.h | |||
@@ -113,6 +113,8 @@ private: | |||
113 | void OpenConsole() const; | 113 | void OpenConsole() const; |
114 | void PublishSocket(const std::string& name, int fd) const; | 114 | void PublishSocket(const std::string& name, int fd) const; |
115 | void KillProcessGroup(int signal); | 115 | void KillProcessGroup(int signal); |
116 | void CreateSockets(const std::string& scon); | ||
117 | void SetProcessAttributes(); | ||
116 | 118 | ||
117 | bool ParseClass(const std::vector<std::string>& args, std::string* err); | 119 | bool ParseClass(const std::vector<std::string>& args, std::string* err); |
118 | bool ParseConsole(const std::vector<std::string>& args, std::string* err); | 120 | bool ParseConsole(const std::vector<std::string>& args, std::string* err); |