为什么pam_loginuid模块在使用-EPERM写入/ proc / self / loginuid时失败?

时间:2017-01-27 13:03:39

标签: linux-kernel linux-device-driver

我发现使用pam库进行身份验证的应用程序在出错时失败:

Error writing /proc/self/loginuid: Operation not permitted

通过strace我发现写入/ proc / self / loginuid文件时失败。

进一步检查并向内核添加一些调试代码(下面的代码):

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;

    printk(KERN_DEBUG "proc_loginuid_write\n");

    printk(KERN_DEBUG "a+++ %s\n", current->comm);
    printk(KERN_DEBUG "b+++ %s\n", pid_task(proc_pid(inode), PIDTYPE_PID)->comm);
    printk(KERN_DEBUG "+++2++ pid = %d\n", current->pid);
    printk(KERN_DEBUG "+++3++ pid = %d\n", pid_task(proc_pid(inode), PIDTYPE_PID)->pid);

    rcu_read_lock();
    if (current != pid_task(proc_pid(inode), PIDTYPE_PID)) {
        rcu_read_unlock();
        printk(KERN_ERR "proc_loginuid_write failed by permission!\n");
        return -EPERM;
    }
    rcu_read_unlock();


    if (*ppos != 0) {
        /* No partial writes. */
        return -EINVAL;
    }

    rv = kstrtou32_from_user(buf, count, 10, &loginuid);
    if (rv < 0)
        return rv;

    /* is userspace tring to explicitly UNSET the loginuid? */
    if (loginuid == AUDIT_UID_UNSET) {
        kloginuid = INVALID_UID;
    } else {
        kloginuid = make_kuid(file->f_cred->user_ns, loginuid);
        if (!uid_valid(kloginuid))
            return -EINVAL;
    }

    rv = audit_set_loginuid(kloginuid);
    if (rv < 0)
        return rv;
    return count;
}

在dmesg中显示:

[   30.672242] proc_loginuid_write
[   30.672249] a+++ testapp
[   30.672251] b+++ testapp
[   30.672254] +++2++ pid = 2920
[   30.672257] +++3++ pid = 2451
[   30.672259] proc_loginuid_write failed by permission!

名称testapp是故意更改名称。所以看起来文件/ proc / self / loginuid是父文件创建的文件,它由子线程读取。

我在内核3.14和4.9上测试了相同的代码,在3.14内核上运行了它,在内核4.9上它不起作用。为什么呢?

1 个答案:

答案 0 :(得分:0)

我找到了问题的解决方案。

内核3.14 已关闭配置中的选项 CONFIG_AUDITSYSCALL 。所以没有文件/ proc / self / loginuid和pam模块在没有这样的文件时根本不在乎。

CONFIG_AUDIT = y 会自动选择较新的内核4.9 选项。 最简单的解决方案是关闭 CONFIG_AUDIT 选项,但是为什么在内核演化过程中 CONFIG_AUDITSYSCALL 成为一个不可控制的选项是其他问题的问题。

谢谢!