shm_open和ftruncate竞争条件可能吗?

eth*_*ice 5 c c++ linux mmap shared-memory

shm_open手册页:

新的共享内存对象最初的长度为零.可以使用ftruncate(2)设置对象的大小.[...] shm_open()函数本身不会创建指定大小的共享对象,因为这样做会复制现有函数,该函数设置文件描述符引用的对象的大小.

这不会使应用程序暴露于竞争条件吗?考虑以下伪代码:

int fd = shm_open("/foo", CREATE);
if ( fd is valid ) {
  // created shm object, so set its size
  ftruncate(fd, 128);
} else {
  fd = shm_open("/foo", GET_EXISTING);
}
void* mem = mmap(fd, 128);
Run Code Online (Sandbox Code Playgroud)

由于shm_openftruncate调用(一起)不是原子的,你可能有一个竞争条件,一个进程调用shm_open(CREATEcase),但是在调用之前ftruncate,另一个进程调用shm_open(GET_EXISTINGcase)并尝试mmap0大小的对象,甚至可能写入它.

我可以想到两种避免这种竞争条件的方法:

  1. 使用IPC互斥量/信号量使整个事物同步,或者......

  2. 如果它是安全的(按POSIX),请ftruncate同时调用CREATEGET_EXISTING案例.

哪种方法可以避免这种竞争条件?

R..*_*R.. 6

您的方法(ftruncate从两者调用)应该可以工作,但是您需要一种方法来同步使用共享内存段的内容.由于内存最初是空的(零填充),因此不包含有效的同步对象,除非您要使用atomics自行滚动,否则无论如何都需要辅助形式的同步来控制对共享内存的访问.

我认为通常情况下,您不希望多个流程竞争创建或打开具有固定名称的共享内存段,您希望拥有一个负责创建具有随机名称的段的所有者进程,O_EXCL以避免随机或恶意冲突,然后传递名称,一旦您成功打开它,调整它的大小,并在其中创建同步对象,到其他需要访问它的进程.

  • 顺便说一句,从安全角度来看,零填充基本上需要锁定.如果有办法观察"扩展但未归零"的文件,则该过程将能够观察它不一定具有的权限(例如,释放内核内存或属于其他用户的已删除文件). (2认同)