【问题标题】:What makes printk() write to the console even if it begins with KERN_INFO?是什么让 printk() 写入控制台,即使它以 KERN_INFO 开头?
【发布时间】:2017-02-03 15:40:47
【问题描述】:

据我了解系统控制变量,kernel.printk 中的第一个值是内核消息必须小于才能写入控制台的数字。所以,如果是4,那么由此产生的消息将只有dmesg可见:

printk(KERN_INFO "This is a kernel message.");

消息在控制台上出现的唯一情况是它前面有KERN_ERRKERN_CRITKERN_INFOKERN_EMERG。即使内核模块出现问题,我希望上面的消息不会出现在我的屏幕上。

我正在尝试的一件事是系统调用拦截。有些工作完美无缺,有些则没有。但是在某些情况下,来自我标记为KERN_INFO 的不成功内核模块的消息阻塞了我的控制台,没有给我足够的时间来卸载它们。这些代码行的某处发生了错误:

…
#define INODE_IS_DEVICE(inode) (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode))
#define INODE_IS_RAW(inode) (imajor(inode) == RAW_MAJOR)
#define INODE_IS_RAW_DEVICE(inode) (INODE_IS_DEVICE(inode) || INODE_IS_RAW(inode))
#define TEST_OPEN_FLAGS(flags) ((flags & O_WRONLY) || (flags & O_RDWR))
…
struct inode *current_inode;
…
struct inode* get_inode_from_pathname(const char pathname) {
    struct path path;
    kern_path(pathname, LOOKUP_FOLLOW, &path);
    return path.dentry->d_inode;
}

asmlinkage int (*real_open)(const char* __user, int, int);

asmlinkage int custom_open(const char* __user file_name, int flags, int mode) {
    current_inode = get_inode_from_pathname(file_name);
    printk(KERN_INFO "intercepted: open(\"%s\", %X, %X)\n", file_name, flags, mode);
    if (INODE_IS_RAW_DEVICE(inode) && TEST_OPEN_FLAGS(flags)) {
        printk(KERN_INFO "Intercepted call to write to block device %s.\n", file_name);
    }
    return real_open(file_name, flags, mode);
}
…
void hack(void) {
    make_rw((unsigned_long)sys_call_table);
    real_open = (void*)*(sys_call_table + __NR_open);
    *(sys_call_table + __NR_open) = (unsigned_long)custom_open;
    make_ro((unsigned_long)sys_call_table);
}

void restore(void) {
    make_rw((unsigned_long)sys_call_table);
    *(sys_call_table + __NR_open) = (unsigned_long)real_open;
    make_ro((unsigned_long)sys_call_table);
}

make_rwmake_ro 的代码与 here 的代码相同。编译这段代码没有给我任何错误,但加载模块会导致消息被定向到控制台以及某种崩溃或错误。请注意,当custom_open 中的代码块被替换为

    printk(KERN_INFO "intercepted: open(\"%s\", %X, %X)\n", file_name, flags, mode);
    if (file_name == "/dev/sda" && TEST_OPEN_FLAGS(flags)) {
        printk("Intercepted call to write to block device.");
        return -EPERM;
    }
    return real_open(file_name, flags, mode);

一切都按照我想要的方式进行。将custom_open 的控制流语句替换为print(KERN_INFO "i_mode of %s: %hu\n", file_name, current_inode->i_mode); 会产生完全相同的问题。

我不确定是什么导致了这里的错误。有什么见解吗?

【问题讨论】:

  • cat /proc/sys/kernel/printk 说什么?

标签: linux linux-kernel kernel-module


【解决方案1】:

内核变量 DEFAULT_MESSAGE_LOGLEVEL 决定了内核的默认日志级别。要知道它的当前值是多少,请检查内核配置文件中 CONFIG_DEFAULT_MESSAGE_LOGLEVEL 的值。

这将为您提供有关 KERN_INFO 为何到达终端的线索。

【讨论】:

    【解决方案2】:

    注意,当custom_open 中的代码块被替换时 与

        printk(KERN_INFO "intercepted: open(\"%s\", %X, %X)\n", file_name, flags, mode);
        if (file_name == "/dev/sda" && TEST_OPEN_FLAGS(flags)) {
            printk("Intercepted call to write to block device.");
            return -EPERM;
        }
        return real_open(file_name, flags, mode);
    

    一切都按照我想要的方式进行。

    你错了。上面的代码没有输出并不意味着printk 没有输出到控制台; printk 很可能永远不会执行,因为函数参数 file_name 很可能不指向字符串文字 "/dev/sda" 的内存位置 - 请记住,要比较字符串,strcmp 是用过。

    【讨论】:

    • dmesg 的输出另有说明。它显示在内核日志缓冲区中,在这种情况下它不会打印到控制台/终端。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-22
    • 2019-11-21
    • 2011-06-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多