From: Stefan Sperling Subject: -portable gotd progress To: gameoftrees@openbsd.org Date: Sun, 20 Aug 2023 14:28:55 +0200 The following patches provide some progress for gotd in -portable. The patches are based on the ta/gotd branch, not the 'portable' branch! I am restoring chroot support where possible. This requires the main process to keep running as root. But that is probably better than not chrooting. A blocking issue I found during testing is that 'got send' never exits after uploading the pack file. On the server side I see gotsh hanging in poll on stdin, still waiting for more pack file data to arrive. Any ideas how that can be fixed? We seem to be relying on some OpenBSD-specific behaviour on the server side? To test the changes, add a gotd user to the system, create an empty directory at /var/run/gotd, put gotsh and gitwrapper in /usr/bin with appropriate symlinks for gitwrapper. Try a gotd.conf such as: [[[ user gotd repository "test" { path "/git/test.git" permit rw stsp } ]]] I don't want to commit the debug diff (#4). OK for any others? Should I put patches on ta/gotd or do we create a separate branch? Diffs #1 and #2 could probably go directly to the 'portable' branch? ----------------------------------------------- commit fdd7ffc98a9c9a26d83d115d398c1cd1e609e7cd from: Stefan Sperling date: Sun Aug 20 10:32:34 2023 UTC make sure program_invocation_short_name gets defined in getprogname.c This is needed for gitwrapper which will fail if its program name cannot be detected properly. diff 497c206b2e1425e9a667723222a167d4f3b1dae6 fdd7ffc98a9c9a26d83d115d398c1cd1e609e7cd commit - 497c206b2e1425e9a667723222a167d4f3b1dae6 commit + fdd7ffc98a9c9a26d83d115d398c1cd1e609e7cd blob - 1dc2f493577b073fa65b7544928ff6ff61c1c2e6 blob + 975dd4f84e4975bf7c53aaa058770a333a96cfd4 --- compat/getprogname.c +++ compat/getprogname.c @@ -14,10 +14,15 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define _GNU_SOURCE + #include #include +#include +#include "got_compat.h" + #if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME) const char * getprogname(void) ----------------------------------------------- commit 13c8c4fddb5a359fdfb781028cfaa3529ae65043 from: Stefan Sperling date: Sun Aug 20 10:32:34 2023 UTC use a workng git libexec directory default on Linux Tested on ubuntu 22.04 diff fdd7ffc98a9c9a26d83d115d398c1cd1e609e7cd 13c8c4fddb5a359fdfb781028cfaa3529ae65043 commit - fdd7ffc98a9c9a26d83d115d398c1cd1e609e7cd commit + 13c8c4fddb5a359fdfb781028cfaa3529ae65043 blob - 2b1255118b91d4c7edef0a6016130ed9de07bfcd blob + af3cf15215d61e94a762d704ddca0ecf37080994 --- gitwrapper/gitwrapper.c +++ gitwrapper/gitwrapper.c @@ -43,8 +43,12 @@ #include "log.h" #ifndef GITWRAPPER_GIT_LIBEXEC_DIR +#ifdef __linux__ +#define GITWRAPPER_GIT_LIBEXEC_DIR "/usr/lib/git-core/" +#else #define GITWRAPPER_GIT_LIBEXEC_DIR "/usr/local/libexec/git" #endif +#endif #ifndef GITWRAPPER_MY_SERVER_PROG #define GITWRAPPER_MY_SERVER_PROG "gotsh" ----------------------------------------------- commit bf9a5775e4bca9539f7e1064a16fe20f611028ef from: Stefan Sperling date: Sun Aug 20 10:32:34 2023 UTC re-enable chroot in -portable gotd Reads (git clone) are working but writes (git push) run into an error diff 13c8c4fddb5a359fdfb781028cfaa3529ae65043 bf9a5775e4bca9539f7e1064a16fe20f611028ef commit - 13c8c4fddb5a359fdfb781028cfaa3529ae65043 commit + bf9a5775e4bca9539f7e1064a16fe20f611028ef blob - d847e923a6c4676e526a8171f6813cb9686f9698 blob + 4fd361f420a38ab5a9dfe6a68516b93b5d1f9d2c --- gotd/gotd.c +++ gotd/gotd.c @@ -1821,6 +1821,29 @@ int fatal("unveil"); } +static int +enter_chroot(const char *path, struct passwd *pw) +{ + int ret = 0; + +#ifndef HAVE_UNVEIL + log_info("chroot into %s", path); + if (chroot(path) == -1) + fatal("chroot"); + if (chdir("/") == -1) + fatal("chdir(\"/\")"); + ret = 1; +#endif + + /* 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); + + return ret; +} + int main(int argc, char **argv) { @@ -1960,11 +1983,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 +2013,8 @@ main(int argc, char **argv) */ apply_unveil_none(); + enter_chroot(GOTD_EMPTY_PATH, pw); + listen_main(title, fd, gotd.connection_limits, gotd.nconnection_limits); /* NOTREACHED */ @@ -2022,6 +2050,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 +2061,16 @@ main(int argc, char **argv) err(1, "pledge"); #endif apply_unveil_repo_readonly(repo_path, 0); + + if (enter_chroot(repo_path, pw)) { + 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); + } + repo_read_main(title, repo_path, pack_fds, temp_fds); /* NOTREACHED */ exit(0); @@ -2044,6 +2083,14 @@ 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, pw)) { + free(repo_path); + repo_path = strdup("/"); + if (repo_path == NULL) + fatal("strdup"); + } + repo_write_main(title, repo_path, pack_fds, temp_fds, &repo->protected_tag_namespaces, &repo->protected_branch_namespaces, blob - 3f19d8e3cb52c8795ccedfb4853ac60cab2de702 blob + 104969391e88b00555dda0b771c28af94e7b9f06 --- gotd/gotd.h +++ gotd/gotd.h @@ -20,7 +20,11 @@ #define GOTD_UNIX_SOCKET_BACKLOG 10 #define GOTD_USER "_gotd" #define GOTD_CONF_PATH "/etc/gotd.conf" +#ifdef __linux__ +#define GOTD_EMPTY_PATH "/var/run/gotd" +#else #define GOTD_EMPTY_PATH "/var/empty" +#endif #define GOTD_MAXCLIENTS 1024 #define GOTD_MAX_CONN_PER_UID 4 ----------------------------------------------- commit 40b0f0fa8f9f421c31757f17284754c53eb8e443 from: Stefan Sperling date: Sun Aug 20 10:32:34 2023 UTC debug that shows where the git push error occurs diff bf9a5775e4bca9539f7e1064a16fe20f611028ef 40b0f0fa8f9f421c31757f17284754c53eb8e443 commit - bf9a5775e4bca9539f7e1064a16fe20f611028ef commit + 40b0f0fa8f9f421c31757f17284754c53eb8e443 blob - f08a5f86379cbe0217a47636363ab3ab49ad063b blob + 7c7e5d3ebd3a007abdc4367fa3533f3942762e53 --- lib/serve.c +++ lib/serve.c @@ -208,11 +208,11 @@ announce_refs(int outfd, struct imsgbuf *ibuf, int cli goto done; case GOTD_IMSG_REFLIST: if (have_nrefs || nrefs > 0) { - err = got_error(GOT_ERR_PRIVSEP_MSG); + err = got_error_msg(GOT_ERR_PRIVSEP_MSG, "1"); goto done; } if (datalen != sizeof(ireflist)) { - err = got_error(GOT_ERR_PRIVSEP_MSG); + err = got_error_msg(GOT_ERR_PRIVSEP_MSG, "2"); goto done; } memcpy(&ireflist, imsg.data, sizeof(ireflist)); @@ -224,11 +224,11 @@ announce_refs(int outfd, struct imsgbuf *ibuf, int cli break; case GOTD_IMSG_REF: if (!have_nrefs || nrefs == 0) { - err = got_error(GOT_ERR_PRIVSEP_MSG); + err = got_error_msg(GOT_ERR_PRIVSEP_MSG, "3"); goto done; } if (datalen < sizeof(iref)) { - err = got_error(GOT_ERR_PRIVSEP_MSG); + err = got_error_msg(GOT_ERR_PRIVSEP_MSG, "4"); goto done; } memcpy(&iref, imsg.data, sizeof(iref)); @@ -255,7 +255,7 @@ announce_refs(int outfd, struct imsgbuf *ibuf, int cli break; case GOTD_IMSG_SYMREF: if (!have_nrefs || nrefs == 0) { - err = got_error(GOT_ERR_PRIVSEP_MSG); + err = got_error_msg(GOT_ERR_PRIVSEP_MSG, "5"); goto done; } if (datalen < sizeof(isymref)) { @@ -309,7 +309,7 @@ announce_refs(int outfd, struct imsgbuf *ibuf, int cli nrefs--; break; default: - err = got_error(GOT_ERR_PRIVSEP_MSG); + err = got_error_msg(GOT_ERR_PRIVSEP_MSG, "6"); break; } @@ -554,7 +554,7 @@ recv_want(int *use_sidebands, int outfd, struct imsgbu done = 1; break; default: - err = got_error(GOT_ERR_PRIVSEP_MSG); + err = got_error_msg(GOT_ERR_PRIVSEP_MSG, "7"); break; } @@ -651,7 +651,7 @@ recv_have(int *have_ack, int outfd, struct imsgbuf *ib done = 1; break; default: - err = got_error(GOT_ERR_PRIVSEP_MSG); + err = got_error_msg(GOT_ERR_PRIVSEP_MSG, "8"); break; } @@ -692,7 +692,7 @@ recv_done(int *packfd, int outfd, struct imsgbuf *ibuf err = got_error(GOT_ERR_PRIVSEP_NO_FD); break; default: - err = got_error(GOT_ERR_PRIVSEP_MSG); + err = got_error_msg(GOT_ERR_PRIVSEP_MSG, "9"); break; } @@ -753,7 +753,7 @@ relay_progress_reports(struct imsgbuf *ibuf, int outfd err = got_pkt_writepkt(outfd, buf, 1 + n, chattygot); break; default: - err = got_error(GOT_ERR_PRIVSEP_MSG); + err = got_error_msg(GOT_ERR_PRIVSEP_MSG, "10"); break; } @@ -1047,7 +1047,7 @@ recv_ref_update(int *report_status, int outfd, struct done = 1; break; default: - err = got_error(GOT_ERR_PRIVSEP_MSG); + err = got_error_msg(GOT_ERR_PRIVSEP_MSG, "11"); break; } @@ -1070,7 +1070,7 @@ recv_packfile(struct imsg *imsg, int infd) datalen = imsg->hdr.len - IMSG_HEADER_SIZE; if (datalen != 0) - return got_error(GOT_ERR_PRIVSEP_MSG); + return got_error_msg(GOT_ERR_PRIVSEP_MSG, "13"); if (imsg->fd == -1) return got_error(GOT_ERR_PRIVSEP_NO_FD); @@ -1329,7 +1329,7 @@ serve_write(int infd, int outfd, int gotd_sock, const curstate = STATE_PACKFILE_RECEIVED; break; default: - err = got_error(GOT_ERR_PRIVSEP_MSG); + err = got_error_fmt(GOT_ERR_PRIVSEP_MSG, "14: %d", imsg.hdr.type); break; } @@ -1366,7 +1366,7 @@ serve_write(int infd, int outfd, int gotd_sock, const err = got_pkt_flushpkt(outfd, chattygot); break; default: - err = got_error(GOT_ERR_PRIVSEP_MSG); + err = got_error_msg(GOT_ERR_PRIVSEP_MSG, "15"); break; } ----------------------------------------------- commit 7c045a52e6d559f699fd241c2451ff17de39f7ee (gotd-chroot) from: Stefan Sperling date: Sun Aug 20 12:05:45 2023 UTC fix -portable specific mismerge in serve_write() diff 40b0f0fa8f9f421c31757f17284754c53eb8e443 7c045a52e6d559f699fd241c2451ff17de39f7ee commit - 40b0f0fa8f9f421c31757f17284754c53eb8e443 commit + 7c045a52e6d559f699fd241c2451ff17de39f7ee blob - 7c7e5d3ebd3a007abdc4367fa3533f3942762e53 blob + f016d8400617c19bdb55eec1b8cfca2dda2e0248 --- lib/serve.c +++ lib/serve.c @@ -1313,7 +1313,7 @@ serve_write(int infd, int outfd, int gotd_sock, const case GOTD_IMSG_ERROR: err = gotd_imsg_recv_error(NULL, &imsg); goto done; - case GOTD_IMSG_RECV_PACKFILE: + case GOTD_IMSG_PACKFILE_PIPE: err = recv_packfile(&imsg, infd); if (err) { if (err->code != GOT_ERR_EOF)