> Date: Sat, 14 Sep 2024 16:47:01 +0530 > From: Shiv <[email protected]> > > As part of my GSoC project, me and my mentor have > decided to extend support for renameat2 in the compat_linux. > We have decided to enable support for 2 newer flags, namely > RENAME_NOREPLACE and RENAME_EXCHANGE.
For context, here is the Linux documentation: https://man7.org/linux/man-pages/man2/rename.2.html renameat2() renameat2() has an additional flags argument. A renameat2() call with a zero flags argument is equivalent to renameat(). The flags argument is a bit mask consisting of zero or more of the following flags: RENAME_EXCHANGE Atomically exchange oldpath and newpath. Both pathnames must exist but may be of different types (e.g., one could be a non-empty directory and the other a symbolic link). RENAME_NOREPLACE Don't overwrite newpath of the rename. Return an error if newpath already exists. How widely used are these operations in the real world? Do important applications rely on them or were they invented for theoretical needs of test suites? > There are > 2 particular questions, on which we would like to gather communities > insights: > > 1. To prevent TOCTOU attack and provide atomicity, most of the > renameat code has been reimplemented in the compat layer. Is > this an acceptable approach or are there some better alternatives? > > 2. RENAME_EXCHANGE requires atomic swap of filenames and the > filetypes need not be the same. Can any of the existing VFS operations > be used to do so? And if this should be done in VFS layer or any specific > support is expected from the file system to implement this? I don't think either of these can be implemented correctly without substantial changes to the vfs interface and all file systems. In particular, the entire locking dance in do_sys_renameat is an essentially useless artefact of the hopelessly broken VOP_RENAME protocol which we haven't finished eliminating yet. Even if you're careful to take locks in exactly the same way as do_sys_renameat, the file systems that use genfs_rename -- i.e., the ones that have a chance of working reliably -- will just drop all the locks you'd taken and start over from scratch. So you won't prevent TOCTOU or achieve atomicity. Once all file systems have been adapted to use genfs_rename, we can get rid of the existing VOP_RENAME and replace it by something more sensible, and then delete all that code in do_sys_renameat. But progress toward converting all file systems to genfs_rename has stalled. (Remaining file systems: coda (if it works), nilfs (which I thought was read-only?), puffs, sysvbfs, v7fs, chfs, zfs, and the pseudo-file-systems union/null/umap/layer/...) If we wanted to make further changes to the rename protocol without waiting to finish converting all file systems to genfs_rename, we could: 1. change VOP_RENAME to VOP_RENAME_LEGACY, 2. add VOP_RENAME_MODERN or whatever with the signature of genfs_sane_rename (more or less), 3. create genfs_legacy_rename and move the current logic of do_sys_renameat into that (this implements VOP_RENAME_MODERN in terms of VOP_RENAME_LEGACY), 4. change do_sys_renameat to use VOP_RENAME_MODERN, and 5. do a switcheroo in every file system (implement VOP_RENAME_MODERN using genfs_sane_rename where it's already done, or using genfs_legacy_rename where it's not). And then we could pass flags through the new VOP_RENAME_MODERN, with some care to make sure file systems don't claim success for flags they don't understand. We already have one weird flag in genfs_rename -- posixly_correct -- so it's not that much of a stretch to pass others through.
