Re: [RESEND PATCH] vfs: add RWF_NOAPPEND flag for pwritev2
From: Rich Felker <dalias@libc.org>
Date: 2020-08-30 16:37:07
Also in:
linux-fsdevel, lkml
On Sun, Aug 30, 2020 at 05:05:45PM +0200, Jann Horn wrote:
On Sat, Aug 29, 2020 at 4:00 AM Rich Felker [off-list ref] wrote:quoted
The pwrite function, originally defined by POSIX (thus the "p"), is defined to ignore O_APPEND and write at the offset passed as its argument. However, historically Linux honored O_APPEND if set and ignored the offset. This cannot be changed due to stability policy, but is documented in the man page as a bug. Now that there's a pwritev2 syscall providing a superset of the pwrite functionality that has a flags argument, the conforming behavior can be offered to userspace via a new flag.[...]quoted
diff --git a/include/linux/fs.h b/include/linux/fs.h[...]quoted
@@ -3411,6 +3413,8 @@ static inline int kiocb_set_rw_flags(struct kiocb *ki, rwf_t flags) ki->ki_flags |= (IOCB_DSYNC | IOCB_SYNC); if (flags & RWF_APPEND) ki->ki_flags |= IOCB_APPEND; + if (flags & RWF_NOAPPEND) + ki->ki_flags &= ~IOCB_APPEND; return 0; }Linux enforces the S_APPEND flag (set by "chattr +a") only at open() time, not at write() time: # touch testfile # exec 100>testfile # echo foo > testfile # cat testfile foo # chattr +a testfile # echo bar > testfile bash: testfile: Operation not permitted # echo bar >&100 # cat testfile bar # At open() time, the kernel enforces that you can't use O_WRONLY/O_RDWR without also setting O_APPEND if the file is marked as append-only: static int may_open(const struct path *path, int acc_mode, int flag) { [...] /* * An append-only file must be opened in append mode for writing. */ if (IS_APPEND(inode)) { if ((flag & O_ACCMODE) != O_RDONLY && !(flag & O_APPEND)) return -EPERM; if (flag & O_TRUNC) return -EPERM; } [...] } It seems to me like your patch will permit bypassing S_APPEND by opening an append-only file with O_WRONLY|O_APPEND, then calling pwritev2() with RWF_NOAPPEND? I think you'll have to add an extra check for IS_APPEND() somewhere. One could also argue that if an O_APPEND file descriptor is handed across privilege boundaries, a programmer might reasonably expect that the recipient will not be able to use the file descriptor for non-append writes; if that is not actually true, that should probably be noted in the open.2 manpage, at the end of the description of O_APPEND.
fcntl F_SETFL can remove O_APPEND, so it is not a security boundary. I'm not sure how this interacts with S_APPEND; presumably fcntl rechecks it. So just checking IS_APPEND in the code paths used by pwritev2 (and erroring out rather than silently writing output at the wrong place) should suffice to preserve all existing security invariants. Rich