1

我的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值不应该被修改。

4

1 回答 1

1

您正在查看错误的代码。/proc/sys/kernel/printk由 提供kernel/sysctl.c。的定义printk 如下所示

{
    .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) 所指出的那样。如手册页所述

   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(调用 via klogctl)确实检查了你的参数的有效性。

于 2015-07-10T05:34:27.840 回答