【问题标题】:Why the printk console_loglevel can be lower than minimum_console_loglevel?为什么 printk console_loglevel 会低于 minimum_console_loglevel?
【发布时间】:2015-07-09 07:19:26
【问题描述】:

我的Linux 发行版是RHEL7,内核版本是3.10.0

形成printk文档,我知道minimum_console_loglevel定义:

  • minimum_console_loglevel:最小(最高)值 console_loglevel 可以设置

查询printk的当前日志级别:

[root@localhost kernel]# cat /proc/sys/kernel/printk
7       4       1       7

修改当前控制台日志级别:

[root@localhost kernel]# echo 0 > /proc/sys/kernel/printk
[root@localhost kernel]# cat /proc/sys/kernel/printk
0       4       1       7

据我了解,minimum_console_loglevel1,因此将console_loglevel 修改为0 应该会失败。但从 cat 输出来看,似乎成功了。

来自printk.c代码:

case SYSLOG_ACTION_CONSOLE_LEVEL:
        error = -EINVAL;
        if (len < 1 || len > 8)
            goto out;
        if (len < minimum_console_loglevel)
            len = minimum_console_loglevel;
        console_loglevel = len;
        /* Implicitly re-enable logging to console */
        saved_console_loglevel = -1;
        error = 0;
        break;

我也认为不应修改 console_loglevel 值。

【问题讨论】:

    标签: c linux linux-kernel rhel printk


    【解决方案1】:

    您正在查看错误的代码。 /proc/sys/kernel/printkkernel/sysctl.c 提供。 printklooks like this的定义:

    {
        .procname       = "printk",
        .data           = &console_loglevel,
        .maxlen         = 4*sizeof(int),
        .mode           = 0644,
        .proc_handler   = proc_dointvec,
    },
    

    这定义了一个名为printk 的文件,它控制一个包含 4 个元素的 int 数组。至关重要的是,处理函数proc_dointvec 是一个对整数数组进行操作的通用函数,它不验证其参数

    因此,作为 root,您可以将任何垃圾编号写入/proc/sys/kernel/printk,内核会很乐意接受它们。演示:

    root@ubuntu:/proc/sys/kernel# echo '-989897 42 -2147483648 0' > printk
    root@ubuntu:/proc/sys/kernel# cat printk
    -989897 42  -18446744071562067968   0
    

    (第三个实际上是我刚刚发现的一个有趣且可能无害的错误......)

    printk.h可以看出,四个日志级别的参数是直接从这个四元素数组派生而来的:

    extern int console_printk[];
    
    #define console_loglevel (console_printk[0])
    #define default_message_loglevel (console_printk[1])
    #define minimum_console_loglevel (console_printk[2])
    #define default_console_loglevel (console_printk[3])
    

    那么,那么,您发布的代码是做什么的呢?它实现了syslog 系统调用,正如函数名(do_syslog)所指出的那样。正如the man page所指出的:

       SYSLOG_ACTION_CONSOLE_LEVEL (8)
              The call sets console_loglevel to the value given in len,
              which must be an integer between 1 and 8 (inclusive).  The
              kernel silently enforces a minimum value of
              minimum_console_loglevel for len.  See the log level section
              for details.  The bufp argument is ignored.
    

    我们可以看到syslog 系统调用还允许您设置控制台日志级别,但它实际上会检查这些值是否有效。让我们用一个简单的测试程序进行测试(注意 glibc 调用函数 klogctl 而不是 syslog,因为用户空间 syslog 函数做了其他事情):

    #include <sys/klog.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <errno.h>
    #include <string.h>
    #include <stdlib.h>
    
    #define SYSLOG_ACTION_CONSOLE_LEVEL 8
    
    int main(int argc, char **argv) {
        if(klogctl(SYSLOG_ACTION_CONSOLE_LEVEL, NULL, atoi(argv[1])) < 0) {
            perror("klogctl");
        } else {
            printf("klogctl succeeded\n");
        }
        return 0;
    }
    

    运行它(在将printk重置为7 4 1 7之后):

    root@ubuntu:/tmp# ./test 1 ; cat /proc/sys/kernel/printk
    klogctl succeeded
    1   4   1   7
    root@ubuntu:/tmp# ./test 0 ; cat /proc/sys/kernel/printk
    klogctl: Invalid argument
    1   4   1   7
    

    因此您可以看到syslog(通过klogctl 调用)确实检查了您的参数的有效性。

    【讨论】:

    • 非常感谢您的详细解答!另一个问题。据我了解,由于proc_dointve 不进行整数检查,我们可以绕过minimum_console_loglevel,对吗?如果它是正确的,它应该被认为是一个错误吗?谢谢!
    • 也许它可以被认为是一个错误,但我认为验证 sysctl 文件并不是重点。 (您可以尝试提交错误报告...)
    • 非常感谢您的时间和详细的解释!
    猜你喜欢
    • 2019-07-25
    • 2019-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-28
    • 1970-01-01
    • 1970-01-01
    • 2017-08-29
    相关资源
    最近更新 更多