【问题标题】:relying on PATH_MAX can cause overflow依赖 PATH_MAX 会导致溢出
【发布时间】:2019-07-07 10:03:02
【问题描述】:

如您所知,PATH_MAX 是用于指示环境变量(在本例中为 PATH 变量)的最大大小的值,但在大多数情况下并非如此,请查看用于将环境变量复制到大小为PATH_MAX的数组中

  char env[PATH_MAX]; 
  strcpy(path, getenv("PATH"));

如果你看到它很容易溢出,有人会说使用strncpy 这样你就可以避免溢出,但是如果你使用它并且PATH 很大,那么MAX_PATH 我们将无法获得PATH env 变量已完成,这让我思考,如何在不溢出或不丢失数据的假设下获得 PATH env 变量

【问题讨论】:

    标签: c linux security x86 buffer-overflow


    【解决方案1】:

    一般如果你需要复制一个未知长度的字符串,使用strncpy复制到一个有大小限制的固定大小的缓冲区(但要注意如果字符串太长,则不终止字符串的不便行为。

    或者使用 strdup 来 malloc 一个副本。


    如您所知,PATH_MAX 是用于指示环境变量(在本例中为 PATH 变量)的最大大小的值

    不,不是;与$PATH或环境无关!!

    单个文件系统路径名的最大长度。例如/foo/bar/verylongdirectoryname/x/y.txt 的长度保证最多为 PATH_MAX。否则您可能无法使用绝对路径读取它,而必须将 chdir 改为该树并使用相对路径。

    PATH 环境只是一个扁平字符串,就像任何其他 env var 一样;内核不会将它们剪辑到固定长度。或者当然不限于PATH_MAX

    如何在不发生溢出或数据丢失的假设下获得 PATH 环境变量

    呃,你已经有了getenv("PATH")。这将返回一个指向进程内存空间中现有字符串的指针。它有效地在静态存储中;你不需要复制它,以后对getenv 的调用不会破坏指针。 (在 Linux 上,环境变量在进程启动时位于 argv 上方的堆栈中。在任何移动堆栈指针之前运行的 CRT 启动代码将指向它们的指针存储在全局 envp 中,getenv 稍后可以找到它。)

    如果您想复制环境变量的缓冲区以便延长它,或者在不更改原始内容的情况下修改它,最简单的选择是strdup(3) from <string.h> 来分配一个副本。 (POSIX 2008,以及之前的 BSD、GNU C 和之前的各种其他系统)。或strndup 设置要复制的字节数限制。

    GNU C 甚至有一个基于 alloca 而不是 malloc 的版本,以防您想要更便宜的临时自动存储。


    PATH_MAX

    PATH_MAXgetwd(3) 等 POSIX 函数相关,您可以在其中提供缓冲区但没有长度限制。 (但实际上您应该改用char *getcwd(char *buf, size_t size);请参阅与getwd 相同的链接。手册页还说:

    请注意,在某些系统上,PATH_MAX 可能不是编译时常量;此外,它的价值可能取决于 在文件系统上,请参阅 pathconf(3)。


    Linux readdir(3) 手册页没有这么说,但是 struct dirent 成员 char d_name[256]; /* Null-terminated filename */ 的大小是这样的,因为 PATH_MAX = 255。(或者更准确地说,PATH_MAX 是 255,因为 readdir 大小限制。)


    此外,像 chdir(2)open(2) 这样的系统调用允许在超过 PATH_MAX (ENAMETOOLONG) 的路径上失败:

    ENAMETOOLONG
    路径名或路径名的组成部分太长。

    readlink(2) 采用缓冲区大小,因此不需要限制链接目标的长度;它只提到 ENAMETOOLONG 作为您提供的路径中的一个可能错误,而不是链接名称。


    即使在现代 Linux 上,单个文件名的 255 个字节也是一个硬限制。但是 IIRC 它确实选择允许更长的路径名(具有多个目录组件)。 POSIX 规范对于长路径上的open()要求错误,因此操作系统可以提供相当小的 PATH_MAX,但在可能的情况下仍然适用于更长的路径。

    【讨论】:

    • @alk:getcwd 不使用缓冲区大小参数的版本实际上称为getwd。那不是错字。 (在寻找具有路径名输出的函数/系统调用之前,我也不知道它存在)
    • 胡!对不起,我太草率了,只检查了您放置的链接的拼写。 :}
    【解决方案2】:

    避免假设 $PATH 已定义或长度有限是您问题的解决方案,请使用如下所示的通用代码。

    char *path = NULL; 
      const char *temp = getenv("PATH");
      if (temp != NULL) {
        path = (char*) malloc(strlen(temp) + 1);
        if (path == NULL) {
          /* Handle error condition */
        } else {
          strcpy(path, temp);
        }
        /* Use path */
      }
    

    【讨论】:

    • POSIX 2008 添加了strdup(3),它为您分配了一个字符串的副本(并且它在 Linux 上的可用时间比这更长)。如果您使用其他 POSIX 函数,则无需自己编写。
    猜你喜欢
    • 1970-01-01
    • 2014-07-26
    • 1970-01-01
    • 2012-11-13
    • 1970-01-01
    • 1970-01-01
    • 2013-02-17
    • 2018-06-21
    • 2016-02-09
    相关资源
    最近更新 更多