Skip to content

Commit

Permalink
non-root: extend zdtm.py to be able to run tests as non-root
Browse files Browse the repository at this point in the history
This are the minimal changes to make zdtm.py successfully run the
env00 and pthread test case as non-root using the '--rootless' zdtm option.

Signed-off-by: Adrian Reber <[email protected]>
  • Loading branch information
adrianreber committed May 3, 2021
1 parent 98732b8 commit f895c0e
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 57 deletions.
41 changes: 36 additions & 5 deletions test/zdtm.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@

prev_line = None

NON_ROOT_UID = 65534


def alarm(*args):
print("==== ALARM ====")
Expand Down Expand Up @@ -436,6 +438,8 @@ def __wait_task_die(self):
wait_pid_die(int(self.__pid), self.__name, self.__timeout)

def __add_wperms(self):
if os.getuid() != 0:
return
# Add write perms for .out and .pid files
for b in self._bins:
p = os.path.dirname(b)
Expand Down Expand Up @@ -612,11 +616,15 @@ def available():
subprocess.check_call(["make", "zdtm_ct"])
if not os.access("zdtm/lib/libzdtmtst.a", os.F_OK):
subprocess.check_call(["make", "-C", "zdtm/"])
if opts['rootless'] or os.getuid() != 0:
return
subprocess.check_call(
["flock", "zdtm_mount_cgroups.lock", "./zdtm_mount_cgroups"])

@staticmethod
def cleanup():
if opts['rootless'] or os.getuid() != 0:
return
subprocess.check_call(
["flock", "zdtm_mount_cgroups.lock", "./zdtm_umount_cgroups"])

Expand Down Expand Up @@ -1025,6 +1033,7 @@ def __init__(self, opts):
self.__dedup = bool(opts['dedup'])
self.__mdedup = bool(opts['noauto_dedup'])
self.__user = bool(opts['user'])
self.__rootless = bool(opts['rootless'])
self.__leave_stopped = bool(opts['stop'])
self.__stream = bool(opts['stream'])
self.__criu = (opts['rpc'] and criu_rpc or criu_cli)
Expand Down Expand Up @@ -1110,6 +1119,9 @@ def __criu_act(self, action, opts=[], log=None, nowait=False):

print("Run criu " + action)

if self.__rootless or os.getuid() != 0:
s_args += ["--unprivileged"]

strace = []
if self.__sat:
fname = os.path.join(self.__ddir(), action + '.strace')
Expand All @@ -1128,7 +1140,10 @@ def __criu_act(self, action, opts=[], log=None, nowait=False):
if action == "restore":
preexec = None
else:
preexec = self.__user and self.set_user_id or None
if os.getuid():
preexec = None
else:
preexec = self.__user and self.set_user_id or None

__ddir = self.__ddir()

Expand Down Expand Up @@ -1287,6 +1302,9 @@ def dump(self, action, opts=[]):
os.mkdir(self.__ddir())
os.chmod(self.__ddir(), 0o777)

if self.__rootless:
os.setgid(NON_ROOT_UID)
os.setuid(NON_ROOT_UID)
a_opts = ["-t", self.__test.getpid()]
if self.__prev_dump_iter:
a_opts += [
Expand Down Expand Up @@ -1362,6 +1380,9 @@ def dump(self, action, opts=[]):
raise test_fail_exc("criu page-server exited with %d" % ret)

def restore(self):
if self.__rootless:
os.setgid(NON_ROOT_UID)
os.setuid(NON_ROOT_UID)
r_opts = []
if self.__restore_sibling:
r_opts = ["--restore-sibling"]
Expand Down Expand Up @@ -1431,9 +1452,11 @@ def check(feature):
except Exception:
return False

return criu_cli.run(
"check", ["--no-default-config", "-v0", "--feature", feature],
opts['criu_bin']) == 0
args = ["--no-default-config", "-v0", "--feature", feature]
if opts['rootless'] or os.getuid() != 0:
args += ["--unprivileged"]

return criu_cli.run("check", args, opts['criu_bin']) == 0

@staticmethod
def available():
Expand Down Expand Up @@ -1975,7 +1998,7 @@ def run_test(self, name, desc, flavor):
'sat', 'script', 'rpc', 'lazy_pages', 'join_ns', 'dedup', 'sbs',
'freezecg', 'user', 'dry_run', 'noauto_dedup',
'remote_lazy_pages', 'show_stats', 'lazy_migrate', 'stream',
'tls', 'criu_bin', 'crit_bin', 'pre_dump_mode')
'tls', 'criu_bin', 'crit_bin', 'pre_dump_mode', 'rootless')
arg = repr((name, desc, flavor, {d: self.__opts[d] for d in nd}))

if self.__use_log:
Expand All @@ -1985,6 +2008,9 @@ def run_test(self, name, desc, flavor):
logf = None
log = None

if opts['rootless'] and os.getuid() == 0:
os.setgid(NON_ROOT_UID)
os.setuid(NON_ROOT_UID)
sub = subprocess.Popen(["./zdtm_ct", "zdtm.py"],
env=dict(os.environ, CR_CT_TEST_INFO=arg),
stdout=log,
Expand Down Expand Up @@ -2595,6 +2621,11 @@ def clean_stuff(opts):
action='store_true')
rp.add_argument("--freezecg", help="Use freeze cgroup (path:state)")
rp.add_argument("--user", help="Run CRIU as regular user", action='store_true')
rp.add_argument(
"--rootless",
help="Run CRIU rootless (uid!=0) (needs CAP_CHECKPOINT_RESTORE)",
action='store_true'
)
rp.add_argument("--rpc",
help="Run CRIU via RPC rather than CLI",
action='store_true')
Expand Down
51 changes: 28 additions & 23 deletions test/zdtm/lib/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ int write_pidfile(int pid)

void test_init(int argc, char **argv)
{
uid_t uid;
pid_t pid;
char *val;
struct sigaction sa = {
Expand All @@ -219,6 +220,8 @@ void test_init(int argc, char **argv)
};
sigemptyset(&sa.sa_mask);

uid = getuid();

parseargs(argc, argv);

val = getenv("ZDTM_NEWNS");
Expand All @@ -238,34 +241,36 @@ void test_init(int argc, char **argv)
exit(1);
}

val = getenv("ZDTM_GROUPS");
if (val) {
char *tok = NULL;
unsigned int size = 0, groups[NGROUPS_MAX];

tok = strtok(val, " ");
while (tok) {
size++;
groups[size - 1] = atoi(tok);
tok = strtok(NULL, " ");
if (!uid) {
val = getenv("ZDTM_GROUPS");
if (val) {
char *tok = NULL;
unsigned int size = 0, groups[NGROUPS_MAX];

tok = strtok(val, " ");
while (tok) {
size++;
groups[size - 1] = atoi(tok);
tok = strtok(NULL, " ");
}

if (setgroups(size, groups)) {
fprintf(stderr, "Can't set groups: %m");
exit(1);
}
}

if (setgroups(size, groups)) {
fprintf(stderr, "Can't set groups: %m");
val = getenv("ZDTM_GID");
if (val && (setgid(atoi(val)) == -1)) {
fprintf(stderr, "Can't set gid: %m");
exit(1);
}
}

val = getenv("ZDTM_GID");
if (val && (setgid(atoi(val)) == -1)) {
fprintf(stderr, "Can't set gid: %m");
exit(1);
}

val = getenv("ZDTM_UID");
if (val && (setuid(atoi(val)) == -1)) {
fprintf(stderr, "Can't set gid: %m");
exit(1);
val = getenv("ZDTM_UID");
if (val && (setuid(atoi(val)) == -1)) {
fprintf(stderr, "Can't set gid: %m");
exit(1);
}
}

if (prctl(PR_SET_DUMPABLE, 1)) {
Expand Down
64 changes: 35 additions & 29 deletions test/zdtm_ct.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,46 +93,52 @@ static int create_timens()

int main(int argc, char **argv)
{
uid_t uid;
pid_t pid;
int status;

uid = getuid();

/*
* pidns is used to avoid conflicts
* mntns is used to mount /proc
* net is used to avoid conflicts of parasite sockets
*/
if (unshare(CLONE_NEWNS | CLONE_NEWPID | CLONE_NEWNET | CLONE_NEWIPC))
return 1;
if (!uid)
if (unshare(CLONE_NEWNS | CLONE_NEWPID | CLONE_NEWNET | CLONE_NEWIPC))
return 1;
pid = fork();
if (pid == 0) {
if (create_timens())
exit(1);
if (mount(NULL, "/", NULL, MS_REC | MS_SLAVE, NULL)) {
fprintf(stderr, "mount(/, S_REC | MS_SLAVE)): %m");
return 1;
}
umount2("/proc", MNT_DETACH);
umount2("/dev/pts", MNT_DETACH);
if (mount("zdtm_proc", "/proc", "proc", 0, NULL)) {
fprintf(stderr, "mount(/proc): %m");
return 1;
if (!uid) {
if (create_timens())
exit(1);
if (mount(NULL, "/", NULL, MS_REC | MS_SLAVE, NULL)) {
fprintf(stderr, "mount(/, S_REC | MS_SLAVE)): %m");
return 1;
}
umount2("/proc", MNT_DETACH);
umount2("/dev/pts", MNT_DETACH);
if (mount("zdtm_proc", "/proc", "proc", 0, NULL)) {
fprintf(stderr, "mount(/proc): %m");
return 1;
}
if (mount("zdtm_devpts", "/dev/pts", "devpts", 0,
"newinstance,ptmxmode=0666")) {
fprintf(stderr, "mount(pts): %m");
return 1;
}
if (mount("zdtm_binfmt", "/proc/sys/fs/binfmt_misc", "binfmt_misc", 0,
NULL)) {
fprintf(stderr, "mount(binfmt_misc): %m");
return 1;
}
if (mount("/dev/pts/ptmx", "/dev/ptmx", NULL, MS_BIND, NULL)) {
fprintf(stderr, "mount(ptmx): %m");
return 1;
}
if (system("ip link set up dev lo"))
return 1;
}
if (mount("zdtm_devpts", "/dev/pts", "devpts", 0,
"newinstance,ptmxmode=0666")) {
fprintf(stderr, "mount(pts): %m");
return 1;
}
if (mount("zdtm_binfmt", "/proc/sys/fs/binfmt_misc", "binfmt_misc", 0,
NULL)) {
fprintf(stderr, "mount(binfmt_misc): %m");
return 1;
}
if (mount("/dev/pts/ptmx", "/dev/ptmx", NULL, MS_BIND, NULL)) {
fprintf(stderr, "mount(ptmx): %m");
return 1;
}
if (system("ip link set up dev lo"))
return 1;
execv(argv[1], argv + 1);
fprintf(stderr, "execve: %m");
return 1;
Expand Down

0 comments on commit f895c0e

Please sign in to comment.