2015-07-21 6 views
10

Ich habe ein kleines Programm, das versucht, ein Pseudoterminal nach unshare zu erstellen. der Ausgang ist:grantpt Bericht Fehler nach unshare

uid before unshare:5000 
uid after unshare:0 
Grant pt Error: : Permission denied 

Der 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 

Wenn ich flag |= CLONE_NEWUSER; entfernen, wird es nicht gemeldeten Fehler. Kannst du erklären, warum das passiert? Danke im Voraus!

Antwort

5

Da ich das gleiche Problem hatte, habe ich auch in diesem Thema untersucht. Hier sind meine Ergebnisse:

grantpt(3) versucht, um sicherzustellen, dass der Slave-Pseudo-Terminal seine Gruppe auf die speziellen tty Gruppe gesetzt hat (oder was auch immer TTY_GROUP ist, wenn glibc kompiliert):

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; 

    /* Get the group ID of the special `tty' group. */ 
    if (grbuflen == (size_t) -1L) 
     /* `sysconf' does not support _SC_GETGR_R_SIZE_MAX. 
     Try a 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 the group of the device is that special group. */ 
if (st.st_gid != gid) 
    { 
    if (__chown (buf, uid, gid) < 0) 
     goto helper; 
    } 

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

Auf meinem System ist die tty Gruppe 5. Diese Gruppe ist jedoch nicht in Ihrem Benutzernamespace zugeordnet und die chown(2) schlägt fehl, weil die GID 5 nicht vorhanden ist. glibc fällt dann zurück auf die Ausführung des pt_chown-Helfers, der ebenfalls fehlschlägt. Ich habe die Details, warum es fehlschlägt, nicht untersucht, aber ich nehme an, es liegt daran, dass es niemanden definiert, es sei denn, Sie haben den Benutzer root Ihrem Benutzer-Namespace zugeordnet. Hier ist Strace Ausgang, der die fehlgeschlagene Operation zeigt:

[pid 30] chown("/dev/pts/36", 1000, 5) = -1 EINVAL (Invalid argument) 

Die Ihnen ein paar Methoden gibt, um dieses Problem zu umgehen:

  • Karte die erforderlichen Gruppen (dh tty), die unter Umständen nicht möglich, ohne CAP_SYS_ADMIN in der Binärdatei, die den Benutzernamen öffnet
  • Verwenden Sie Sububstanzen und Subgids zusammen mit newuidmap(1) und newgidmap(1), um diese Gruppen verfügbar (dies könnte funktionieren, aber ich habe es nicht getestet).
  • Nehmen Sie Änderungen vor, die das Fehlschlagen des chown(2)-Aufrufs vermeiden, z. Verwenden Sie einen Mount-Namespace und ändern Sie die GID der tty-Gruppe in /etc/groups in die GID Ihres Benutzers.
  • Vermeiden Sie den chown(2) Anruf, z. indem Sie die st.st_gid != gid Prüfung falsch machen; Dies sollte möglich sein, indem Sie die tty-Gruppe aus dem Ziel-Mount-Namespace /etc/groups löschen. Natürlich kann das andere Probleme verursachen.
+0

danke, sehr hilfreich – Sven