依赖 PATH_MAX 可能会导致溢出

问题描述 投票:0回答:2

如您所知,

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
2个回答
7
投票

一般来说,如果你需要复制一个未知长度的字符串,请参阅string_copying(7)

手册页
strncpy
通常是错误的选择,而不是以0结尾的长字符串,并且浪费时间归零到短字符串大小限制的末尾。除了 
strlen
 + 手动检查 + 
memcpy
 之外,便携式 ISO C 没有任何好的选择,即使这样也不是很好,因为它会读取输入两次。 
string_copying
 手册页显示了 POSIX.2008 
stpecpy
中非标准化
memccpy
的实现,其中停止字符为
0
,添加手动终止符以防输入不合适.

或使用

strdup

 来分配副本。


如您所知,

PATH_MAX

是用于指示环境变量的最大大小的值(在本例中为
PATH
变量)

不,不是;与

$PATH
或环境无关!!

它是单个文件系统路径名的最大长度。例如/foo/bar/verylongdirectoryname/x/y.txt

 保证长度最多为 
PATH_MAX
。否则您可能无法使用绝对路径读取它,而必须改为 chdir 到该树中并使用相对路径。

PATH

环境只是一个像任何其他环境变量一样的扁平字符串;内核不会将它们剪裁为固定长度。或者当然不限于 
PATH_MAX

我如何在假设不应该溢出或数据丢失的情况下获取 PATH 环境变量

呃,你已经有了getenv("PATH")

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

如果您想

复制环境变量的缓冲区,以便可以延长它,或者在不更改原始版本的情况下修改它,最简单的选项是strdup(3)

<string.h>
到malloc副本。
(POSIX) 2008 年,以及在此之前的 BSD、GNU C 以及之前的各种其他系统)。或者
strndup
 设置要复制的字节数限制。

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


PATH_MAX

PATH_MAX

 与 POSIX 函数相关,例如 
getwd(3)
,您提供缓冲区但没有长度限制。 (但实际上你应该使用
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。(或者更准确地说,由于 readdir 大小限制,PATH_MAX 是 255。 )


此外,像

chdir(2)

open(2)
 这样的系统调用也可以在长于 
PATH_MAX
 (
ENAMETOOLONG
) 的路径上失败:

ENAMETOOLONG


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

readlink(2)

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


即使在现代 Linux 上,单个文件名 255 字节也是硬性限制。但 IIRC 它确实选择允许更长的路径名(具有多个目录组件)。 POSIX 规范不会在长路径上出现

require open()

 错误,因此操作系统可以提供相当小的 PATH_MAX,但在可能的情况下仍然适用于更长的路径。


3
投票
避免假设 $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 */ }
    
© www.soinside.com 2019 - 2024. All rights reserved.