From: Linus Torvalds Date: Thu, 15 Sep 2005 16:03:31 GMT Subject: Re: git-daemon --inetd Message-ID: In-Reply-To: <43290EFF.3070604@zytor.com> On Wed, 14 Sep 2005, H. Peter Anvin wrote: > > On that note, though, it would be very nice if there was a way to run > git-daemon in a chroot, or otherwise restrict it to a specific > subhierarchy of the filesystem. Hmm.. That should work fine. You can already just run it that way by just wrapping it in "chroot", but if you don't want that for some reason, how about a patch like this? It compiles. That's just about all I can say about it. Linus --- diff --git a/daemon.c b/daemon.c --- a/daemon.c +++ b/daemon.c @@ -1,11 +1,19 @@ +/* setresuid/setresgid. GNU? Who are you kidding, glibc? */ +#define _GNU_SOURCE + #include "cache.h" #include "pkt-line.h" #include #include #include #include +#include #include #include +#include + +#include +#include static const char daemon_usage[] = "git-daemon [--inetd | --port=n]"; @@ -326,10 +334,50 @@ static int serve(int port) } } +/* + * This will drop our effective uid/gid to the real one, + * even if no "--user=" or "--group=" arguments were used. + * + * So it's not a no-op even without that. + */ +static void set_user_group(const char *user, const char *group) +{ + uid_t uid = getuid(); + gid_t gid = getgid(); + char *end; + + if (user) { + struct passwd *pw = getpwnam(user); + if (pw) { + uid = pw->pw_uid; + gid = pw->pw_gid; + } else { + uid = strtol(user, &end, 10); + if (*end || end == user) + die("invalid user name '%s'", user); + } + } + if (group) { + struct group *grp = getgrnam(group); + if (grp) { + gid = grp->gr_gid; + } else { + gid = strtol(group, &end, 10); + if (*end || end == group) + die("invalid group name '%s'", group); + } + } + if (!uid || !gid) + die("I refuse to run as root"); + if (setresgid(gid, gid, gid) || setresuid(uid, uid, uid)) + die("I can't run as %d:%d", uid, gid); +} + int main(int argc, char **argv) { int port = DEFAULT_GIT_PORT; int inetd_mode = 0; + const char *user = NULL, *group = NULL; int i; for (i = 1; i < argc; i++) { @@ -350,9 +398,32 @@ int main(int argc, char **argv) continue; } + if (!strncmp(arg, "--chroot=", 9)) { + if (chroot(arg+9) < 0) + die("unable to chroot to '%s': %s", arg+9, strerror(errno)); + if (chdir("/") < 0) + die("unable to chdir to new root"); + + user = user ? user : "nobody"; + group = group ? group : "nobody"; + continue; + } + + if (!strncmp(arg, "--user=", 7)) { + user = arg+7; + continue; + } + + if (!strncmp(arg, "--group=", 8)) { + group = arg + 8; + continue; + } + usage(daemon_usage); } + set_user_group(user, group); + if (inetd_mode) { fclose(stderr); //FIXME: workaround return execute();