Skip to content

Commit

Permalink
SystemServer: Fetch any extra GIDs and call setgroups() before spawn
Browse files Browse the repository at this point in the history
We now pick up all the user's extra GIDs from /etc/group and make
sure those are set before exec'ing a service.

This means we finally get to enjoy being in more than one group. :^)
  • Loading branch information
awesomekling committed Jan 4, 2020
1 parent b4b8b88 commit c2b7c43
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 7 deletions.
2 changes: 1 addition & 1 deletion Base/usr/share/man/man5/SystemServer.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ describing how to launch and manage this service.
* `KeepAlive` - whether the service should be restarted if it exits or crashes. For lazy services, this means the service will get respawned once a new connection is attempted on their socket after they exit or crash.
* `Lazy` - whether the service should only get spawned once a client attempts to connect to their socket.
* `Socket` - a path to a socket to create on behalf of the service. For lazy services, SystemServer will actually watch the socket for new connection attempts. An open file descriptor to this socket will be passed as fd 3 to the service.
* `User` - a name of the user to run the service as. This impacts what UID and GID the service processes have. By default, services are run as root.
* `User` - a name of the user to run the service as. This impacts what UID, GID (and extra GIDs) the service processes have. By default, services are run as root.

## Environment

Expand Down
24 changes: 18 additions & 6 deletions Servers/SystemServer/Service.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <LibCore/CConfigFile.h>
#include <LibCore/CLocalSocket.h>
#include <fcntl.h>
#include <grp.h>
#include <libgen.h>
#include <pwd.h>
#include <sched.h>
Expand All @@ -13,20 +14,30 @@
#include <sys/stat.h>
#include <unistd.h>

struct UidAndGid {
struct UidAndGids {
uid_t uid;
gid_t gid;
Vector<gid_t> extra_gids;
};

static HashMap<String, UidAndGid>* s_user_map;
static HashMap<String, UidAndGids>* s_user_map;
static HashMap<pid_t, Service*> s_service_map;

void Service::resolve_user()
{
if (s_user_map == nullptr) {
s_user_map = new HashMap<String, UidAndGid>;
for (struct passwd* passwd = getpwent(); passwd; passwd = getpwent())
s_user_map->set(passwd->pw_name, { passwd->pw_uid, passwd->pw_gid });
s_user_map = new HashMap<String, UidAndGids>;
for (struct passwd* passwd = getpwent(); passwd; passwd = getpwent()) {
Vector<gid_t> extra_gids;
for (struct group* group = getgrent(); group; group = getgrent()) {
for (size_t m = 0; group->gr_mem[m]; ++m) {
if (!strcmp(group->gr_mem[m], passwd->pw_name))
extra_gids.append(group->gr_gid);
}
}
endgrent();
s_user_map->set(passwd->pw_name, { passwd->pw_uid, passwd->pw_gid, move(extra_gids) });
}
endpwent();
}

Expand All @@ -37,6 +48,7 @@ void Service::resolve_user()
}
m_uid = user.value().uid;
m_gid = user.value().gid;
m_extra_gids = user.value().extra_gids;
}

Service* Service::find_by_pid(pid_t pid)
Expand Down Expand Up @@ -189,7 +201,7 @@ void Service::spawn()
}

if (!m_user.is_null()) {
if (setgid(m_gid) < 0 || setuid(m_uid) < 0) {
if (setgid(m_gid) < 0 || setgroups(m_extra_gids.size(), m_extra_gids.data()) < 0 || setuid(m_uid) < 0) {
dbgprintf("Failed to drop privileges (GID=%u, UID=%u)\n", m_gid, m_uid);
exit(1);
}
Expand Down
1 change: 1 addition & 0 deletions Servers/SystemServer/Service.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class Service final : public CObject {
String m_user;
uid_t m_uid { 0 };
gid_t m_gid { 0 };
Vector<gid_t> m_extra_gids;

// PID of the running instance of this service.
pid_t m_pid { -1 };
Expand Down

0 comments on commit c2b7c43

Please sign in to comment.