c - grantpt report error after unshare -


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;   } 

see https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/grantpt.c;h=c04c85d450f9296efa506121bcee022afda3e2dd;hb=head#l137.

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 without cap_sys_admin in 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 of tty group in /etc/groups user's gid.
  • avoid chown(2) call, e.g. making st.st_gid != gid check false; should possible deleting tty group target mount namespace's /etc/groups. of course, may cause other problems.

Comments