i have small program, tries create pseudoterminal after unshare. output is:
uid before unshare:5000 uid after unshare:0 grant pt error: : permission denied the code:
#define _gnu_source #include <sys/mount.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <fcntl.h> #include <errno.h> #include <sched.h> void set_uid_map(pid_t pid, int inside_id, int outside_id, int length) { char path[256]; sprintf(path, "/proc/%d/uid_map", getpid()); file* uid_map = fopen(path, "w"); fprintf(uid_map, "%d %d %d", inside_id, outside_id, length); fclose(uid_map); } void set_gid_map(pid_t pid, int inside_id, int outside_id, int length) { char path[256]; sprintf(path, "/proc/%d/gid_map", getpid()); file* gid_map = fopen(path, "w"); fprintf(gid_map, "%d %d %d", inside_id, outside_id, length); fclose(gid_map); } int main(void) { int master; int flag = 0; flag |= clone_newuser; flag |= clone_newns; flag |= clone_newipc; flag |= clone_newnet; flag |= clone_newuts; flag |= clone_newpid; printf("uid before unshare:%d \n", (int) getuid()); unshare(flag); set_uid_map(getpid(), 0, 5000, 1); set_gid_map(getpid(), 0, 5000, 1); printf("uid after unshare:%d \n", (int) getuid()); if ( ( master = posix_openpt(o_rdwr | o_noctty) ) < 0) perror("openpt error: "); if ( grantpt(master) < 0 ) perror("grant pt error: "); unlockpt(master); return 0; } // main if remove flag |= clone_newuser;, there not error reported. can explain why happens? in advance!
since i've had same issue have looked this. here findings:
grantpt(3) tries ensure slave pseudo terminal has group set special tty group (or whatever tty_group when compiling glibc):
static int tty_gid = -1; if (__glibc_unlikely (tty_gid == -1)) { char *grtmpbuf; struct group grbuf; size_t grbuflen = __sysconf (_sc_getgr_r_size_max); struct group *p; /* group id of special `tty' group. */ if (grbuflen == (size_t) -1l) /* `sysconf' not support _sc_getgr_r_size_max. try moderate value. */ grbuflen = 1024; grtmpbuf = (char *) __alloca (grbuflen); __getgrnam_r (tty_group, &grbuf, grtmpbuf, grbuflen, &p); if (p != null) tty_gid = p->gr_gid; } gid_t gid = tty_gid == -1 ? __getgid () : tty_gid; /* make sure group of device special group. */ if (st.st_gid != gid) { if (__chown (buf, uid, gid) < 0) goto helper; } on system, tty group 5. however, group isn't mapped user namespace , chown(2) fails because gid 5 doesn't exist. glibc falls executing pt_chown helper, fails. haven't looked details of why fails, assume it's because it's setuid nobody unless mapped root user user namespace. here's strace output shows failing operation:
[pid 30] chown("/dev/pts/36", 1000, 5) = -1 einval (invalid argument) the gives couple of methods work around problem:
- map required groups (i.e.
tty), may not possible withoutcap_sys_adminin binary opens user namespace - use subuids , subgids
newuidmap(1),newgidmap(1)make these groups available (this might work, haven't tested it). - make changes avoid failure of
chown(2)call, e.g. using mount namespace , changing gid ofttygroup in/etc/groupsuser's gid. - avoid
chown(2)call, e.g. makingst.st_gid != gidcheck false; should possible deletingttygroup target mount namespace's/etc/groups. of course, may cause other problems.
Comments
Post a Comment