openat和TOCTTOU问题

这篇博客讲述了openat系统调用和相关的TOCTTOU问题

openat v.s open

通常打开一个文件使用的系统调用是:

#include <fcntl.h>

int open(const char *path, int oflag);

open系统调用和大多数语言提供的打开文件的api一致,包含两个参数:文件路径和打开
模式(只读、只写或者读写)

然而除了open之外,类Unix系统还提供了另一个打开文件的系统调用openat

int openat(int dirfd, const char *path, int oflag);

openatopen功能相同,需要的参数本质上一样:需要打开的文件和打开模式。不同之处在于open
数直接通过文件路径指定文件,而openat通过一个目录文件句柄dirfd和相对路径指定文件
有三种可能:

  • path参数是绝对路径,fd参数被忽略,这时和open函数一样了
  • path参数是相对路径,fd参数是相对路径的起始位置的文件描述符
  • path参数是相对路径,fdAT_FDCWD表示相对路径的起始位置是当前工作目录

openat的用途和TOCTTOU

  1. 支持使用相对路径在其他目录打开文件,这样能够方便实现多线程使用各自不同的工作目录
  2. 避免部分TOCTTOU问题
    所谓TOCTTOU是一个简称,全称是:Time of Check To Time of Use
    翻译成中文是:检查的时刻到使用的时刻
    举个例子
char *filename = "/tmp/dir1/dir2/a.txt";
struct stat;
/**
 * 先检查文件是否存在(Time of Check)
 */
if (stat(filename, &stat) == -1){
    perror();
} else {
    /**
     * 打开文件(Time of Use)
     */
    open(filename, O_WRONLY);
}

先检查文件,然后打开文件,写入或者读取文件,是典型的TOCTTOU问题,因为检查和写入
文件不是原子操作,检查和写入之间可能文件的状态可能已经发生了变化,比如dir1
一个链接目录,在检查文件后,其他程序修改了dir1的指向,在打开文件时,文件已经
不是原本我们检查的那个文件了,也不是我们一开始意图打开的文件。

使用openat可以一定程度上避免这个问题,因为dirfd是一个文件描述符,直接指向了
真实的文件,在检查文件的操作后,即使dir1指向其他目录或者dir1改名,dirfd
向的目录也不会改变了。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。