On 2021-04-23, Christian Brauner <brauner@xxxxxxxxxx> wrote: > The new openat2() syscall verifies that no unknown O-flag values are > set and returns an error to userspace if they are while the older open > syscalls like open() and openat2() simply ignore unknown flag values: > > #define O_FLAG_CURRENTLY_INVALID (1 << 31) > struct open_how how = { > .flags = O_RDONLY | O_FLAG_CURRENTLY_INVALID, > .resolve = 0, > }; > > /* fails */ > fd = openat2(-EBADF, "/dev/null", &how, sizeof(how)); > > /* succeeds */ > fd = openat(-EBADF, "/dev/null", O_RDONLY | O_FLAG_CURRENTLY_INVALID); > > However, openat2() silently truncates the upper 32 bits meaning: > > #define O_FLAG_CURRENTLY_INVALID_LOWER32 (1 << 31) > #define O_FLAG_CURRENTLY_INVALID_UPPER32 (1 << 40) > > struct open_how how_lowe32 = { > .flags = O_RDONLY | O_FLAG_CURRENTLY_INVALID_LOWE32, > .resolve = 0, > }; > > struct open_how how_upper32 = { > .flags = O_RDONLY | O_FLAG_CURRENTLY_INVALID_LOWE32, > .resolve = 0, > }; > > /* fails */ > fd = openat2(-EBADF, "/dev/null", &how_lower32, sizeof(how_lower32)); > > /* succeeds */ > fd = openat2(-EBADF, "/dev/null", &how_upper32, sizeof(how_upper32)); > > That seems like a bug. Fix it by preventing the truncation in > build_open_flags(). > > There's a snafu here though stripping FMODE_* directly from flags would > cause the upper 32 bits to be truncated as well due to integer promotion > rules since FMODE_* is unsigned int, O_* are signed ints (yuck). > > This change shouldn't regress old open syscalls since they silently > truncate any unknown values. Yeah, oops on my part (I was always worried I'd missed something with making everything -EINVAL). Reviewed-by: Aleksa Sarai <cyphar@xxxxxxxxxx> -- Aleksa Sarai Senior Software Engineer (Containers) SUSE Linux GmbH <https://www.cyphar.com/>
Attachment:
signature.asc
Description: PGP signature