Skip to content

Commit ad46e60

Browse files
authored
Merge pull request #47 from jthiltges/pr/threaduid
Use thread-specific setgroups syscall to set supplementary groups on individual threads
2 parents 3064b2e + c851fb1 commit ad46e60

1 file changed

Lines changed: 32 additions & 0 deletions

File tree

src/UserSentry.hh

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@
1414

1515
#include <dlfcn.h>
1616
#include <fcntl.h>
17+
#include <grp.h>
1718
#include <pwd.h>
1819
#include <sys/capability.h>
1920
#include <sys/fsuid.h>
2021
#include <sys/types.h>
2122
#include <sys/stat.h>
23+
#include <sys/syscall.h>
2224
#include <unistd.h>
2325

2426
// TODO: set this via library parameters.
@@ -121,6 +123,13 @@ public:
121123
return false;
122124
}
123125

126+
// Use syscall to set supplementary groups instead of through glibc so
127+
// changes are applied to individual threads only. See nptl(7).
128+
static int ThreadSetgroups(size_t size, const gid_t *list)
129+
{
130+
return syscall(SYS_setgroups, size, list);
131+
}
132+
124133
void Init(const std::string username, XrdSysError &log)
125134
{
126135
struct passwd pwd, *result = nullptr;
@@ -158,6 +167,24 @@ public:
158167
return;
159168
}
160169

170+
// Get supplementary groups for user
171+
int ngroups = 16;
172+
std::vector<gid_t> groups(ngroups);
173+
do {
174+
int old_ngroups = ngroups;
175+
retval = getgrouplist(username.c_str(), pwd.pw_gid, groups.data(), &ngroups);
176+
if (-1 == retval && ngroups > old_ngroups) {
177+
// Too many groups. Resize buffer and try again.
178+
groups.resize(ngroups);
179+
continue;
180+
}
181+
break;
182+
} while (1);
183+
if (-1 == retval) {
184+
m_log.Emsg("UserSentry", "Failure when looking up supplementary groups for username", username.c_str());
185+
return;
186+
}
187+
161188
// Note: Capabilities need to be set per thread, so we need to do this
162189
ConfigCaps(m_log, nullptr);
163190

@@ -169,6 +196,7 @@ public:
169196
return;
170197
}
171198
m_orig_gid = setfsgid(result->pw_gid);
199+
ThreadSetgroups(ngroups, groups.data());
172200
}
173201

174202
~UserSentry() {
@@ -178,6 +206,10 @@ public:
178206
if ((m_orig_gid != -1) && (-1 == setfsgid(m_orig_gid))) {
179207
m_log.Emsg("UserSentry", "Failed to return fsgid to original state", strerror(errno));
180208
}
209+
// Clear supplementary groups
210+
// We don't need to restore the daemon's original groups, as the
211+
// *-privileged processes run without supplementary groups defined.
212+
ThreadSetgroups(0, nullptr);
181213
}
182214

183215
bool IsValid() const {return ((m_orig_gid != -1) && (m_orig_uid != -1)) || m_is_anonymous;}

0 commit comments

Comments
 (0)