这是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导致线程写入失败.

查看内核文件fs / 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检查)才能通过.Thread不满足条件,因为比较的pids不同.

所以我的问题是:这是一个错误吗?为什么不允许特定进程的线程更改loginuid?我在登录应用程序中遇到了这个,它为PAM登录产生了另一个线程.

最佳答案 无论这是否是错误我写了一个修复程序,通过线程扩展写入该文件的权限:

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

你怎么看待这件事?它会影响安全性吗?

点赞