You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何openat()在3.10.0-693内核中将/dev/stdout识别为目录?

为何Linux 3.10内核中openat会将/dev/stdout识别为目录?

演示程序

#define _GNU_SOURCE
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

int main(void) {

    int fd = openat(AT_FDCWD, "/dev/stdout", O_RDONLY|O_PATH|O_DIRECTORY);
    if (fd == -1) {
        perror("openat");
        return 1;
    }

    return 0;
}

不同内核下的ltrace结果

Linux 3.10.0-693内核

__libc_start_main([ "./a.out" ] <unfinished ...>
openat(0xffffff9c, 0x400670, 0x210000, 0x4005e0)      = 3
+++ exited (status 0) +++

Linux 4.14.15-1内核

__libc_start_main(0x40059d, 1, 0x7ffcaccd9e98, 0x4005e0 <unfinished ...>
openat(0xffffff9c, 0x400670, 0x210000, 0x4005e0)      = -1
perror("openat"openat: Not a directory
)                                                     = <void>
+++ exited (status 1) +++

补充:3.10.0-693内核下的strace结果

mprotect(0x7f568f480000, 4096, PROT_READ) = 0
munmap(0x7f568f473000, 47716)           = 0
openat(AT_FDCWD, "/dev/stdout", O_RDONLY|O_PATH|O_DIRECTORY) = 3
exit_group(0)                           = ?
+++ exited with 0 +++

问题核心

/dev/stdout是指向字符设备的符号链接,绝非目录,但3.10.0-693内核中,带O_PATH|O_DIRECTORY标志的openat()调用居然能成功打开它;而4.14内核中该调用会正确返回Not a directory错误,想了解该边缘情况的具体原因。

原因解析

这是Linux内核处理O_PATH标志时的旧bug,存在于3.10到4.13左右的版本中:

  • 3.10内核中,当使用O_PATH打开文件时,内核跳过了部分常规文件类型检查逻辑。针对/dev/stdout这类符号链接,O_DIRECTORY的类型验证被错误地应用在符号链接本身而非其指向的目标文件上——内核没有跟进符号链接去检查最终目标的类型,只要路径解析完成就返回成功,完全忽略了目标是字符设备的事实。
  • 后续4.14及以上内核修复了该问题,在O_PATH模式下也会强制验证最终目标文件的类型是否符合O_DIRECTORY要求,因此打开/dev/stdout会正确返回ENOTDIR错误。

内容的提问来源于stack exchange,提问作者ms2008

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 04:01:18