commit 15cd675b6d611a6290b3ed88dd47c42e5ff9eb54 from: Stefan Sperling via: Thomas Adam date: Wed Aug 23 20:29:35 2023 UTC portable: gotd: re-enable chroot Reads (git clone) are working but writes (git push) run into an error commit - 336414eee6beb20c43830a6ae482e31977f609f3 commit + 15cd675b6d611a6290b3ed88dd47c42e5ff9eb54 blob - e8f36dc8c9e4dca41153d952a13e1120bff3f215 blob + c6531257554a0d495a7ef3a1e39d84a0be4ce03d --- gotd/Makefile.am +++ gotd/Makefile.am @@ -48,6 +48,12 @@ gotd_SOURCES = gotd.c \ $(top_srcdir)/lib/reference_parse.c \ $(top_srcdir)/lib/repository.c \ $(top_srcdir)/lib/sigs.c + +if !HOST_OPENBSD +nodist_gotd_SOURCES = chroot-notobsd.c +else +nodist_gotd_SOURCES = chroot-openbsd.c +endif gotd_DEPENDENCIES = $(top_builddir)/compat/libopenbsd-compat.a EXTRA_DIST = gotd.8 gotd.conf.5 *.h @@ -59,7 +65,8 @@ LDADD = -L$(top_builddir)/compat -lopenbsd-compat -lm LDADD += $(libuuid_LIBS) \ $(zlib_LIBS) \ $(libbsd_LIBS) \ - $(libevent_LIBS) + $(libevent_LIBS) \ + $(libutil_LIBS) if HOST_FREEBSD LDADD += -lmd endif blob - /dev/null blob + 19506ed47c6c6a95b2e8984da0db9174f1a0afb8 (mode 644) --- /dev/null +++ gotd/chroot-notobsd.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023 Thomas Adam + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "got_compat.h" + +#include +#include + +#include "log.h" + +int +enter_chroot(const char *path) +{ + log_info("chroot into %s", path); + if (chroot(path) == -1) + fatal("chroot"); + if (chdir("/") == -1) + fatal("chdir(\"/\")"); + + return 1; +} blob - d847e923a6c4676e526a8171f6813cb9686f9698 blob + 7fe8383caa546eb53fad4c421af5738bf34f0ea1 --- gotd/gotd.c +++ gotd/gotd.c @@ -116,6 +116,7 @@ static const struct got_error *start_auth_child(struct struct gotd_repo *, char *, const char *, int, int); static void kill_proc(struct gotd_child_proc *, int); static void disconnect(struct gotd_client *); +static void drop_privs(struct passwd *); __dead static void usage(void) @@ -1819,6 +1820,16 @@ apply_unveil_selfexec(void) if (unveil(NULL, NULL) == -1) fatal("unveil"); +} + +static void +drop_privs(struct passwd *pw) +{ + /* Drop root privileges. */ + if (setgid(pw->pw_gid) == -1) + fatal("setgid %d failed", pw->pw_gid); + if (setuid(pw->pw_uid) == -1) + fatal("setuid %d failed", pw->pw_uid); } int @@ -1960,11 +1971,14 @@ main(int argc, char **argv) setproctitle("%s", title); log_procinit(title); - /* Drop root privileges. */ - if (setgid(pw->pw_gid) == -1) - fatal("setgid %d failed", pw->pw_gid); - if (setuid(pw->pw_uid) == -1) - fatal("setuid %d failed", pw->pw_uid); + if (proc_id != PROC_GOTD && proc_id != PROC_LISTEN && + proc_id != PROC_REPO_READ && proc_id != PROC_REPO_WRITE) { + /* Drop root privileges. */ + if (setgid(pw->pw_gid) == -1) + fatal("setgid %d failed", pw->pw_gid); + if (setuid(pw->pw_uid) == -1) + fatal("setuid %d failed", pw->pw_uid); + } event_init(); @@ -1987,6 +2001,9 @@ main(int argc, char **argv) */ apply_unveil_none(); + enter_chroot(GOTD_EMPTY_PATH); + drop_privs(pw); + listen_main(title, fd, gotd.connection_limits, gotd.nconnection_limits); /* NOTREACHED */ @@ -2022,6 +2039,7 @@ main(int argc, char **argv) apply_unveil_repo_readonly(repo_path, 1); else apply_unveil_repo_readwrite(repo_path); + session_main(title, repo_path, pack_fds, temp_fds, &gotd.request_timeout, proc_id); /* NOTREACHED */ @@ -2032,6 +2050,17 @@ main(int argc, char **argv) err(1, "pledge"); #endif apply_unveil_repo_readonly(repo_path, 0); + + if (enter_chroot(repo_path)) { + log_info("change repo path %s", repo_path); + free(repo_path); + repo_path = strdup("/"); + if (repo_path == NULL) + fatal("strdup"); + log_info("repo path is now %s", repo_path); + } + drop_privs(pw); + repo_read_main(title, repo_path, pack_fds, temp_fds); /* NOTREACHED */ exit(0); @@ -2044,6 +2073,15 @@ main(int argc, char **argv) repo = gotd_find_repo_by_path(repo_path, &gotd); if (repo == NULL) fatalx("no repository for path %s", repo_path); + + if (enter_chroot(repo_path)) { + free(repo_path); + repo_path = strdup("/"); + if (repo_path == NULL) + fatal("strdup"); + } + drop_privs(pw); + repo_write_main(title, repo_path, pack_fds, temp_fds, &repo->protected_tag_namespaces, &repo->protected_branch_namespaces, blob - /dev/null blob + ce373655b60c84b3b9b6f8a93fc01b6c40e8c401 (mode 644) --- /dev/null +++ gotd/chroot-openbsd.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 Thomas Adam + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "got_compat.h" + +int +enter_chroot(const char *path) +{ + (void)path; + return 0; +} blob - 3f19d8e3cb52c8795ccedfb4853ac60cab2de702 blob + a379ad89ec990acda3d6d8952f4e9ad3d45e92e0 --- gotd/gotd.h +++ gotd/gotd.h @@ -20,7 +20,13 @@ #define GOTD_UNIX_SOCKET_BACKLOG 10 #define GOTD_USER "_gotd" #define GOTD_CONF_PATH "/etc/gotd.conf" +#ifdef __linux__ +/* FIXME: Will move to --configure */ +#define GOTD_EMPTY_PATH "/var/run/gotd" +#else +/* Assumes *BSD, Apple, etc... */ #define GOTD_EMPTY_PATH "/var/empty" +#endif #define GOTD_MAXCLIENTS 1024 #define GOTD_MAX_CONN_PER_UID 4 @@ -444,6 +450,7 @@ struct gotd_imsg_auth { uint32_t client_id; }; +int enter_chroot(const char *); int parse_config(const char *, enum gotd_procid, struct gotd *); struct gotd_repo *gotd_find_repo_by_name(const char *, struct gotd *); struct gotd_repo *gotd_find_repo_by_path(const char *, struct gotd *);