Skip to content

Commit 16facce

Browse files
authored
Try to change uid/gid on plugin runtime dir before dropping privs, if POSIX not available (#13046)
* Try to change uid/gid on plugin runtime dir before dropping privs, if POSIX not available Also add chown for log dir+files
1 parent 5f30ce6 commit 16facce

1 file changed

Lines changed: 79 additions & 0 deletions

File tree

src/traffic_server/traffic_server.cc

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
#include <syslog.h>
5555
#include <algorithm>
5656
#include <atomic>
57+
#include <filesystem>
5758
#include <list>
5859
#include <string>
5960

@@ -1757,6 +1758,83 @@ change_uid_gid(const char *user)
17571758
#endif
17581759
}
17591760

1761+
#if !TS_USE_POSIX_CAP
1762+
/**
1763+
* Recursively chown a directory and all its contents to the given uid/gid.
1764+
* Uses lchown() to avoid following symlinks.
1765+
*/
1766+
static void
1767+
chown_dir_recursive(const char *dir, uid_t uid, gid_t gid)
1768+
{
1769+
if (lchown(dir, uid, gid) != 0) {
1770+
Warning("chown_dir_recursive: failed to chown '%s': %s", dir, strerror(errno));
1771+
}
1772+
1773+
std::error_code ec;
1774+
1775+
for (const auto &entry : std::filesystem::recursive_directory_iterator(dir, ec)) {
1776+
if (lchown(entry.path().c_str(), uid, gid) != 0) {
1777+
Warning("chown_dir_recursive: failed to chown '%s': %s", entry.path().c_str(), strerror(errno));
1778+
}
1779+
}
1780+
1781+
if (ec) {
1782+
Warning("chown_dir_recursive: error iterating '%s': %s", dir, ec.message().c_str());
1783+
}
1784+
}
1785+
1786+
/**
1787+
* On systems without POSIX capabilities, privilege is dropped late — after
1788+
* initialization has already created files and directories as root. This
1789+
* causes runtime operations (plugin reloads, log rotation) to fail because
1790+
* the now-unprivileged process can't write to root-owned paths. Fix this by
1791+
* chowning affected directories to the target user before dropping privileges.
1792+
*/
1793+
static void
1794+
chown_owned_dirs(const char *user)
1795+
{
1796+
if (getuid() != 0 && geteuid() != 0) {
1797+
return;
1798+
}
1799+
1800+
struct passwd *pwd;
1801+
struct passwd pbuf;
1802+
unsigned pw_bufsize = 4096;
1803+
#if defined(_SC_GETPW_R_SIZE_MAX)
1804+
long pw_size = sysconf(_SC_GETPW_R_SIZE_MAX);
1805+
1806+
if (pw_size > 0) {
1807+
pw_bufsize = static_cast<unsigned>(pw_size);
1808+
}
1809+
#endif
1810+
char buf[pw_bufsize];
1811+
1812+
if (*user == '#') {
1813+
uid_t uid = static_cast<uid_t>(atoi(&user[1]));
1814+
if (getpwuid_r(uid, &pbuf, buf, sizeof(buf), &pwd) != 0 || pwd == nullptr) {
1815+
Warning("chown_owned_dirs: cannot resolve uid %ld", static_cast<long>(uid));
1816+
return;
1817+
}
1818+
} else {
1819+
if (getpwnam_r(user, &pbuf, buf, sizeof(buf), &pwd) != 0 || pwd == nullptr) {
1820+
Warning("chown_owned_dirs: cannot resolve user '%s'", user);
1821+
return;
1822+
}
1823+
}
1824+
1825+
std::string rundir(RecConfigReadRuntimeDir());
1826+
std::string logdir(RecConfigReadLogDir());
1827+
1828+
if (!rundir.empty()) {
1829+
chown_dir_recursive(rundir.c_str(), pwd->pw_uid, pwd->pw_gid);
1830+
}
1831+
1832+
if (!logdir.empty()) {
1833+
chown_dir_recursive(logdir.c_str(), pwd->pw_uid, pwd->pw_gid);
1834+
}
1835+
}
1836+
#endif // !TS_USE_POSIX_CAP
1837+
17601838
/*
17611839
* Binds stdout and stderr to files specified by the parameters
17621840
*
@@ -2400,6 +2478,7 @@ main(int /* argc ATS_UNUSED */, const char **argv)
24002478

24012479
#if !TS_USE_POSIX_CAP
24022480
if (admin_user_p) {
2481+
chown_owned_dirs(user);
24032482
change_uid_gid(user);
24042483
}
24052484
#endif

0 commit comments

Comments
 (0)