Skip to content

Instantly share code, notes, and snippets.

@christierney
Last active December 21, 2021 19:19
Show Gist options
  • Save christierney/37f3b2d57d51adfa0cb6faed1f6971f9 to your computer and use it in GitHub Desktop.
Save christierney/37f3b2d57d51adfa0cb6faed1f6971f9 to your computer and use it in GitHub Desktop.
Reprex demonstrating buggy behavior in docker-for-mac on M1 hardware. Attempting to build and run this image from an M1 machine using `--platform Linux/amd64` will result in an "Operation not permitted" error from one of the `initgroups` calls.
FROM ubuntu:bionic-20201119
RUN export DEBIAN_FRONTEND=noninteractive && \
apt-get update && \
apt-get install -y \
gcc && \
rm -rf /var/lib/apt/lists/*
ARG USER_GID=1001
ARG USER_UID=1001
# Create a non-root user with known id:gid that our script will switch to
RUN groupadd -g $USER_GID notroot && \
useradd -u $USER_UID -g notroot notroot
COPY ./forkandinit.c /
RUN gcc /forkandinit.c -o /forkandinit
CMD ["/forkandinit"]
#include <stdio.h>
#include <grp.h>
#include <errno.h>
#include <pwd.h>
#include <sys/wait.h>
int main() {
errno = 0;
uid_t root = 0;
uid_t uid = 1001; // nonroot
gid_t gid = 1001; // nonroot
pid_t pid = 0;
pid_t terminated = 0;
int wstatus = 0;
printf("parent: dropping privileges, forking, and restoring privileges:\n");
if (setresgid(-1, gid, getegid()) < 0)
perror("parent: setresgid error");
if (setresuid(-1, uid, geteuid()) < 0)
perror("parent: setresuid error");
printf("parent: forking\n");
// emit buffered messages before forking.
fflush(stdout);
fflush(stderr);
pid = fork();
if (pid == 0) {
// The child.
printf("child: forked\n");
// Change the effective user to root.
if (seteuid(root) < 0)
perror("child: seteuid error");
// Get user info to use in group calls
struct passwd* pPrivPasswd = getpwuid(root);
if (pPrivPasswd == NULL)
printf("child:failed to load root passwd data\n");
// init supplemental groups
if (initgroups(pPrivPasswd->pw_name, pPrivPasswd->pw_gid) < 0)
perror("child: initgroups error");
printf("child: done\n");
} else {
// The parent.
printf("parent: waiting\n");
terminated = wait(&wstatus);
printf("parent: done\n");
}
return(0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment