summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTreehugger Robot2016-07-11 12:08:45 -0500
committerGerrit Code Review2016-07-11 12:08:45 -0500
commit82d2bcc21e4a9cc347c9c0598e12b2419561db0b (patch)
treeb462e3e36c3b24d6ad9682bfd7e629c32486159b
parent5d420e791bf468531749131dd32bf15b81d5dfc0 (diff)
parent344d01f99f6049565e4342b4c4202bd9ab96340b (diff)
downloadplatform-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.cpp210
-rw-r--r--init/service.h2
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
55static 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
55static void SetUpPidNamespace(const std::string& service_name) { 92static 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
132static 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
95SocketInfo::SocketInfo() : uid(0), gid(0), perm(0) { 145SocketInfo::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
207void 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
221void 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
157bool Service::Reap() { 251bool 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);