2017-01-31 1 views
4

Il y a une possibilité que j'ai trouvé un bogue dans le noyau Linux. Considérons l'application qui écrit dans/proc/self/loginuid à partir du thread principal et d'un thread auxiliaire. Le code est ci-dessous:S'agit-il d'un bogue dans le noyau Linux concernant l'écriture dans/proc/self/loginuid?

#include <stdio.h> 
#include <pthread.h> 
#include <sys/syscall.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 

void write_loginuid(char *str) 
{ 
    int fd; 

    printf("%s\n", str); 

    fd = open("/proc/self/loginuid", O_RDWR); 

    if (fd < 0) { 
     perror(str); 
     return; 
    } 

    if (write(fd, "0", 2) != 2) { 
     printf("write\n"); 
     perror(str); 
    } 

    close(fd); 
} 

void *thread_function(void *arg) 
{ 
    fprintf(stderr, "Hello from thread! my pid = %u, tid = %u, parent pid = %u\n", getpid(), syscall(SYS_gettid), getppid()); 

    write_loginuid("thread"); 

    return NULL; 
} 

int main() 
{ 
    pthread_t thread; 

    pthread_create(&thread, NULL, thread_function, NULL); 

    write_loginuid("main process"); 

    fprintf(stderr, "test my pid = %u, tid = %u, parent pid = %u\n", getpid(), syscall(SYS_gettid), getppid()); 

    pthread_join(thread, NULL); 
    return 0; 
} 

Après l'exécution de cette application, nous obtenons:

main process 
test my pid = 3487, tid = 3487, parent pid = 3283 
Hello from thread! my pid = 3487, tid = 3488, parent pid = 3283 
thread 
write 
thread: Operation not permitted 

qui nous dit l'écriture de fil échoué par -EPERM.

En regardant le fichier du noyau fs/proc/base.c et la fonction proc_loginuid_write(), nous voyons à la vérification de début:

static ssize_t proc_loginuid_write(struct file * file, const char __user * buf, 
        size_t count, loff_t *ppos) 
{ 
    struct inode * inode = file_inode(file); 
    uid_t loginuid; 
    kuid_t kloginuid; 
    int rv; 

    /* this is the probably buggy check */ 
    rcu_read_lock(); 
    if (current != pid_task(proc_pid(inode), PIDTYPE_PID)) { 
     rcu_read_unlock(); 
     return -EPERM; 
    } 
    rcu_read_unlock(); 

Alors, en regardant le code ci-dessus, nous voyons que seulement pour PID exact (vérifié par moi avec printks) nous passons à travers. Thread ne satisfait pas la condition, parce que les pids comparés diffère. Donc, ma question est la suivante: est-ce un bug? Pourquoi ne pas autoriser les threads d'un processus particulier à changer le loginuid? J'ai rencontré cela dans l'application de connexion qui a engendré un autre thread pour la connexion PAM.

+0

Votre thread a un PID différent puisqu'il s'agit d'un enfant dans un groupe. Le PID du parent est en fait celui qui est vérifié là comme je peux le supposer. – 0andriy

+0

Oui, c'est le problème tel que je l'ai décrit. Même processus, différents threads. Et seulement un d'entre eux a accès à/proc/self/loginuid. La question est pourquoi cela se produit? Est-ce un bug ou un comportement intentionnel? – sibislaw

Répondre

1

Que ce soit bug ou non i écrit un correctif qui étend l'autorisation de l'écriture de ce fichier par des fils:

rcu_read_lock(); 
/* 
* I changed the condition that it checks now the tgid as returned in sys_getpid() 
* rather than task_struct pointers 
*/ 
if (task_tgid_vnr(current) != task_tgid_vnr(pid_task(proc_pid(inode), PIDTYPE_PID))) { 
    rcu_read_unlock(); 
    return -EPERM; 
} 
rcu_read_unlock(); 

Que pensez-vous à ce sujet? Cela affecte-t-il la sécurité?

+1

Cela devrait faire partie de la question, pas une réponse. –