2017-01-31 6 views
4

Возможно, я обнаружил ошибку в ядре linux. Рассмотрим приложение, которое пишет в/proc/self/loginuid из основного потока и одного вспомогательного потока. Код ниже:Является ли это ошибкой в ​​ядре linux относительно записи в/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; 
} 

После выполнения этого приложения мы получаем:

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 

Это говорит нам нить ошибки записи по -EPERM.

Глядя на файле ядра фс/Proc/base.c и функция proc_loginuid_write() мы видим в начале проверки:

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(); 

Таким образом, глядя на код выше, мы видим, что только для точного PID (проверяется мной с помощью printks), мы проходим через. Труд не удовлетворяет условию, потому что сравниваются pids.

Так что мой вопрос: это ошибка? Почему бы не позволить потоку конкретного процесса изменять loginuid? Я столкнулся с этим в приложении для входа, который породил другой поток для входа в систему PAM.

+0

Ваша нить отличается от PID, так как это ребенок в группе. Патент PID на самом деле тот, который проверяется там, как я могу предположить. – 0andriy

+0

Да, это проблема, как я ее описал. Тот же процесс, разные потоки. И только один из них имеет доступ к/proc/self/loginuid. Вопрос в том, почему это происходит? Это ошибка или преднамеренное поведение? – sibislaw

ответ

1

ли это ошибка или нет я написал фикс, который расширяет письменного разрешения на этот файл нитками:

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(); 

Что вы думаете об этом? Это влияет на безопасность?

+1

Это должно быть частью вопроса, а не ответа. –