在没有此标志的系统上模拟 O_NOFOLLOW 的好方法是什么?

发布于 2024-09-03 02:53:01 字数 748 浏览 6 评论 0原文

我希望能够安全地使用 O_CREAT | 模拟 open O_WRONLY | O_TRUNC | O_NOFOLLOWO_CREAT | O_WRONLY | O_APPEND | O_NOFOLLOW 在不支持 O_NOFOLLOW 的系统上。我可以在某种程度上实现我的要求:

struct stat lst;
if (lstat(filename, &lst) != -1 && S_ISLNK(lst.st_mode)) {
    errno = ELOOP;
    return -1;
}

mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
int fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW, mode);

但随后我引入了竞争条件,可能还引入了安全问题。

我考虑过创建一个只有用户能够写入的虚拟文件,有点像 touching filename,进行 lstat 检查,然后在我完成写入后使用 chmod (以更正文件模式位),但我可能会忽略一些主要内容(例如,如果 filename 处的文件存在,则不是常规文件,或者已经是符号链接)。

你怎么认为?

I would like to safely be able to simulate open with O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW and O_CREAT | O_WRONLY | O_APPEND | O_NOFOLLOW on systems that do not support O_NOFOLLOW. I can somewhat achieve what I am asking for with:

struct stat lst;
if (lstat(filename, &lst) != -1 && S_ISLNK(lst.st_mode)) {
    errno = ELOOP;
    return -1;
}

mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
int fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW, mode);

but then I introduce a race condition and possibly a security problem.

I thought about maybe creating a dummy file with only the user being able to write, kind of like touching filename, doing the lstat check, and then using chmod after I finish writing (to correct the file mode bits), but I could be overlooking something major (e.g. if the file at filename exists, is not a regular file, or is already a symbolic link).

What do you think?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

少女的英雄梦 2024-09-10 02:53:01

你的提案仍然存在竞争条件:

  • Mallory 创建他希望你关注的链接;
  • 您使用 O_CREAT open() 链接;
  • Mallory 将链接替换为常规文件;
  • 您执行 lstat() 测试,该测试通过(不是链接);
  • Mallory 再次用链接替换常规文件。

对于非 O_TRUNC 情况,您可以通过在打开的文件描述符上调用 fstat() 以及在路径上调用 lstat() 来修复此问题,并确保 .st_dev.st_ino 成员相同。

但是,如果您使用 O_TRUNC,则此方法不起作用 - 当您发现欺骗时,为时已晚 - Mallory 已经诱导您截断您的一个重要文件。

我相信在没有 O_NOFOLLOW 支持的情况下消除漏洞的传统方法是:

  • 使用模式 700 创建一个临时目录。如果 mkdir() 由于现有目录而失败,则出错(或重试);
  • 在临时目录中创建新文件;
  • 使用rename()自动将临时文件移动到目标名称;
  • 删除临时目录。

Your proposal still has a race condition:

  • Mallory creates the link he wants you to follow;
  • You open() the link with O_CREAT;
  • Mallory replaces the link with a regular file;
  • You do your lstat() test, which passes (not a link);
  • Mallory replaces the regular file with the link again.

You can fix this for the non-O_TRUNC case by calling fstat() on your open file descriptor as well as lstat() on the path, and ensuring that the .st_dev and .st_ino members are the same.

However, this doesn't work if you're using O_TRUNC - by the time you've discovered the deception, it's too late - Mallory has already induced you to truncate one of your important files.

I believe the traditional way to eliminate the hole without O_NOFOLLOW support is:

  • Create a temporary directory with mode 700. Error (or retry) if mkdir() fails due to existing directory;
  • Create your new file within the temporary directory;
  • Use rename() to atomically move the temporary file to the target name;
  • Remove the temporary directory.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文