Have starter also set supplemental groups

We rely on these for resources accessed by some processes.

Change-Id: Idf22b6263ebc313c8abb63fe93bce2cc3ef24274
Signed-off-by: James Kuszmaul <james.kuszmaul@bluerivertech.com>
diff --git a/aos/starter/starterd.cc b/aos/starter/starterd.cc
index b40776d..a5a340a 100644
--- a/aos/starter/starterd.cc
+++ b/aos/starter/starterd.cc
@@ -24,6 +24,10 @@
         return 1;
       }
     }
+    // Change the real and effective IDs to the user we're running as. The
+    // effective IDs mean files we access (like shared memory) will happen as
+    // that user. The real IDs allow child processes with an different effective
+    // ID to still participate in signal sending/receiving.
     constexpr int kUnchanged = -1;
     if (setresgid(/* ruid */ gid, /* euid */ gid,
                   /* suid */ kUnchanged) != 0) {
diff --git a/aos/starter/starterd_lib.cc b/aos/starter/starterd_lib.cc
index 7bf2e0d..00b094f 100644
--- a/aos/starter/starterd_lib.cc
+++ b/aos/starter/starterd_lib.cc
@@ -1,6 +1,7 @@
 #include "starterd_lib.h"
 
 #include <fcntl.h>
+#include <grp.h>
 #include <pwd.h>
 #include <sys/fsuid.h>
 #include <sys/prctl.h>
@@ -24,11 +25,11 @@
                 ? application->executable_name()->string_view()
                 : application->name()->string_view()),
       args_(1),
-      user_(application->has_user() ? FindUid(application->user()->c_str())
+      user_name_(application->has_user() ? application->user()->str() : ""),
+      user_(application->has_user() ? FindUid(user_name_.c_str())
                                     : std::nullopt),
-      group_(application->has_user()
-                 ? FindPrimaryGidForUser(application->user()->c_str())
-                 : std::nullopt),
+      group_(application->has_user() ? FindPrimaryGidForUser(user_name_.c_str())
+                                     : std::nullopt),
       autostart_(application->autostart()),
       event_loop_(event_loop),
       start_timer_(event_loop_->AddTimer([this] {
@@ -91,6 +92,23 @@
   }
 
   if (group_) {
+    CHECK(!user_name_.empty());
+    // The manpage for setgroups says we just need CAP_SETGID, but empirically
+    // we also need the effective UID to be 0 to make it work. user_ must also
+    // be set so we change this effective UID back later.
+    CHECK(user_);
+    if (seteuid(0) == -1) {
+      write_pipe_.Write(
+          static_cast<uint32_t>(aos::starter::LastStopReason::SET_GRP_ERR));
+      PLOG(FATAL) << "Could not seteuid(0) for " << name_
+                  << " in preparation for setting groups";
+    }
+    if (initgroups(user_name_.c_str(), *group_) == -1) {
+      write_pipe_.Write(
+          static_cast<uint32_t>(aos::starter::LastStopReason::SET_GRP_ERR));
+      PLOG(FATAL) << "Could not initialize normal groups for " << name_
+                  << " as " << user_name_ << " with " << *group_;
+    }
     if (setgid(*group_) == -1) {
       write_pipe_.Write(
           static_cast<uint32_t>(aos::starter::LastStopReason::SET_GRP_ERR));
diff --git a/aos/starter/starterd_lib.h b/aos/starter/starterd_lib.h
index 1809326..8c70960 100644
--- a/aos/starter/starterd_lib.h
+++ b/aos/starter/starterd_lib.h
@@ -117,6 +117,7 @@
   std::string name_;
   std::string path_;
   std::vector<char *> args_;
+  std::string user_name_;
   std::optional<uid_t> user_;
   std::optional<gid_t> group_;