aboutsummaryrefslogtreecommitdiffstats
path: root/git-protection.c
diff options
context:
space:
mode:
authorMattias Andrée <m@maandree.se>2026-03-04 18:51:23 +0100
committerMattias Andrée <m@maandree.se>2026-03-04 18:53:28 +0100
commit15d3290b1d95cedaf4e671fe346beb11dcd12ac9 (patch)
tree86c959933f7574104cc5d16c0c0122d40842bed1 /git-protection.c
downloadgit-protection-15d3290b1d95cedaf4e671fe346beb11dcd12ac9.tar.gz
git-protection-15d3290b1d95cedaf4e671fe346beb11dcd12ac9.tar.bz2
git-protection-15d3290b1d95cedaf4e671fe346beb11dcd12ac9.tar.xz
First commitHEAD1.0master
Signed-off-by: Mattias Andrée <m@maandree.se>
Diffstat (limited to 'git-protection.c')
-rw-r--r--git-protection.c98
1 files changed, 98 insertions, 0 deletions
diff --git a/git-protection.c b/git-protection.c
new file mode 100644
index 0000000..6084c74
--- /dev/null
+++ b/git-protection.c
@@ -0,0 +1,98 @@
+/* See LICENSE file for copyright and license details. */
+#include <sys/mount.h>
+#include <sched.h>
+#include <libsimple.h>
+#include <libsimple-arg.h>
+
+NUSAGE(125, "utility [argument] ...");
+
+
+int
+main(int argc, char *argv[])
+{
+ int fds[2], status;
+ pid_t pid;
+ char *dir = NULL;
+ size_t dirsize = 0;
+ size_t dirlen = 0;
+ ssize_t r;
+
+ libsimple_default_failure_exit = 125;
+
+ ARGBEGIN {
+ default:
+ usage();
+ } ARGEND;
+
+ if (!argc)
+ usage();
+
+ if (unshare(CLONE_NEWNS))
+ eprintf("unshare CLONE_NEWNS:");
+ if (mount("none", "/", NULL, MS_REC | MS_SLAVE, NULL))
+ eprintf("mount none / NULL MS_REC|MS_SLAVE NULL:");
+
+ if (pipe(fds))
+ eprintf("pipe:");
+ pid = fork();
+ if (pid < 0)
+ eprintf("fork:");
+ if (pid == 0) {
+ if (setegid(getgid()))
+ eprintf("setegid <real group>:");
+ if (seteuid(getuid()))
+ eprintf("seteuid <real user>:");
+
+ close(fds[0]);
+ if (fds[1] != STDOUT_FILENO) {
+ if (dup2(fds[1], STDOUT_FILENO) != STDOUT_FILENO)
+ eprintf("dup2 <pipe> STDOUT_FILENO:");
+ close(fds[1]);
+ }
+ execlp(GIT_PATH, "git", "rev-parse", "--show-toplevel", NULL);
+ eprintf("execlp %s:", GIT_PATH);
+ }
+ close(fds[1]);
+ for (;;) {
+ if (dirlen == dirsize)
+ dir = erealloc(dir, dirsize += 512u);
+ r = read(fds[0], &dir[dirlen], dirsize - dirlen);
+ if (r <= 0) {
+ if (!r)
+ break;
+ if (errno == EINTR)
+ continue;
+ eprintf("read <pipe>:");
+ }
+ dirlen += (size_t)r;
+ if (!dirlen || dir[--dirlen] != '\n')
+ eprintf("received invalid output from `git rev-parse --show-toplevel`");
+ }
+ close(fds[0]);
+ if (waitpid(pid, &status, 0) != pid)
+ eprintf("waitpid <subprocess>:");
+ if (status) {
+ if (WIFSIGNALED(status))
+ eprintf("subprocess git was killed by signal %i\n", WTERMSIG(status));
+ exit(libsimple_default_failure_exit);
+ }
+ if (dirsize - dirlen < sizeof("/.git"))
+ dir = erealloc(dir, dirlen + sizeof("/.git"));
+ stpcpy(&dir[dirlen], "/.git");
+
+ if (mount(dir, dir, NULL, MS_BIND, NULL))
+ eprintf("mount %s %s NULL MS_BIND NULL:", dir, dir);
+ if (mount("none", dir, NULL, MS_BIND | MS_REMOUNT | MS_RDONLY, NULL))
+ eprintf("mount none %s NULL MS_BIND|MS_REMOUNT|MS_RDONLY NULL:", dir);
+
+ free(dir);
+
+ if (setegid(getgid()))
+ eprintf("setegid <real group>:");
+ if (seteuid(getuid()))
+ eprintf("seteuid <real user>:");
+
+ execvp(argv[0], argv);
+ enprintf(errno == ENOENT ? 127 : 126, "execvp %s:", argv[0]);
+ return 0;
+}