这是 linux 内核中关于写入 /proc/self/loginuid 的错误吗?

sib*_*law 5 linux linux-device-driver linux-kernel

我有可能在 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;
}
Run Code Online (Sandbox Code Playgroud)

执行此应用程序后,我们得到:

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
Run Code Online (Sandbox Code Playgroud)

这告诉我们线程写入失败 -EPERM。

查看内核文件 fs/proc/base.c 和函数 proc_loginuid_write() 我们看到开头检查:

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
Run Code Online (Sandbox Code Playgroud)

因此,查看上面的代码,我们看到仅对于我们通过的精确 PID(由我使用 printks 检查)。Thread 不满足条件,因为比较的 pids 不同。

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

sib*_*law 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();
Run Code Online (Sandbox Code Playgroud)

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