* [PATCH v3 0/4] O_REGULAR flag support for open
@ 2026-01-27 17:58 Dorjoy Chowdhury
2026-01-27 17:58 ` [PATCH v3 1/4] open: new O_REGULAR flag support Dorjoy Chowdhury
` (3 more replies)
0 siblings, 4 replies; 26+ messages in thread
From: Dorjoy Chowdhury @ 2026-01-27 17:58 UTC (permalink / raw)
To: linux-fsdevel
Cc: linux-kernel, viro, brauner, jack, jlayton, chuck.lever,
alex.aring, arnd, adilger
Changes in v3:
- included motivation about O_REGULAR flag in commit message e.g., programs not wanting to be tricked into opening device nodes
- fixed commit message wrongly referencing ENOTREGULAR instead of ENOTREG
- fixed the O_REGULAR flag in arch/parisc/include/uapi/asm/fcntl.h from 060000000 to 0100000000
- added 2 commits converting arch/{mips,sparc}/include/uapi/asm/fcntl.h O_* macros from hex to octal
- v2 is at: https://lore.kernel.org/linux-fsdevel/20260126154156.55723-1-dorjoychy111@gmail.com/T/
Changes in v2:
- rename ENOTREGULAR to ENOTREG
- define ENOTREG in uapi/asm-generic/errno.h (instead of errno-base.h) and in arch/*/include/uapi/asm/errno.h files
- override O_REGULAR in arch/{alpha,sparc,parisc}/include/uapi/asm/fcntl.h due to clash with include/uapi/asm-generic/fcntl.h
- I have kept the kselftest but now that O_REGULAR and ENOTREG can have different value on different architectures I am not sure if it's right
- v1 is at: https://lore.kernel.org/linux-fsdevel/20260125141518.59493-1-dorjoychy111@gmail.com/T/
Hi,
I came upon this "Ability to only open regular files" uapi feature suggestion
from https://uapi-group.org/kernel-features/#ability-to-only-open-regular-files
and thought it would be something I could do as a first patch and get to
know the kernel code a bit better.
I am not quite sure if the semantics that I baked into the code for this
O_REGULAR flag's behavior when combined with other flags like O_CREAT look
good and if there are other places that need the checks. I can fixup my
patch according to suggestions for improvement. I did some happy path testing
and the O_REGULAR flag seems to work as intended.
Thanks.
Regards,
Dorjoy
Dorjoy Chowdhury (4):
open: new O_REGULAR flag support
kselftest/openat2: test for O_REGULAR flag
sparc/fcntl.h: convert O_* flag macros from hex to octal
mips/fcntl.h: convert O_* flag macros from hex to octal
arch/alpha/include/uapi/asm/errno.h | 2 +
arch/alpha/include/uapi/asm/fcntl.h | 1 +
arch/mips/include/uapi/asm/errno.h | 2 +
arch/mips/include/uapi/asm/fcntl.h | 22 +++++------
arch/parisc/include/uapi/asm/errno.h | 2 +
arch/parisc/include/uapi/asm/fcntl.h | 1 +
arch/sparc/include/uapi/asm/errno.h | 2 +
arch/sparc/include/uapi/asm/fcntl.h | 35 +++++++++---------
fs/fcntl.c | 2 +-
fs/namei.c | 6 +++
fs/open.c | 4 +-
include/linux/fcntl.h | 2 +-
include/uapi/asm-generic/errno.h | 2 +
include/uapi/asm-generic/fcntl.h | 4 ++
tools/arch/alpha/include/uapi/asm/errno.h | 2 +
tools/arch/mips/include/uapi/asm/errno.h | 2 +
tools/arch/parisc/include/uapi/asm/errno.h | 2 +
tools/arch/sparc/include/uapi/asm/errno.h | 2 +
tools/include/uapi/asm-generic/errno.h | 2 +
.../testing/selftests/openat2/openat2_test.c | 37 ++++++++++++++++++-
20 files changed, 102 insertions(+), 32 deletions(-)
--
2.52.0
^ permalink raw reply [flat|nested] 26+ messages in thread* [PATCH v3 1/4] open: new O_REGULAR flag support 2026-01-27 17:58 [PATCH v3 0/4] O_REGULAR flag support for open Dorjoy Chowdhury @ 2026-01-27 17:58 ` Dorjoy Chowdhury 2026-01-27 23:23 ` Aleksa Sarai ` (2 more replies) 2026-01-27 17:58 ` [PATCH v3 2/4] kselftest/openat2: test for O_REGULAR flag Dorjoy Chowdhury ` (2 subsequent siblings) 3 siblings, 3 replies; 26+ messages in thread From: Dorjoy Chowdhury @ 2026-01-27 17:58 UTC (permalink / raw) To: linux-fsdevel Cc: linux-kernel, viro, brauner, jack, jlayton, chuck.lever, alex.aring, arnd, adilger This flag indicates the path should be opened if it's a regular file. This is useful to write secure programs that want to avoid being tricked into opening device nodes with special semantics while thinking they operate on regular files. A corresponding error code ENOTREG has been introduced. For example, if open is called on path /dev/null with O_REGULAR in the flag param, it will return -ENOTREG. When used in combination with O_CREAT, either the regular file is created, or if the path already exists, it is opened if it's a regular file. Otherwise, -ENOTREG is returned. -EINVAL is returned when O_REGULAR is combined with O_DIRECTORY (not part of O_TMPFILE) because it doesn't make sense to open a path that is both a directory and a regular file. Signed-off-by: Dorjoy Chowdhury <dorjoychy111@gmail.com> --- arch/alpha/include/uapi/asm/errno.h | 2 ++ arch/alpha/include/uapi/asm/fcntl.h | 1 + arch/mips/include/uapi/asm/errno.h | 2 ++ arch/parisc/include/uapi/asm/errno.h | 2 ++ arch/parisc/include/uapi/asm/fcntl.h | 1 + arch/sparc/include/uapi/asm/errno.h | 2 ++ arch/sparc/include/uapi/asm/fcntl.h | 1 + fs/fcntl.c | 2 +- fs/namei.c | 6 ++++++ fs/open.c | 4 +++- include/linux/fcntl.h | 2 +- include/uapi/asm-generic/errno.h | 2 ++ include/uapi/asm-generic/fcntl.h | 4 ++++ tools/arch/alpha/include/uapi/asm/errno.h | 2 ++ tools/arch/mips/include/uapi/asm/errno.h | 2 ++ tools/arch/parisc/include/uapi/asm/errno.h | 2 ++ tools/arch/sparc/include/uapi/asm/errno.h | 2 ++ tools/include/uapi/asm-generic/errno.h | 2 ++ 18 files changed, 38 insertions(+), 3 deletions(-) diff --git a/arch/alpha/include/uapi/asm/errno.h b/arch/alpha/include/uapi/asm/errno.h index 6791f6508632..8bbcaa9024f9 100644 --- a/arch/alpha/include/uapi/asm/errno.h +++ b/arch/alpha/include/uapi/asm/errno.h @@ -127,4 +127,6 @@ #define EHWPOISON 139 /* Memory page has hardware error */ +#define ENOTREG 140 /* Not a regular file */ + #endif diff --git a/arch/alpha/include/uapi/asm/fcntl.h b/arch/alpha/include/uapi/asm/fcntl.h index 50bdc8e8a271..4da5a64c23bd 100644 --- a/arch/alpha/include/uapi/asm/fcntl.h +++ b/arch/alpha/include/uapi/asm/fcntl.h @@ -34,6 +34,7 @@ #define O_PATH 040000000 #define __O_TMPFILE 0100000000 +#define O_REGULAR 0200000000 #define F_GETLK 7 #define F_SETLK 8 diff --git a/arch/mips/include/uapi/asm/errno.h b/arch/mips/include/uapi/asm/errno.h index c01ed91b1ef4..293c78777254 100644 --- a/arch/mips/include/uapi/asm/errno.h +++ b/arch/mips/include/uapi/asm/errno.h @@ -126,6 +126,8 @@ #define EHWPOISON 168 /* Memory page has hardware error */ +#define ENOTREG 169 /* Not a regular file */ + #define EDQUOT 1133 /* Quota exceeded */ diff --git a/arch/parisc/include/uapi/asm/errno.h b/arch/parisc/include/uapi/asm/errno.h index 8cbc07c1903e..442917484f99 100644 --- a/arch/parisc/include/uapi/asm/errno.h +++ b/arch/parisc/include/uapi/asm/errno.h @@ -124,4 +124,6 @@ #define EHWPOISON 257 /* Memory page has hardware error */ +#define ENOTREG 258 /* Not a regular file */ + #endif diff --git a/arch/parisc/include/uapi/asm/fcntl.h b/arch/parisc/include/uapi/asm/fcntl.h index 03dee816cb13..0cc3320fe326 100644 --- a/arch/parisc/include/uapi/asm/fcntl.h +++ b/arch/parisc/include/uapi/asm/fcntl.h @@ -19,6 +19,7 @@ #define O_PATH 020000000 #define __O_TMPFILE 040000000 +#define O_REGULAR 0100000000 #define F_GETLK64 8 #define F_SETLK64 9 diff --git a/arch/sparc/include/uapi/asm/errno.h b/arch/sparc/include/uapi/asm/errno.h index 4a41e7835fd5..8dce0bfeab74 100644 --- a/arch/sparc/include/uapi/asm/errno.h +++ b/arch/sparc/include/uapi/asm/errno.h @@ -117,4 +117,6 @@ #define EHWPOISON 135 /* Memory page has hardware error */ +#define ENOTREG 136 /* Not a regular file */ + #endif diff --git a/arch/sparc/include/uapi/asm/fcntl.h b/arch/sparc/include/uapi/asm/fcntl.h index 67dae75e5274..a93d18d2c23e 100644 --- a/arch/sparc/include/uapi/asm/fcntl.h +++ b/arch/sparc/include/uapi/asm/fcntl.h @@ -37,6 +37,7 @@ #define O_PATH 0x1000000 #define __O_TMPFILE 0x2000000 +#define O_REGULAR 0x4000000 #define F_GETOWN 5 /* for sockets. */ #define F_SETOWN 6 /* for sockets. */ diff --git a/fs/fcntl.c b/fs/fcntl.c index f93dbca08435..62ab4ad2b6f5 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -1169,7 +1169,7 @@ static int __init fcntl_init(void) * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY * is defined as O_NONBLOCK on some platforms and not on others. */ - BUILD_BUG_ON(20 - 1 /* for O_RDONLY being 0 */ != + BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ != HWEIGHT32( (VALID_OPEN_FLAGS & ~(O_NONBLOCK | O_NDELAY)) | __FMODE_EXEC)); diff --git a/fs/namei.c b/fs/namei.c index b28ecb699f32..f5504ae4b03c 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -4616,6 +4616,10 @@ static int do_open(struct nameidata *nd, if (unlikely(error)) return error; } + + if ((open_flag & O_REGULAR) && !d_is_reg(nd->path.dentry)) + return -ENOTREG; + if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry)) return -ENOTDIR; @@ -4765,6 +4769,8 @@ static int do_o_path(struct nameidata *nd, unsigned flags, struct file *file) struct path path; int error = path_lookupat(nd, flags, &path); if (!error) { + if ((file->f_flags & O_REGULAR) && !d_is_reg(path.dentry)) + return -ENOTREG; audit_inode(nd->name, path.dentry, 0); error = vfs_open(&path, file); path_put(&path); diff --git a/fs/open.c b/fs/open.c index 74c4c1462b3e..82153e21907e 100644 --- a/fs/open.c +++ b/fs/open.c @@ -1173,7 +1173,7 @@ struct file *kernel_file_open(const struct path *path, int flags, EXPORT_SYMBOL_GPL(kernel_file_open); #define WILL_CREATE(flags) (flags & (O_CREAT | __O_TMPFILE)) -#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC) +#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC | O_REGULAR) inline struct open_how build_open_how(int flags, umode_t mode) { @@ -1250,6 +1250,8 @@ inline int build_open_flags(const struct open_how *how, struct open_flags *op) return -EINVAL; if (!(acc_mode & MAY_WRITE)) return -EINVAL; + } else if ((flags & O_DIRECTORY) && (flags & O_REGULAR)) { + return -EINVAL; } if (flags & O_PATH) { /* O_PATH only permits certain other flags to be set. */ diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h index a332e79b3207..4fd07b0e0a17 100644 --- a/include/linux/fcntl.h +++ b/include/linux/fcntl.h @@ -10,7 +10,7 @@ (O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | \ O_APPEND | O_NDELAY | O_NONBLOCK | __O_SYNC | O_DSYNC | \ FASYNC | O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | \ - O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE) + O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE | O_REGULAR) /* List of all valid flags for the how->resolve argument: */ #define VALID_RESOLVE_FLAGS \ diff --git a/include/uapi/asm-generic/errno.h b/include/uapi/asm-generic/errno.h index 92e7ae493ee3..2216ab9aa32e 100644 --- a/include/uapi/asm-generic/errno.h +++ b/include/uapi/asm-generic/errno.h @@ -122,4 +122,6 @@ #define EHWPOISON 133 /* Memory page has hardware error */ +#define ENOTREG 134 /* Not a regular file */ + #endif diff --git a/include/uapi/asm-generic/fcntl.h b/include/uapi/asm-generic/fcntl.h index 613475285643..3468b352a575 100644 --- a/include/uapi/asm-generic/fcntl.h +++ b/include/uapi/asm-generic/fcntl.h @@ -88,6 +88,10 @@ #define __O_TMPFILE 020000000 #endif +#ifndef O_REGULAR +#define O_REGULAR 040000000 +#endif + /* a horrid kludge trying to make sure that this will fail on old kernels */ #define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) diff --git a/tools/arch/alpha/include/uapi/asm/errno.h b/tools/arch/alpha/include/uapi/asm/errno.h index 6791f6508632..8bbcaa9024f9 100644 --- a/tools/arch/alpha/include/uapi/asm/errno.h +++ b/tools/arch/alpha/include/uapi/asm/errno.h @@ -127,4 +127,6 @@ #define EHWPOISON 139 /* Memory page has hardware error */ +#define ENOTREG 140 /* Not a regular file */ + #endif diff --git a/tools/arch/mips/include/uapi/asm/errno.h b/tools/arch/mips/include/uapi/asm/errno.h index c01ed91b1ef4..293c78777254 100644 --- a/tools/arch/mips/include/uapi/asm/errno.h +++ b/tools/arch/mips/include/uapi/asm/errno.h @@ -126,6 +126,8 @@ #define EHWPOISON 168 /* Memory page has hardware error */ +#define ENOTREG 169 /* Not a regular file */ + #define EDQUOT 1133 /* Quota exceeded */ diff --git a/tools/arch/parisc/include/uapi/asm/errno.h b/tools/arch/parisc/include/uapi/asm/errno.h index 8cbc07c1903e..442917484f99 100644 --- a/tools/arch/parisc/include/uapi/asm/errno.h +++ b/tools/arch/parisc/include/uapi/asm/errno.h @@ -124,4 +124,6 @@ #define EHWPOISON 257 /* Memory page has hardware error */ +#define ENOTREG 258 /* Not a regular file */ + #endif diff --git a/tools/arch/sparc/include/uapi/asm/errno.h b/tools/arch/sparc/include/uapi/asm/errno.h index 4a41e7835fd5..8dce0bfeab74 100644 --- a/tools/arch/sparc/include/uapi/asm/errno.h +++ b/tools/arch/sparc/include/uapi/asm/errno.h @@ -117,4 +117,6 @@ #define EHWPOISON 135 /* Memory page has hardware error */ +#define ENOTREG 136 /* Not a regular file */ + #endif diff --git a/tools/include/uapi/asm-generic/errno.h b/tools/include/uapi/asm-generic/errno.h index 92e7ae493ee3..2216ab9aa32e 100644 --- a/tools/include/uapi/asm-generic/errno.h +++ b/tools/include/uapi/asm-generic/errno.h @@ -122,4 +122,6 @@ #define EHWPOISON 133 /* Memory page has hardware error */ +#define ENOTREG 134 /* Not a regular file */ + #endif -- 2.52.0 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* Re: [PATCH v3 1/4] open: new O_REGULAR flag support 2026-01-27 17:58 ` [PATCH v3 1/4] open: new O_REGULAR flag support Dorjoy Chowdhury @ 2026-01-27 23:23 ` Aleksa Sarai 2026-01-28 7:12 ` Mateusz Guzik 2026-01-27 23:52 ` Jeff Layton 2026-01-29 10:49 ` Christian Brauner 2 siblings, 1 reply; 26+ messages in thread From: Aleksa Sarai @ 2026-01-27 23:23 UTC (permalink / raw) To: Dorjoy Chowdhury Cc: linux-fsdevel, linux-kernel, viro, brauner, jack, jlayton, chuck.lever, alex.aring, arnd, adilger [-- Attachment #1: Type: text/plain, Size: 6258 bytes --] On 2026-01-27, Dorjoy Chowdhury <dorjoychy111@gmail.com> wrote: > This flag indicates the path should be opened if it's a regular file. > This is useful to write secure programs that want to avoid being tricked > into opening device nodes with special semantics while thinking they > operate on regular files. > > A corresponding error code ENOTREG has been introduced. For example, if > open is called on path /dev/null with O_REGULAR in the flag param, it > will return -ENOTREG. > > When used in combination with O_CREAT, either the regular file is > created, or if the path already exists, it is opened if it's a regular > file. Otherwise, -ENOTREG is returned. > > -EINVAL is returned when O_REGULAR is combined with O_DIRECTORY (not > part of O_TMPFILE) because it doesn't make sense to open a path that > is both a directory and a regular file. As you mention in your cover letter, this is something that the UAPI group has asked for in the past[1] and was even discussed at a recent LPC (maybe LPC 2024?) -- thanks for the patch! In the next posting of this patchset, I would suggest including this information in the *commit message* with a link (commit messages end up in the git history, cover letters are a little harder to search for when doing "git blame"). [1]: https://uapi-group.org/kernel-features/#ability-to-only-open-regular-files > #define WILL_CREATE(flags) (flags & (O_CREAT | __O_TMPFILE)) > -#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC) > +#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC | O_REGULAR) It doesn't really make sense to use this flag with O_PATH -- O_PATH file descriptors do not actually open the target inode and so there is no risk to doing this. In fact the method of safely opening files while avoiding device inodes on Linux today is to open an O_PATH, then use fstat(2) to check whether it is a regular file, and then re-open the file descriptor through /proc/self/fd/$n. (This is totally race-safe.) My main reason for pushing back against this it's really quite preferable to avoid expanding the set of O_* flags which work with O_PATH if they don't add much -- O_PATH has really unfortunate behaviour with ignoring other flags and openat2(2) finally fixed that by blocking ignored flag combinations. > inline struct open_how build_open_how(int flags, umode_t mode) > { > @@ -1250,6 +1250,8 @@ inline int build_open_flags(const struct open_how *how, struct open_flags *op) > return -EINVAL; > if (!(acc_mode & MAY_WRITE)) > return -EINVAL; > + } else if ((flags & O_DIRECTORY) && (flags & O_REGULAR)) { > + return -EINVAL; > } > if (flags & O_PATH) { > /* O_PATH only permits certain other flags to be set. */ > diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h > index a332e79b3207..4fd07b0e0a17 100644 > --- a/include/linux/fcntl.h > +++ b/include/linux/fcntl.h > @@ -10,7 +10,7 @@ > (O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | \ > O_APPEND | O_NDELAY | O_NONBLOCK | __O_SYNC | O_DSYNC | \ > FASYNC | O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | \ > - O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE) > + O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE | O_REGULAR) Legacy open(2)/openat(2) do not reject invalid flag arguments, which means that you cannot trivially add a new security-critical flag to them for two reasons: * You cannot easily rely on them because old kernels will not return -EINVAL, meaning you cannot be sure that the flag is supported. You can try to test-run it, but the operation needs to be a non-dangerous operation to try (and caching this has its own issues, such as with programs that apply seccomp filters later). To be fair, since you reject O_DIRECTORY|O_REGULAR there is a relatively easy way to detect this, but the caveats about problems with caching still apply. * Old programs might pass garbage bits that have been ignored thus far, which means that making them have meaning can break userspace. Given the age of open(2) this is a very hard thing to guarantee and is one of many reasons I wrote openat2(2) and finally added proper flag checking. This is something your patch doesn't deal with and I don't think can be done in a satisfactory way (because the behaviour relies on more than just the arguments). For reference, this is why O_TMPFILE includes O_DIRECTORY and requires an O_ACCMODE with write bits -- this combination will fail on old kernels, which allows you to rely on it and also guarantees that no existing older programs passed that flag combination already and happened to work on older kernels. This kind of trick won't work for O_REGULAR, unfortunately. In my view, this should be an openat2(2)-only API. In addition, I would propose that (instead of burning another O_* flag bit for this as a special-purpose API just for regular files) you could have a mask of which S_IFMT bits should be rejected as a new field in "struct open_how". This would let you reject sockets or device inodes but permit FIFOs and regular files or directories, for instance. This could even be done without a new O_* flag at all (the zero-value how->sfmt_mask would allow everything and so would work well with extensible structs), but we could add an O2_* flag anyway. > +#define ENOTREG 134 /* Not a regular file */ > + We are probably a little too reticent to add new errnos, but in this case I think that there should be some description in the commit or cover letter about why a new errno is needed. ENXIO or EPROTONOSUPPORT/EPROTOTYPE is what you would typically use (yes, they aren't a _perfect_ match but one of the common occurrences in syscall design is to read through errno(7) and figure out what errnos kind of fit what you need to express). Then to be fair, the existence of ENOTBLK, ENOTDIR, ENOTSOCK, etc. kind of justify the existence of ENOTREG too. Unfortunately, you won't be able to use ENOTREG if you go with my idea of having mask bits in open_how... (And what errno should we use then...? Hm.) -- Aleksa Sarai https://www.cyphar.com/ [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 265 bytes --] ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v3 1/4] open: new O_REGULAR flag support 2026-01-27 23:23 ` Aleksa Sarai @ 2026-01-28 7:12 ` Mateusz Guzik 2026-01-28 16:57 ` Dorjoy Chowdhury 2026-01-28 19:26 ` Aleksa Sarai 0 siblings, 2 replies; 26+ messages in thread From: Mateusz Guzik @ 2026-01-28 7:12 UTC (permalink / raw) To: Aleksa Sarai Cc: Dorjoy Chowdhury, linux-fsdevel, linux-kernel, viro, brauner, jack, jlayton, chuck.lever, alex.aring, arnd, adilger On Wed, Jan 28, 2026 at 12:23:45AM +0100, Aleksa Sarai wrote: > In my view, this should be an openat2(2)-only API. fwiw +1 from me, the O_ flag situation is already terrible even without the validation woes. I find it most unfortunate the openat2 syscall reuses the O_ namespace. For my taste it would be best closed for business, with all new flag additions using a different space. I can easily see people passing O_WHATEVER to open and openat by blindly assuming they are supported just based on the name. that's a side mini-rant, too late to do anything here now > In addition, I would > propose that (instead of burning another O_* flag bit for this as a > special-purpose API just for regular files) you could have a mask of > which S_IFMT bits should be rejected as a new field in "struct > open_how". This would let you reject sockets or device inodes but permit > FIFOs and regular files or directories, for instance. This could even be > done without a new O_* flag at all (the zero-value how->sfmt_mask would > allow everything and so would work well with extensible structs), but we > could add an O2_* flag anyway. I don't think this works because the vars have overlapping bits: #define S_IFBLK 0060000 #define S_IFDIR 0040000 So you very much can't select what you want off of a bitmask. At best the field could be used to select the one type you are fine with. If one was to pursue the idea, some other defines with unique bits would need to be provided. But even then, semantics should be to only *allow* the bits you are fine with and reject the rest. But I'm not at all confident this is worth any effort -- with O_DIRECTORY already being there and O_REGULAR proposed, is there a use case which wants something else? > > > +#define ENOTREG 134 /* Not a regular file */ > > + > [..] > Then to be fair, the existence of ENOTBLK, ENOTDIR, ENOTSOCK, etc. kind > of justify the existence of ENOTREG too. Unfortunately, you won't be > able to use ENOTREG if you go with my idea of having mask bits in > open_how... (And what errno should we use then...? Hm.) > The most useful behavior would indicate what was found (e.g., a pipe). The easiest way to do it would create errnos for all types (EISDIR already exists for one), but I can't seriously propose that. Going the other way, EBADTYPE or something else reusable would be my idea. ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v3 1/4] open: new O_REGULAR flag support 2026-01-28 7:12 ` Mateusz Guzik @ 2026-01-28 16:57 ` Dorjoy Chowdhury 2026-01-28 19:26 ` Aleksa Sarai 1 sibling, 0 replies; 26+ messages in thread From: Dorjoy Chowdhury @ 2026-01-28 16:57 UTC (permalink / raw) To: Mateusz Guzik, Aleksa Sarai Cc: linux-fsdevel, linux-kernel, viro, brauner, jack, jlayton, chuck.lever, alex.aring, arnd, adilger On Wed, Jan 28, 2026 at 1:12 PM Mateusz Guzik <mjguzik@gmail.com> wrote: > > On Wed, Jan 28, 2026 at 12:23:45AM +0100, Aleksa Sarai wrote: > > In my view, this should be an openat2(2)-only API. > > fwiw +1 from me, the O_ flag situation is already terrible even without > the validation woes. > > I find it most unfortunate the openat2 syscall reuses the O_ namespace. > For my taste it would be best closed for business, with all new flag > additions using a different space. > > I can easily see people passing O_WHATEVER to open and openat by blindly > assuming they are supported just based on the name. > > that's a side mini-rant, too late to do anything here now > > > In addition, I would > > propose that (instead of burning another O_* flag bit for this as a > > special-purpose API just for regular files) you could have a mask of > > which S_IFMT bits should be rejected as a new field in "struct > > open_how". This would let you reject sockets or device inodes but permit > > FIFOs and regular files or directories, for instance. This could even be > > done without a new O_* flag at all (the zero-value how->sfmt_mask would > > allow everything and so would work well with extensible structs), but we > > could add an O2_* flag anyway. > > I don't think this works because the vars have overlapping bits: > #define S_IFBLK 0060000 > #define S_IFDIR 0040000 > > So you very much can't select what you want off of a bitmask. > > At best the field could be used to select the one type you are fine with. > > If one was to pursue the idea, some other defines with unique bits would > need to be provided. But even then, semantics should be to only *allow* > the bits you are fine with and reject the rest. > > But I'm not at all confident this is worth any effort -- with > O_DIRECTORY already being there and O_REGULAR proposed, is there a use > case which wants something else? > Good discussion. So should I just rename the O_REGULAR to O2_REGULAR and create a VALID_OPENAT2_FLAGS and no need to do how->sfmt_mask stuff? > > > > > +#define ENOTREG 134 /* Not a regular file */ > > > + > > > [..] > > Then to be fair, the existence of ENOTBLK, ENOTDIR, ENOTSOCK, etc. kind > > of justify the existence of ENOTREG too. Unfortunately, you won't be > > able to use ENOTREG if you go with my idea of having mask bits in > > open_how... (And what errno should we use then...? Hm.) > > > > The most useful behavior would indicate what was found (e.g., a pipe). > > The easiest way to do it would create errnos for all types (EISDIR > already exists for one), but I can't seriously propose that. > > Going the other way, EBADTYPE or something else reusable would be my > idea. Good point. Maybe ENOTREG is acceptable too? Regards, Dorjoy ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v3 1/4] open: new O_REGULAR flag support 2026-01-28 7:12 ` Mateusz Guzik 2026-01-28 16:57 ` Dorjoy Chowdhury @ 2026-01-28 19:26 ` Aleksa Sarai 1 sibling, 0 replies; 26+ messages in thread From: Aleksa Sarai @ 2026-01-28 19:26 UTC (permalink / raw) To: Mateusz Guzik Cc: Dorjoy Chowdhury, linux-fsdevel, linux-kernel, viro, brauner, jack, jlayton, chuck.lever, alex.aring, arnd, adilger [-- Attachment #1: Type: text/plain, Size: 3934 bytes --] On 2026-01-28, Mateusz Guzik <mjguzik@gmail.com> wrote: > On Wed, Jan 28, 2026 at 12:23:45AM +0100, Aleksa Sarai wrote: > > In my view, this should be an openat2(2)-only API. > > fwiw +1 from me, the O_ flag situation is already terrible even without > the validation woes. > > I find it most unfortunate the openat2 syscall reuses the O_ namespace. > For my taste it would be best closed for business, with all new flag > additions using a different space. We don't have any openat2(2)-only O_* flags yet, I agree that new flag additions (except for very rare cases where you can make them backward compatible -- such as a hypothetical O_EMPTYPATH) should be O2_* or OEXT_* or something. > I can easily see people passing O_WHATEVER to open and openat by blindly > assuming they are supported just based on the name. Yeah, if we don't do that it'll lead to confusion. openat2(2) has exclusive rights to the 64-bit flag bits so we could start with those before we need to cross with the O_* flag space. > that's a side mini-rant, too late to do anything here now > > > In addition, I would > > propose that (instead of burning another O_* flag bit for this as a > > special-purpose API just for regular files) you could have a mask of > > which S_IFMT bits should be rejected as a new field in "struct > > open_how". This would let you reject sockets or device inodes but permit > > FIFOs and regular files or directories, for instance. This could even be > > done without a new O_* flag at all (the zero-value how->sfmt_mask would > > allow everything and so would work well with extensible structs), but we > > could add an O2_* flag anyway. > > I don't think this works because the vars have overlapping bits: > #define S_IFBLK 0060000 > #define S_IFDIR 0040000 > > So you very much can't select what you want off of a bitmask. Well, you can filter on S_IFCHR if you want to block both block/char devices, but yeah the overlap is quite unfortunate... (That would also mean blocking directories would also block S_IFBLK -- I remembered there was an overlap but I forgot it coincided with S_IFDIR... Damn wacky APIs.) > At best the field could be used to select the one type you are fine with. > > If one was to pursue the idea, some other defines with unique bits would > need to be provided. But even then, semantics should be to only *allow* > the bits you are fine with and reject the rest. > > But I'm not at all confident this is worth any effort -- with > O_DIRECTORY already being there and O_REGULAR proposed, is there a use > case which wants something else? There's also O_NOFOLLOW in a similar vein. I can see someone wanting to permit FIFOs, regular files, and directories being fine but blocking everything else. None of O_REGULAR, O_DIRECTORY, nor O_NOFOLLOW provide that. > > > +#define ENOTREG 134 /* Not a regular file */ > > > + > > > [..] > > Then to be fair, the existence of ENOTBLK, ENOTDIR, ENOTSOCK, etc. kind > > of justify the existence of ENOTREG too. Unfortunately, you won't be > > able to use ENOTREG if you go with my idea of having mask bits in > > open_how... (And what errno should we use then...? Hm.) > > > > The most useful behavior would indicate what was found (e.g., a pipe). > > The easiest way to do it would create errnos for all types (EISDIR > already exists for one), but I can't seriously propose that. It might be kinda neat from a potential re-use perspective in other APIs but yeah it would be quite wasteful to burn 3-5 errnos for this when we already have ~4 that are logical inverses. > Going the other way, EBADTYPE or something else reusable would be my > idea. I think that would be reasonable and if you word the error message carefully you can even see it being a fairly generic errno for other places to use. -- Aleksa Sarai https://www.cyphar.com/ [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 265 bytes --] ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v3 1/4] open: new O_REGULAR flag support 2026-01-27 17:58 ` [PATCH v3 1/4] open: new O_REGULAR flag support Dorjoy Chowdhury 2026-01-27 23:23 ` Aleksa Sarai @ 2026-01-27 23:52 ` Jeff Layton 2026-01-28 15:36 ` Dorjoy Chowdhury 2026-01-29 10:49 ` Christian Brauner 2 siblings, 1 reply; 26+ messages in thread From: Jeff Layton @ 2026-01-27 23:52 UTC (permalink / raw) To: Dorjoy Chowdhury, linux-fsdevel Cc: linux-kernel, viro, brauner, jack, chuck.lever, alex.aring, arnd, adilger On Tue, 2026-01-27 at 23:58 +0600, Dorjoy Chowdhury wrote: > This flag indicates the path should be opened if it's a regular file. > This is useful to write secure programs that want to avoid being tricked > into opening device nodes with special semantics while thinking they > operate on regular files. > > A corresponding error code ENOTREG has been introduced. For example, if > open is called on path /dev/null with O_REGULAR in the flag param, it > will return -ENOTREG. > > When used in combination with O_CREAT, either the regular file is > created, or if the path already exists, it is opened if it's a regular > file. Otherwise, -ENOTREG is returned. > > -EINVAL is returned when O_REGULAR is combined with O_DIRECTORY (not > part of O_TMPFILE) because it doesn't make sense to open a path that > is both a directory and a regular file. > > Signed-off-by: Dorjoy Chowdhury <dorjoychy111@gmail.com> > --- > arch/alpha/include/uapi/asm/errno.h | 2 ++ > arch/alpha/include/uapi/asm/fcntl.h | 1 + > arch/mips/include/uapi/asm/errno.h | 2 ++ > arch/parisc/include/uapi/asm/errno.h | 2 ++ > arch/parisc/include/uapi/asm/fcntl.h | 1 + > arch/sparc/include/uapi/asm/errno.h | 2 ++ > arch/sparc/include/uapi/asm/fcntl.h | 1 + > fs/fcntl.c | 2 +- > fs/namei.c | 6 ++++++ > fs/open.c | 4 +++- > include/linux/fcntl.h | 2 +- > include/uapi/asm-generic/errno.h | 2 ++ > include/uapi/asm-generic/fcntl.h | 4 ++++ > tools/arch/alpha/include/uapi/asm/errno.h | 2 ++ > tools/arch/mips/include/uapi/asm/errno.h | 2 ++ > tools/arch/parisc/include/uapi/asm/errno.h | 2 ++ > tools/arch/sparc/include/uapi/asm/errno.h | 2 ++ > tools/include/uapi/asm-generic/errno.h | 2 ++ > 18 files changed, 38 insertions(+), 3 deletions(-) > > diff --git a/arch/alpha/include/uapi/asm/errno.h b/arch/alpha/include/uapi/asm/errno.h > index 6791f6508632..8bbcaa9024f9 100644 > --- a/arch/alpha/include/uapi/asm/errno.h > +++ b/arch/alpha/include/uapi/asm/errno.h > @@ -127,4 +127,6 @@ > > #define EHWPOISON 139 /* Memory page has hardware error */ > > +#define ENOTREG 140 /* Not a regular file */ > + > #endif > diff --git a/arch/alpha/include/uapi/asm/fcntl.h b/arch/alpha/include/uapi/asm/fcntl.h > index 50bdc8e8a271..4da5a64c23bd 100644 > --- a/arch/alpha/include/uapi/asm/fcntl.h > +++ b/arch/alpha/include/uapi/asm/fcntl.h > @@ -34,6 +34,7 @@ > > #define O_PATH 040000000 > #define __O_TMPFILE 0100000000 > +#define O_REGULAR 0200000000 > > #define F_GETLK 7 > #define F_SETLK 8 > diff --git a/arch/mips/include/uapi/asm/errno.h b/arch/mips/include/uapi/asm/errno.h > index c01ed91b1ef4..293c78777254 100644 > --- a/arch/mips/include/uapi/asm/errno.h > +++ b/arch/mips/include/uapi/asm/errno.h > @@ -126,6 +126,8 @@ > > #define EHWPOISON 168 /* Memory page has hardware error */ > > +#define ENOTREG 169 /* Not a regular file */ > + > #define EDQUOT 1133 /* Quota exceeded */ > > > diff --git a/arch/parisc/include/uapi/asm/errno.h b/arch/parisc/include/uapi/asm/errno.h > index 8cbc07c1903e..442917484f99 100644 > --- a/arch/parisc/include/uapi/asm/errno.h > +++ b/arch/parisc/include/uapi/asm/errno.h > @@ -124,4 +124,6 @@ > > #define EHWPOISON 257 /* Memory page has hardware error */ > > +#define ENOTREG 258 /* Not a regular file */ > + > #endif > diff --git a/arch/parisc/include/uapi/asm/fcntl.h b/arch/parisc/include/uapi/asm/fcntl.h > index 03dee816cb13..0cc3320fe326 100644 > --- a/arch/parisc/include/uapi/asm/fcntl.h > +++ b/arch/parisc/include/uapi/asm/fcntl.h > @@ -19,6 +19,7 @@ > > #define O_PATH 020000000 > #define __O_TMPFILE 040000000 > +#define O_REGULAR 0100000000 > > #define F_GETLK64 8 > #define F_SETLK64 9 > diff --git a/arch/sparc/include/uapi/asm/errno.h b/arch/sparc/include/uapi/asm/errno.h > index 4a41e7835fd5..8dce0bfeab74 100644 > --- a/arch/sparc/include/uapi/asm/errno.h > +++ b/arch/sparc/include/uapi/asm/errno.h > @@ -117,4 +117,6 @@ > > #define EHWPOISON 135 /* Memory page has hardware error */ > > +#define ENOTREG 136 /* Not a regular file */ > + > #endif > diff --git a/arch/sparc/include/uapi/asm/fcntl.h b/arch/sparc/include/uapi/asm/fcntl.h > index 67dae75e5274..a93d18d2c23e 100644 > --- a/arch/sparc/include/uapi/asm/fcntl.h > +++ b/arch/sparc/include/uapi/asm/fcntl.h > @@ -37,6 +37,7 @@ > > #define O_PATH 0x1000000 > #define __O_TMPFILE 0x2000000 > +#define O_REGULAR 0x4000000 > > #define F_GETOWN 5 /* for sockets. */ > #define F_SETOWN 6 /* for sockets. */ > diff --git a/fs/fcntl.c b/fs/fcntl.c > index f93dbca08435..62ab4ad2b6f5 100644 > --- a/fs/fcntl.c > +++ b/fs/fcntl.c > @@ -1169,7 +1169,7 @@ static int __init fcntl_init(void) > * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY > * is defined as O_NONBLOCK on some platforms and not on others. > */ > - BUILD_BUG_ON(20 - 1 /* for O_RDONLY being 0 */ != > + BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ != > HWEIGHT32( > (VALID_OPEN_FLAGS & ~(O_NONBLOCK | O_NDELAY)) | > __FMODE_EXEC)); > diff --git a/fs/namei.c b/fs/namei.c > index b28ecb699f32..f5504ae4b03c 100644 > --- a/fs/namei.c > +++ b/fs/namei.c > @@ -4616,6 +4616,10 @@ static int do_open(struct nameidata *nd, > if (unlikely(error)) > return error; > } > + > + if ((open_flag & O_REGULAR) && !d_is_reg(nd->path.dentry)) > + return -ENOTREG; > + > if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry)) > return -ENOTDIR; > > @@ -4765,6 +4769,8 @@ static int do_o_path(struct nameidata *nd, unsigned flags, struct file *file) > struct path path; > int error = path_lookupat(nd, flags, &path); > if (!error) { > + if ((file->f_flags & O_REGULAR) && !d_is_reg(path.dentry)) > + return -ENOTREG; > audit_inode(nd->name, path.dentry, 0); > error = vfs_open(&path, file); > path_put(&path); > diff --git a/fs/open.c b/fs/open.c > index 74c4c1462b3e..82153e21907e 100644 > --- a/fs/open.c > +++ b/fs/open.c > @@ -1173,7 +1173,7 @@ struct file *kernel_file_open(const struct path *path, int flags, > EXPORT_SYMBOL_GPL(kernel_file_open); > > #define WILL_CREATE(flags) (flags & (O_CREAT | __O_TMPFILE)) > -#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC) > +#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC | O_REGULAR) > > inline struct open_how build_open_how(int flags, umode_t mode) > { > @@ -1250,6 +1250,8 @@ inline int build_open_flags(const struct open_how *how, struct open_flags *op) > return -EINVAL; > if (!(acc_mode & MAY_WRITE)) > return -EINVAL; > + } else if ((flags & O_DIRECTORY) && (flags & O_REGULAR)) { > + return -EINVAL; > } > if (flags & O_PATH) { > /* O_PATH only permits certain other flags to be set. */ > diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h > index a332e79b3207..4fd07b0e0a17 100644 > --- a/include/linux/fcntl.h > +++ b/include/linux/fcntl.h > @@ -10,7 +10,7 @@ > (O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | \ > O_APPEND | O_NDELAY | O_NONBLOCK | __O_SYNC | O_DSYNC | \ > FASYNC | O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | \ > - O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE) > + O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE | O_REGULAR) > > /* List of all valid flags for the how->resolve argument: */ > #define VALID_RESOLVE_FLAGS \ > diff --git a/include/uapi/asm-generic/errno.h b/include/uapi/asm-generic/errno.h > index 92e7ae493ee3..2216ab9aa32e 100644 > --- a/include/uapi/asm-generic/errno.h > +++ b/include/uapi/asm-generic/errno.h > @@ -122,4 +122,6 @@ > > #define EHWPOISON 133 /* Memory page has hardware error */ > > +#define ENOTREG 134 /* Not a regular file */ > + > #endif > diff --git a/include/uapi/asm-generic/fcntl.h b/include/uapi/asm-generic/fcntl.h > index 613475285643..3468b352a575 100644 > --- a/include/uapi/asm-generic/fcntl.h > +++ b/include/uapi/asm-generic/fcntl.h > @@ -88,6 +88,10 @@ > #define __O_TMPFILE 020000000 > #endif > > +#ifndef O_REGULAR > +#define O_REGULAR 040000000 > +#endif > + > /* a horrid kludge trying to make sure that this will fail on old kernels */ > #define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) > > diff --git a/tools/arch/alpha/include/uapi/asm/errno.h b/tools/arch/alpha/include/uapi/asm/errno.h > index 6791f6508632..8bbcaa9024f9 100644 > --- a/tools/arch/alpha/include/uapi/asm/errno.h > +++ b/tools/arch/alpha/include/uapi/asm/errno.h > @@ -127,4 +127,6 @@ > > #define EHWPOISON 139 /* Memory page has hardware error */ > > +#define ENOTREG 140 /* Not a regular file */ > + > #endif > diff --git a/tools/arch/mips/include/uapi/asm/errno.h b/tools/arch/mips/include/uapi/asm/errno.h > index c01ed91b1ef4..293c78777254 100644 > --- a/tools/arch/mips/include/uapi/asm/errno.h > +++ b/tools/arch/mips/include/uapi/asm/errno.h > @@ -126,6 +126,8 @@ > > #define EHWPOISON 168 /* Memory page has hardware error */ > > +#define ENOTREG 169 /* Not a regular file */ > + > #define EDQUOT 1133 /* Quota exceeded */ > > > diff --git a/tools/arch/parisc/include/uapi/asm/errno.h b/tools/arch/parisc/include/uapi/asm/errno.h > index 8cbc07c1903e..442917484f99 100644 > --- a/tools/arch/parisc/include/uapi/asm/errno.h > +++ b/tools/arch/parisc/include/uapi/asm/errno.h > @@ -124,4 +124,6 @@ > > #define EHWPOISON 257 /* Memory page has hardware error */ > > +#define ENOTREG 258 /* Not a regular file */ > + > #endif > diff --git a/tools/arch/sparc/include/uapi/asm/errno.h b/tools/arch/sparc/include/uapi/asm/errno.h > index 4a41e7835fd5..8dce0bfeab74 100644 > --- a/tools/arch/sparc/include/uapi/asm/errno.h > +++ b/tools/arch/sparc/include/uapi/asm/errno.h > @@ -117,4 +117,6 @@ > > #define EHWPOISON 135 /* Memory page has hardware error */ > > +#define ENOTREG 136 /* Not a regular file */ > + > #endif > diff --git a/tools/include/uapi/asm-generic/errno.h b/tools/include/uapi/asm-generic/errno.h > index 92e7ae493ee3..2216ab9aa32e 100644 > --- a/tools/include/uapi/asm-generic/errno.h > +++ b/tools/include/uapi/asm-generic/errno.h > @@ -122,4 +122,6 @@ > > #define EHWPOISON 133 /* Memory page has hardware error */ > > +#define ENOTREG 134 /* Not a regular file */ > + > #endif One thing this patch is missing is handling for ->atomic_open(). I imagine most of the filesystems that provide that op can't support O_REGULAR properly (maybe cifs can? idk). What you probably want to do is add in some patches that make all of the atomic_open operations in the kernel return -EINVAL if O_REGULAR is set. Then, once the basic support is in, you or someone else can go back and implement support for O_REGULAR where possible. -- Jeff Layton <jlayton@kernel.org> ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v3 1/4] open: new O_REGULAR flag support 2026-01-27 23:52 ` Jeff Layton @ 2026-01-28 15:36 ` Dorjoy Chowdhury 2026-01-28 15:51 ` Jeff Layton 0 siblings, 1 reply; 26+ messages in thread From: Dorjoy Chowdhury @ 2026-01-28 15:36 UTC (permalink / raw) To: Jeff Layton Cc: linux-fsdevel, linux-kernel, viro, brauner, jack, chuck.lever, alex.aring, arnd, adilger On Wed, Jan 28, 2026 at 5:52 AM Jeff Layton <jlayton@kernel.org> wrote: > > On Tue, 2026-01-27 at 23:58 +0600, Dorjoy Chowdhury wrote: > > This flag indicates the path should be opened if it's a regular file. > > This is useful to write secure programs that want to avoid being tricked > > into opening device nodes with special semantics while thinking they > > operate on regular files. > > > > A corresponding error code ENOTREG has been introduced. For example, if > > open is called on path /dev/null with O_REGULAR in the flag param, it > > will return -ENOTREG. > > > > When used in combination with O_CREAT, either the regular file is > > created, or if the path already exists, it is opened if it's a regular > > file. Otherwise, -ENOTREG is returned. > > > > -EINVAL is returned when O_REGULAR is combined with O_DIRECTORY (not > > part of O_TMPFILE) because it doesn't make sense to open a path that > > is both a directory and a regular file. > > > > Signed-off-by: Dorjoy Chowdhury <dorjoychy111@gmail.com> > > --- > > arch/alpha/include/uapi/asm/errno.h | 2 ++ > > arch/alpha/include/uapi/asm/fcntl.h | 1 + > > arch/mips/include/uapi/asm/errno.h | 2 ++ > > arch/parisc/include/uapi/asm/errno.h | 2 ++ > > arch/parisc/include/uapi/asm/fcntl.h | 1 + > > arch/sparc/include/uapi/asm/errno.h | 2 ++ > > arch/sparc/include/uapi/asm/fcntl.h | 1 + > > fs/fcntl.c | 2 +- > > fs/namei.c | 6 ++++++ > > fs/open.c | 4 +++- > > include/linux/fcntl.h | 2 +- > > include/uapi/asm-generic/errno.h | 2 ++ > > include/uapi/asm-generic/fcntl.h | 4 ++++ > > tools/arch/alpha/include/uapi/asm/errno.h | 2 ++ > > tools/arch/mips/include/uapi/asm/errno.h | 2 ++ > > tools/arch/parisc/include/uapi/asm/errno.h | 2 ++ > > tools/arch/sparc/include/uapi/asm/errno.h | 2 ++ > > tools/include/uapi/asm-generic/errno.h | 2 ++ > > 18 files changed, 38 insertions(+), 3 deletions(-) > > > > diff --git a/arch/alpha/include/uapi/asm/errno.h b/arch/alpha/include/uapi/asm/errno.h > > index 6791f6508632..8bbcaa9024f9 100644 > > --- a/arch/alpha/include/uapi/asm/errno.h > > +++ b/arch/alpha/include/uapi/asm/errno.h > > @@ -127,4 +127,6 @@ > > > > #define EHWPOISON 139 /* Memory page has hardware error */ > > > > +#define ENOTREG 140 /* Not a regular file */ > > + > > #endif > > diff --git a/arch/alpha/include/uapi/asm/fcntl.h b/arch/alpha/include/uapi/asm/fcntl.h > > index 50bdc8e8a271..4da5a64c23bd 100644 > > --- a/arch/alpha/include/uapi/asm/fcntl.h > > +++ b/arch/alpha/include/uapi/asm/fcntl.h > > @@ -34,6 +34,7 @@ > > > > #define O_PATH 040000000 > > #define __O_TMPFILE 0100000000 > > +#define O_REGULAR 0200000000 > > > > #define F_GETLK 7 > > #define F_SETLK 8 > > diff --git a/arch/mips/include/uapi/asm/errno.h b/arch/mips/include/uapi/asm/errno.h > > index c01ed91b1ef4..293c78777254 100644 > > --- a/arch/mips/include/uapi/asm/errno.h > > +++ b/arch/mips/include/uapi/asm/errno.h > > @@ -126,6 +126,8 @@ > > > > #define EHWPOISON 168 /* Memory page has hardware error */ > > > > +#define ENOTREG 169 /* Not a regular file */ > > + > > #define EDQUOT 1133 /* Quota exceeded */ > > > > > > diff --git a/arch/parisc/include/uapi/asm/errno.h b/arch/parisc/include/uapi/asm/errno.h > > index 8cbc07c1903e..442917484f99 100644 > > --- a/arch/parisc/include/uapi/asm/errno.h > > +++ b/arch/parisc/include/uapi/asm/errno.h > > @@ -124,4 +124,6 @@ > > > > #define EHWPOISON 257 /* Memory page has hardware error */ > > > > +#define ENOTREG 258 /* Not a regular file */ > > + > > #endif > > diff --git a/arch/parisc/include/uapi/asm/fcntl.h b/arch/parisc/include/uapi/asm/fcntl.h > > index 03dee816cb13..0cc3320fe326 100644 > > --- a/arch/parisc/include/uapi/asm/fcntl.h > > +++ b/arch/parisc/include/uapi/asm/fcntl.h > > @@ -19,6 +19,7 @@ > > > > #define O_PATH 020000000 > > #define __O_TMPFILE 040000000 > > +#define O_REGULAR 0100000000 > > > > #define F_GETLK64 8 > > #define F_SETLK64 9 > > diff --git a/arch/sparc/include/uapi/asm/errno.h b/arch/sparc/include/uapi/asm/errno.h > > index 4a41e7835fd5..8dce0bfeab74 100644 > > --- a/arch/sparc/include/uapi/asm/errno.h > > +++ b/arch/sparc/include/uapi/asm/errno.h > > @@ -117,4 +117,6 @@ > > > > #define EHWPOISON 135 /* Memory page has hardware error */ > > > > +#define ENOTREG 136 /* Not a regular file */ > > + > > #endif > > diff --git a/arch/sparc/include/uapi/asm/fcntl.h b/arch/sparc/include/uapi/asm/fcntl.h > > index 67dae75e5274..a93d18d2c23e 100644 > > --- a/arch/sparc/include/uapi/asm/fcntl.h > > +++ b/arch/sparc/include/uapi/asm/fcntl.h > > @@ -37,6 +37,7 @@ > > > > #define O_PATH 0x1000000 > > #define __O_TMPFILE 0x2000000 > > +#define O_REGULAR 0x4000000 > > > > #define F_GETOWN 5 /* for sockets. */ > > #define F_SETOWN 6 /* for sockets. */ > > diff --git a/fs/fcntl.c b/fs/fcntl.c > > index f93dbca08435..62ab4ad2b6f5 100644 > > --- a/fs/fcntl.c > > +++ b/fs/fcntl.c > > @@ -1169,7 +1169,7 @@ static int __init fcntl_init(void) > > * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY > > * is defined as O_NONBLOCK on some platforms and not on others. > > */ > > - BUILD_BUG_ON(20 - 1 /* for O_RDONLY being 0 */ != > > + BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ != > > HWEIGHT32( > > (VALID_OPEN_FLAGS & ~(O_NONBLOCK | O_NDELAY)) | > > __FMODE_EXEC)); > > diff --git a/fs/namei.c b/fs/namei.c > > index b28ecb699f32..f5504ae4b03c 100644 > > --- a/fs/namei.c > > +++ b/fs/namei.c > > @@ -4616,6 +4616,10 @@ static int do_open(struct nameidata *nd, > > if (unlikely(error)) > > return error; > > } > > + > > + if ((open_flag & O_REGULAR) && !d_is_reg(nd->path.dentry)) > > + return -ENOTREG; > > + > > if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry)) > > return -ENOTDIR; > > > > @@ -4765,6 +4769,8 @@ static int do_o_path(struct nameidata *nd, unsigned flags, struct file *file) > > struct path path; > > int error = path_lookupat(nd, flags, &path); > > if (!error) { > > + if ((file->f_flags & O_REGULAR) && !d_is_reg(path.dentry)) > > + return -ENOTREG; > > audit_inode(nd->name, path.dentry, 0); > > error = vfs_open(&path, file); > > path_put(&path); > > diff --git a/fs/open.c b/fs/open.c > > index 74c4c1462b3e..82153e21907e 100644 > > --- a/fs/open.c > > +++ b/fs/open.c > > @@ -1173,7 +1173,7 @@ struct file *kernel_file_open(const struct path *path, int flags, > > EXPORT_SYMBOL_GPL(kernel_file_open); > > > > #define WILL_CREATE(flags) (flags & (O_CREAT | __O_TMPFILE)) > > -#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC) > > +#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC | O_REGULAR) > > > > inline struct open_how build_open_how(int flags, umode_t mode) > > { > > @@ -1250,6 +1250,8 @@ inline int build_open_flags(const struct open_how *how, struct open_flags *op) > > return -EINVAL; > > if (!(acc_mode & MAY_WRITE)) > > return -EINVAL; > > + } else if ((flags & O_DIRECTORY) && (flags & O_REGULAR)) { > > + return -EINVAL; > > } > > if (flags & O_PATH) { > > /* O_PATH only permits certain other flags to be set. */ > > diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h > > index a332e79b3207..4fd07b0e0a17 100644 > > --- a/include/linux/fcntl.h > > +++ b/include/linux/fcntl.h > > @@ -10,7 +10,7 @@ > > (O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | \ > > O_APPEND | O_NDELAY | O_NONBLOCK | __O_SYNC | O_DSYNC | \ > > FASYNC | O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | \ > > - O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE) > > + O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE | O_REGULAR) > > > > /* List of all valid flags for the how->resolve argument: */ > > #define VALID_RESOLVE_FLAGS \ > > diff --git a/include/uapi/asm-generic/errno.h b/include/uapi/asm-generic/errno.h > > index 92e7ae493ee3..2216ab9aa32e 100644 > > --- a/include/uapi/asm-generic/errno.h > > +++ b/include/uapi/asm-generic/errno.h > > @@ -122,4 +122,6 @@ > > > > #define EHWPOISON 133 /* Memory page has hardware error */ > > > > +#define ENOTREG 134 /* Not a regular file */ > > + > > #endif > > diff --git a/include/uapi/asm-generic/fcntl.h b/include/uapi/asm-generic/fcntl.h > > index 613475285643..3468b352a575 100644 > > --- a/include/uapi/asm-generic/fcntl.h > > +++ b/include/uapi/asm-generic/fcntl.h > > @@ -88,6 +88,10 @@ > > #define __O_TMPFILE 020000000 > > #endif > > > > +#ifndef O_REGULAR > > +#define O_REGULAR 040000000 > > +#endif > > + > > /* a horrid kludge trying to make sure that this will fail on old kernels */ > > #define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) > > > > diff --git a/tools/arch/alpha/include/uapi/asm/errno.h b/tools/arch/alpha/include/uapi/asm/errno.h > > index 6791f6508632..8bbcaa9024f9 100644 > > --- a/tools/arch/alpha/include/uapi/asm/errno.h > > +++ b/tools/arch/alpha/include/uapi/asm/errno.h > > @@ -127,4 +127,6 @@ > > > > #define EHWPOISON 139 /* Memory page has hardware error */ > > > > +#define ENOTREG 140 /* Not a regular file */ > > + > > #endif > > diff --git a/tools/arch/mips/include/uapi/asm/errno.h b/tools/arch/mips/include/uapi/asm/errno.h > > index c01ed91b1ef4..293c78777254 100644 > > --- a/tools/arch/mips/include/uapi/asm/errno.h > > +++ b/tools/arch/mips/include/uapi/asm/errno.h > > @@ -126,6 +126,8 @@ > > > > #define EHWPOISON 168 /* Memory page has hardware error */ > > > > +#define ENOTREG 169 /* Not a regular file */ > > + > > #define EDQUOT 1133 /* Quota exceeded */ > > > > > > diff --git a/tools/arch/parisc/include/uapi/asm/errno.h b/tools/arch/parisc/include/uapi/asm/errno.h > > index 8cbc07c1903e..442917484f99 100644 > > --- a/tools/arch/parisc/include/uapi/asm/errno.h > > +++ b/tools/arch/parisc/include/uapi/asm/errno.h > > @@ -124,4 +124,6 @@ > > > > #define EHWPOISON 257 /* Memory page has hardware error */ > > > > +#define ENOTREG 258 /* Not a regular file */ > > + > > #endif > > diff --git a/tools/arch/sparc/include/uapi/asm/errno.h b/tools/arch/sparc/include/uapi/asm/errno.h > > index 4a41e7835fd5..8dce0bfeab74 100644 > > --- a/tools/arch/sparc/include/uapi/asm/errno.h > > +++ b/tools/arch/sparc/include/uapi/asm/errno.h > > @@ -117,4 +117,6 @@ > > > > #define EHWPOISON 135 /* Memory page has hardware error */ > > > > +#define ENOTREG 136 /* Not a regular file */ > > + > > #endif > > diff --git a/tools/include/uapi/asm-generic/errno.h b/tools/include/uapi/asm-generic/errno.h > > index 92e7ae493ee3..2216ab9aa32e 100644 > > --- a/tools/include/uapi/asm-generic/errno.h > > +++ b/tools/include/uapi/asm-generic/errno.h > > @@ -122,4 +122,6 @@ > > > > #define EHWPOISON 133 /* Memory page has hardware error */ > > > > +#define ENOTREG 134 /* Not a regular file */ > > + > > #endif > > One thing this patch is missing is handling for ->atomic_open(). I > imagine most of the filesystems that provide that op can't support > O_REGULAR properly (maybe cifs can? idk). What you probably want to do > is add in some patches that make all of the atomic_open operations in > the kernel return -EINVAL if O_REGULAR is set. > > Then, once the basic support is in, you or someone else can go back and > implement support for O_REGULAR where possible. Thank you for the feedback. I don't quite understand what I need to fix. I thought open system calls always create regular files, so atomic_open probably always creates regular files? Can you please give me some more details as to where I need to fix this and what the actual bug here is that is related to atomic_open? I think I had done some normal testing and when using O_CREAT | O_REGULAR, if the file doesn't exist, the file gets created and the file that gets created is a regular file, so it probably makes sense? Or should the behavior be that if file doesn't exist, -EINVAL is returned and if file exists it is opened if regular, otherwise -ENOTREG is returned? Regards, Dorjoy ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v3 1/4] open: new O_REGULAR flag support 2026-01-28 15:36 ` Dorjoy Chowdhury @ 2026-01-28 15:51 ` Jeff Layton 2026-01-28 16:29 ` Dorjoy Chowdhury 2026-01-29 12:33 ` Christian Brauner 0 siblings, 2 replies; 26+ messages in thread From: Jeff Layton @ 2026-01-28 15:51 UTC (permalink / raw) To: Dorjoy Chowdhury Cc: linux-fsdevel, linux-kernel, viro, brauner, jack, chuck.lever, alex.aring, arnd, adilger On Wed, 2026-01-28 at 21:36 +0600, Dorjoy Chowdhury wrote: > On Wed, Jan 28, 2026 at 5:52 AM Jeff Layton <jlayton@kernel.org> wrote: > > > > On Tue, 2026-01-27 at 23:58 +0600, Dorjoy Chowdhury wrote: > > > This flag indicates the path should be opened if it's a regular file. > > > This is useful to write secure programs that want to avoid being tricked > > > into opening device nodes with special semantics while thinking they > > > operate on regular files. > > > > > > A corresponding error code ENOTREG has been introduced. For example, if > > > open is called on path /dev/null with O_REGULAR in the flag param, it > > > will return -ENOTREG. > > > > > > When used in combination with O_CREAT, either the regular file is > > > created, or if the path already exists, it is opened if it's a regular > > > file. Otherwise, -ENOTREG is returned. > > > > > > -EINVAL is returned when O_REGULAR is combined with O_DIRECTORY (not > > > part of O_TMPFILE) because it doesn't make sense to open a path that > > > is both a directory and a regular file. > > > > > > Signed-off-by: Dorjoy Chowdhury <dorjoychy111@gmail.com> > > > --- > > > arch/alpha/include/uapi/asm/errno.h | 2 ++ > > > arch/alpha/include/uapi/asm/fcntl.h | 1 + > > > arch/mips/include/uapi/asm/errno.h | 2 ++ > > > arch/parisc/include/uapi/asm/errno.h | 2 ++ > > > arch/parisc/include/uapi/asm/fcntl.h | 1 + > > > arch/sparc/include/uapi/asm/errno.h | 2 ++ > > > arch/sparc/include/uapi/asm/fcntl.h | 1 + > > > fs/fcntl.c | 2 +- > > > fs/namei.c | 6 ++++++ > > > fs/open.c | 4 +++- > > > include/linux/fcntl.h | 2 +- > > > include/uapi/asm-generic/errno.h | 2 ++ > > > include/uapi/asm-generic/fcntl.h | 4 ++++ > > > tools/arch/alpha/include/uapi/asm/errno.h | 2 ++ > > > tools/arch/mips/include/uapi/asm/errno.h | 2 ++ > > > tools/arch/parisc/include/uapi/asm/errno.h | 2 ++ > > > tools/arch/sparc/include/uapi/asm/errno.h | 2 ++ > > > tools/include/uapi/asm-generic/errno.h | 2 ++ > > > 18 files changed, 38 insertions(+), 3 deletions(-) > > > > > > diff --git a/arch/alpha/include/uapi/asm/errno.h b/arch/alpha/include/uapi/asm/errno.h > > > index 6791f6508632..8bbcaa9024f9 100644 > > > --- a/arch/alpha/include/uapi/asm/errno.h > > > +++ b/arch/alpha/include/uapi/asm/errno.h > > > @@ -127,4 +127,6 @@ > > > > > > #define EHWPOISON 139 /* Memory page has hardware error */ > > > > > > +#define ENOTREG 140 /* Not a regular file */ > > > + > > > #endif > > > diff --git a/arch/alpha/include/uapi/asm/fcntl.h b/arch/alpha/include/uapi/asm/fcntl.h > > > index 50bdc8e8a271..4da5a64c23bd 100644 > > > --- a/arch/alpha/include/uapi/asm/fcntl.h > > > +++ b/arch/alpha/include/uapi/asm/fcntl.h > > > @@ -34,6 +34,7 @@ > > > > > > #define O_PATH 040000000 > > > #define __O_TMPFILE 0100000000 > > > +#define O_REGULAR 0200000000 > > > > > > #define F_GETLK 7 > > > #define F_SETLK 8 > > > diff --git a/arch/mips/include/uapi/asm/errno.h b/arch/mips/include/uapi/asm/errno.h > > > index c01ed91b1ef4..293c78777254 100644 > > > --- a/arch/mips/include/uapi/asm/errno.h > > > +++ b/arch/mips/include/uapi/asm/errno.h > > > @@ -126,6 +126,8 @@ > > > > > > #define EHWPOISON 168 /* Memory page has hardware error */ > > > > > > +#define ENOTREG 169 /* Not a regular file */ > > > + > > > #define EDQUOT 1133 /* Quota exceeded */ > > > > > > > > > diff --git a/arch/parisc/include/uapi/asm/errno.h b/arch/parisc/include/uapi/asm/errno.h > > > index 8cbc07c1903e..442917484f99 100644 > > > --- a/arch/parisc/include/uapi/asm/errno.h > > > +++ b/arch/parisc/include/uapi/asm/errno.h > > > @@ -124,4 +124,6 @@ > > > > > > #define EHWPOISON 257 /* Memory page has hardware error */ > > > > > > +#define ENOTREG 258 /* Not a regular file */ > > > + > > > #endif > > > diff --git a/arch/parisc/include/uapi/asm/fcntl.h b/arch/parisc/include/uapi/asm/fcntl.h > > > index 03dee816cb13..0cc3320fe326 100644 > > > --- a/arch/parisc/include/uapi/asm/fcntl.h > > > +++ b/arch/parisc/include/uapi/asm/fcntl.h > > > @@ -19,6 +19,7 @@ > > > > > > #define O_PATH 020000000 > > > #define __O_TMPFILE 040000000 > > > +#define O_REGULAR 0100000000 > > > > > > #define F_GETLK64 8 > > > #define F_SETLK64 9 > > > diff --git a/arch/sparc/include/uapi/asm/errno.h b/arch/sparc/include/uapi/asm/errno.h > > > index 4a41e7835fd5..8dce0bfeab74 100644 > > > --- a/arch/sparc/include/uapi/asm/errno.h > > > +++ b/arch/sparc/include/uapi/asm/errno.h > > > @@ -117,4 +117,6 @@ > > > > > > #define EHWPOISON 135 /* Memory page has hardware error */ > > > > > > +#define ENOTREG 136 /* Not a regular file */ > > > + > > > #endif > > > diff --git a/arch/sparc/include/uapi/asm/fcntl.h b/arch/sparc/include/uapi/asm/fcntl.h > > > index 67dae75e5274..a93d18d2c23e 100644 > > > --- a/arch/sparc/include/uapi/asm/fcntl.h > > > +++ b/arch/sparc/include/uapi/asm/fcntl.h > > > @@ -37,6 +37,7 @@ > > > > > > #define O_PATH 0x1000000 > > > #define __O_TMPFILE 0x2000000 > > > +#define O_REGULAR 0x4000000 > > > > > > #define F_GETOWN 5 /* for sockets. */ > > > #define F_SETOWN 6 /* for sockets. */ > > > diff --git a/fs/fcntl.c b/fs/fcntl.c > > > index f93dbca08435..62ab4ad2b6f5 100644 > > > --- a/fs/fcntl.c > > > +++ b/fs/fcntl.c > > > @@ -1169,7 +1169,7 @@ static int __init fcntl_init(void) > > > * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY > > > * is defined as O_NONBLOCK on some platforms and not on others. > > > */ > > > - BUILD_BUG_ON(20 - 1 /* for O_RDONLY being 0 */ != > > > + BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ != > > > HWEIGHT32( > > > (VALID_OPEN_FLAGS & ~(O_NONBLOCK | O_NDELAY)) | > > > __FMODE_EXEC)); > > > diff --git a/fs/namei.c b/fs/namei.c > > > index b28ecb699f32..f5504ae4b03c 100644 > > > --- a/fs/namei.c > > > +++ b/fs/namei.c > > > @@ -4616,6 +4616,10 @@ static int do_open(struct nameidata *nd, > > > if (unlikely(error)) > > > return error; > > > } > > > + > > > + if ((open_flag & O_REGULAR) && !d_is_reg(nd->path.dentry)) > > > + return -ENOTREG; > > > + > > > if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry)) > > > return -ENOTDIR; > > > > > > @@ -4765,6 +4769,8 @@ static int do_o_path(struct nameidata *nd, unsigned flags, struct file *file) > > > struct path path; > > > int error = path_lookupat(nd, flags, &path); > > > if (!error) { > > > + if ((file->f_flags & O_REGULAR) && !d_is_reg(path.dentry)) > > > + return -ENOTREG; > > > audit_inode(nd->name, path.dentry, 0); > > > error = vfs_open(&path, file); > > > path_put(&path); > > > diff --git a/fs/open.c b/fs/open.c > > > index 74c4c1462b3e..82153e21907e 100644 > > > --- a/fs/open.c > > > +++ b/fs/open.c > > > @@ -1173,7 +1173,7 @@ struct file *kernel_file_open(const struct path *path, int flags, > > > EXPORT_SYMBOL_GPL(kernel_file_open); > > > > > > #define WILL_CREATE(flags) (flags & (O_CREAT | __O_TMPFILE)) > > > -#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC) > > > +#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC | O_REGULAR) > > > > > > inline struct open_how build_open_how(int flags, umode_t mode) > > > { > > > @@ -1250,6 +1250,8 @@ inline int build_open_flags(const struct open_how *how, struct open_flags *op) > > > return -EINVAL; > > > if (!(acc_mode & MAY_WRITE)) > > > return -EINVAL; > > > + } else if ((flags & O_DIRECTORY) && (flags & O_REGULAR)) { > > > + return -EINVAL; > > > } > > > if (flags & O_PATH) { > > > /* O_PATH only permits certain other flags to be set. */ > > > diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h > > > index a332e79b3207..4fd07b0e0a17 100644 > > > --- a/include/linux/fcntl.h > > > +++ b/include/linux/fcntl.h > > > @@ -10,7 +10,7 @@ > > > (O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | \ > > > O_APPEND | O_NDELAY | O_NONBLOCK | __O_SYNC | O_DSYNC | \ > > > FASYNC | O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | \ > > > - O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE) > > > + O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE | O_REGULAR) > > > > > > /* List of all valid flags for the how->resolve argument: */ > > > #define VALID_RESOLVE_FLAGS \ > > > diff --git a/include/uapi/asm-generic/errno.h b/include/uapi/asm-generic/errno.h > > > index 92e7ae493ee3..2216ab9aa32e 100644 > > > --- a/include/uapi/asm-generic/errno.h > > > +++ b/include/uapi/asm-generic/errno.h > > > @@ -122,4 +122,6 @@ > > > > > > #define EHWPOISON 133 /* Memory page has hardware error */ > > > > > > +#define ENOTREG 134 /* Not a regular file */ > > > + > > > #endif > > > diff --git a/include/uapi/asm-generic/fcntl.h b/include/uapi/asm-generic/fcntl.h > > > index 613475285643..3468b352a575 100644 > > > --- a/include/uapi/asm-generic/fcntl.h > > > +++ b/include/uapi/asm-generic/fcntl.h > > > @@ -88,6 +88,10 @@ > > > #define __O_TMPFILE 020000000 > > > #endif > > > > > > +#ifndef O_REGULAR > > > +#define O_REGULAR 040000000 > > > +#endif > > > + > > > /* a horrid kludge trying to make sure that this will fail on old kernels */ > > > #define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) > > > > > > diff --git a/tools/arch/alpha/include/uapi/asm/errno.h b/tools/arch/alpha/include/uapi/asm/errno.h > > > index 6791f6508632..8bbcaa9024f9 100644 > > > --- a/tools/arch/alpha/include/uapi/asm/errno.h > > > +++ b/tools/arch/alpha/include/uapi/asm/errno.h > > > @@ -127,4 +127,6 @@ > > > > > > #define EHWPOISON 139 /* Memory page has hardware error */ > > > > > > +#define ENOTREG 140 /* Not a regular file */ > > > + > > > #endif > > > diff --git a/tools/arch/mips/include/uapi/asm/errno.h b/tools/arch/mips/include/uapi/asm/errno.h > > > index c01ed91b1ef4..293c78777254 100644 > > > --- a/tools/arch/mips/include/uapi/asm/errno.h > > > +++ b/tools/arch/mips/include/uapi/asm/errno.h > > > @@ -126,6 +126,8 @@ > > > > > > #define EHWPOISON 168 /* Memory page has hardware error */ > > > > > > +#define ENOTREG 169 /* Not a regular file */ > > > + > > > #define EDQUOT 1133 /* Quota exceeded */ > > > > > > > > > diff --git a/tools/arch/parisc/include/uapi/asm/errno.h b/tools/arch/parisc/include/uapi/asm/errno.h > > > index 8cbc07c1903e..442917484f99 100644 > > > --- a/tools/arch/parisc/include/uapi/asm/errno.h > > > +++ b/tools/arch/parisc/include/uapi/asm/errno.h > > > @@ -124,4 +124,6 @@ > > > > > > #define EHWPOISON 257 /* Memory page has hardware error */ > > > > > > +#define ENOTREG 258 /* Not a regular file */ > > > + > > > #endif > > > diff --git a/tools/arch/sparc/include/uapi/asm/errno.h b/tools/arch/sparc/include/uapi/asm/errno.h > > > index 4a41e7835fd5..8dce0bfeab74 100644 > > > --- a/tools/arch/sparc/include/uapi/asm/errno.h > > > +++ b/tools/arch/sparc/include/uapi/asm/errno.h > > > @@ -117,4 +117,6 @@ > > > > > > #define EHWPOISON 135 /* Memory page has hardware error */ > > > > > > +#define ENOTREG 136 /* Not a regular file */ > > > + > > > #endif > > > diff --git a/tools/include/uapi/asm-generic/errno.h b/tools/include/uapi/asm-generic/errno.h > > > index 92e7ae493ee3..2216ab9aa32e 100644 > > > --- a/tools/include/uapi/asm-generic/errno.h > > > +++ b/tools/include/uapi/asm-generic/errno.h > > > @@ -122,4 +122,6 @@ > > > > > > #define EHWPOISON 133 /* Memory page has hardware error */ > > > > > > +#define ENOTREG 134 /* Not a regular file */ > > > + > > > #endif > > > > One thing this patch is missing is handling for ->atomic_open(). I > > imagine most of the filesystems that provide that op can't support > > O_REGULAR properly (maybe cifs can? idk). What you probably want to do > > is add in some patches that make all of the atomic_open operations in > > the kernel return -EINVAL if O_REGULAR is set. > > > > Then, once the basic support is in, you or someone else can go back and > > implement support for O_REGULAR where possible. > > Thank you for the feedback. I don't quite understand what I need to > fix. I thought open system calls always create regular files, so > atomic_open probably always creates regular files? Can you please give > me some more details as to where I need to fix this and what the > actual bug here is that is related to atomic_open? I think I had done > some normal testing and when using O_CREAT | O_REGULAR, if the file > doesn't exist, the file gets created and the file that gets created is > a regular file, so it probably makes sense? Or should the behavior be > that if file doesn't exist, -EINVAL is returned and if file exists it > is opened if regular, otherwise -ENOTREG is returned? > atomic_open() is a combination lookup+open for when the dentry isn't present in the dcache. The normal open codepath that you're patching does not get called in this case when ->atomic_open is set for the filesystem. It's mostly used by network filesystems that need to optimize away the lookup since it's wasted round trip, and is often racy anyway. Your patchset doesn't address those filesystems. They will likely end up ignoring O_REGULAR in that case, which is not what you want. What I was suggesting is that, as an interim step, you find all of the atomic_open operations in the kernel (there are maybe a dozen or so), and just make them return -EINVAL if someone sets O_DIRECTORY. Later, you or someone else can then go back and do a proper implementation of O_REGULAR handling on those filesystems, at least on the ones where it's possible. You will probably also need to similarly patch the open() routines for those filesystems too. Otherwise you'll get inconsistent behavior vs. when the dentry is in the cache. One note: I think NFS probably can support O_DIRECTORY, since its OPEN call only works on files. We'll need to change how we handle errors from the server when it's set though. -- Jeff Layton <jlayton@kernel.org> ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v3 1/4] open: new O_REGULAR flag support 2026-01-28 15:51 ` Jeff Layton @ 2026-01-28 16:29 ` Dorjoy Chowdhury 2026-01-29 12:33 ` Christian Brauner 1 sibling, 0 replies; 26+ messages in thread From: Dorjoy Chowdhury @ 2026-01-28 16:29 UTC (permalink / raw) To: Jeff Layton Cc: linux-fsdevel, linux-kernel, viro, brauner, jack, chuck.lever, alex.aring, arnd, adilger On Wed, Jan 28, 2026 at 9:51 PM Jeff Layton <jlayton@kernel.org> wrote: > > On Wed, 2026-01-28 at 21:36 +0600, Dorjoy Chowdhury wrote: > > On Wed, Jan 28, 2026 at 5:52 AM Jeff Layton <jlayton@kernel.org> wrote: > > > > > > On Tue, 2026-01-27 at 23:58 +0600, Dorjoy Chowdhury wrote: > > > > This flag indicates the path should be opened if it's a regular file. > > > > This is useful to write secure programs that want to avoid being tricked > > > > into opening device nodes with special semantics while thinking they > > > > operate on regular files. > > > > > > > > A corresponding error code ENOTREG has been introduced. For example, if > > > > open is called on path /dev/null with O_REGULAR in the flag param, it > > > > will return -ENOTREG. > > > > > > > > When used in combination with O_CREAT, either the regular file is > > > > created, or if the path already exists, it is opened if it's a regular > > > > file. Otherwise, -ENOTREG is returned. > > > > > > > > -EINVAL is returned when O_REGULAR is combined with O_DIRECTORY (not > > > > part of O_TMPFILE) because it doesn't make sense to open a path that > > > > is both a directory and a regular file. > > > > > > > > Signed-off-by: Dorjoy Chowdhury <dorjoychy111@gmail.com> > > > > --- > > > > arch/alpha/include/uapi/asm/errno.h | 2 ++ > > > > arch/alpha/include/uapi/asm/fcntl.h | 1 + > > > > arch/mips/include/uapi/asm/errno.h | 2 ++ > > > > arch/parisc/include/uapi/asm/errno.h | 2 ++ > > > > arch/parisc/include/uapi/asm/fcntl.h | 1 + > > > > arch/sparc/include/uapi/asm/errno.h | 2 ++ > > > > arch/sparc/include/uapi/asm/fcntl.h | 1 + > > > > fs/fcntl.c | 2 +- > > > > fs/namei.c | 6 ++++++ > > > > fs/open.c | 4 +++- > > > > include/linux/fcntl.h | 2 +- > > > > include/uapi/asm-generic/errno.h | 2 ++ > > > > include/uapi/asm-generic/fcntl.h | 4 ++++ > > > > tools/arch/alpha/include/uapi/asm/errno.h | 2 ++ > > > > tools/arch/mips/include/uapi/asm/errno.h | 2 ++ > > > > tools/arch/parisc/include/uapi/asm/errno.h | 2 ++ > > > > tools/arch/sparc/include/uapi/asm/errno.h | 2 ++ > > > > tools/include/uapi/asm-generic/errno.h | 2 ++ > > > > 18 files changed, 38 insertions(+), 3 deletions(-) > > > > > > > > diff --git a/arch/alpha/include/uapi/asm/errno.h b/arch/alpha/include/uapi/asm/errno.h > > > > index 6791f6508632..8bbcaa9024f9 100644 > > > > --- a/arch/alpha/include/uapi/asm/errno.h > > > > +++ b/arch/alpha/include/uapi/asm/errno.h > > > > @@ -127,4 +127,6 @@ > > > > > > > > #define EHWPOISON 139 /* Memory page has hardware error */ > > > > > > > > +#define ENOTREG 140 /* Not a regular file */ > > > > + > > > > #endif > > > > diff --git a/arch/alpha/include/uapi/asm/fcntl.h b/arch/alpha/include/uapi/asm/fcntl.h > > > > index 50bdc8e8a271..4da5a64c23bd 100644 > > > > --- a/arch/alpha/include/uapi/asm/fcntl.h > > > > +++ b/arch/alpha/include/uapi/asm/fcntl.h > > > > @@ -34,6 +34,7 @@ > > > > > > > > #define O_PATH 040000000 > > > > #define __O_TMPFILE 0100000000 > > > > +#define O_REGULAR 0200000000 > > > > > > > > #define F_GETLK 7 > > > > #define F_SETLK 8 > > > > diff --git a/arch/mips/include/uapi/asm/errno.h b/arch/mips/include/uapi/asm/errno.h > > > > index c01ed91b1ef4..293c78777254 100644 > > > > --- a/arch/mips/include/uapi/asm/errno.h > > > > +++ b/arch/mips/include/uapi/asm/errno.h > > > > @@ -126,6 +126,8 @@ > > > > > > > > #define EHWPOISON 168 /* Memory page has hardware error */ > > > > > > > > +#define ENOTREG 169 /* Not a regular file */ > > > > + > > > > #define EDQUOT 1133 /* Quota exceeded */ > > > > > > > > > > > > diff --git a/arch/parisc/include/uapi/asm/errno.h b/arch/parisc/include/uapi/asm/errno.h > > > > index 8cbc07c1903e..442917484f99 100644 > > > > --- a/arch/parisc/include/uapi/asm/errno.h > > > > +++ b/arch/parisc/include/uapi/asm/errno.h > > > > @@ -124,4 +124,6 @@ > > > > > > > > #define EHWPOISON 257 /* Memory page has hardware error */ > > > > > > > > +#define ENOTREG 258 /* Not a regular file */ > > > > + > > > > #endif > > > > diff --git a/arch/parisc/include/uapi/asm/fcntl.h b/arch/parisc/include/uapi/asm/fcntl.h > > > > index 03dee816cb13..0cc3320fe326 100644 > > > > --- a/arch/parisc/include/uapi/asm/fcntl.h > > > > +++ b/arch/parisc/include/uapi/asm/fcntl.h > > > > @@ -19,6 +19,7 @@ > > > > > > > > #define O_PATH 020000000 > > > > #define __O_TMPFILE 040000000 > > > > +#define O_REGULAR 0100000000 > > > > > > > > #define F_GETLK64 8 > > > > #define F_SETLK64 9 > > > > diff --git a/arch/sparc/include/uapi/asm/errno.h b/arch/sparc/include/uapi/asm/errno.h > > > > index 4a41e7835fd5..8dce0bfeab74 100644 > > > > --- a/arch/sparc/include/uapi/asm/errno.h > > > > +++ b/arch/sparc/include/uapi/asm/errno.h > > > > @@ -117,4 +117,6 @@ > > > > > > > > #define EHWPOISON 135 /* Memory page has hardware error */ > > > > > > > > +#define ENOTREG 136 /* Not a regular file */ > > > > + > > > > #endif > > > > diff --git a/arch/sparc/include/uapi/asm/fcntl.h b/arch/sparc/include/uapi/asm/fcntl.h > > > > index 67dae75e5274..a93d18d2c23e 100644 > > > > --- a/arch/sparc/include/uapi/asm/fcntl.h > > > > +++ b/arch/sparc/include/uapi/asm/fcntl.h > > > > @@ -37,6 +37,7 @@ > > > > > > > > #define O_PATH 0x1000000 > > > > #define __O_TMPFILE 0x2000000 > > > > +#define O_REGULAR 0x4000000 > > > > > > > > #define F_GETOWN 5 /* for sockets. */ > > > > #define F_SETOWN 6 /* for sockets. */ > > > > diff --git a/fs/fcntl.c b/fs/fcntl.c > > > > index f93dbca08435..62ab4ad2b6f5 100644 > > > > --- a/fs/fcntl.c > > > > +++ b/fs/fcntl.c > > > > @@ -1169,7 +1169,7 @@ static int __init fcntl_init(void) > > > > * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY > > > > * is defined as O_NONBLOCK on some platforms and not on others. > > > > */ > > > > - BUILD_BUG_ON(20 - 1 /* for O_RDONLY being 0 */ != > > > > + BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ != > > > > HWEIGHT32( > > > > (VALID_OPEN_FLAGS & ~(O_NONBLOCK | O_NDELAY)) | > > > > __FMODE_EXEC)); > > > > diff --git a/fs/namei.c b/fs/namei.c > > > > index b28ecb699f32..f5504ae4b03c 100644 > > > > --- a/fs/namei.c > > > > +++ b/fs/namei.c > > > > @@ -4616,6 +4616,10 @@ static int do_open(struct nameidata *nd, > > > > if (unlikely(error)) > > > > return error; > > > > } > > > > + > > > > + if ((open_flag & O_REGULAR) && !d_is_reg(nd->path.dentry)) > > > > + return -ENOTREG; > > > > + > > > > if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry)) > > > > return -ENOTDIR; > > > > > > > > @@ -4765,6 +4769,8 @@ static int do_o_path(struct nameidata *nd, unsigned flags, struct file *file) > > > > struct path path; > > > > int error = path_lookupat(nd, flags, &path); > > > > if (!error) { > > > > + if ((file->f_flags & O_REGULAR) && !d_is_reg(path.dentry)) > > > > + return -ENOTREG; > > > > audit_inode(nd->name, path.dentry, 0); > > > > error = vfs_open(&path, file); > > > > path_put(&path); > > > > diff --git a/fs/open.c b/fs/open.c > > > > index 74c4c1462b3e..82153e21907e 100644 > > > > --- a/fs/open.c > > > > +++ b/fs/open.c > > > > @@ -1173,7 +1173,7 @@ struct file *kernel_file_open(const struct path *path, int flags, > > > > EXPORT_SYMBOL_GPL(kernel_file_open); > > > > > > > > #define WILL_CREATE(flags) (flags & (O_CREAT | __O_TMPFILE)) > > > > -#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC) > > > > +#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC | O_REGULAR) > > > > > > > > inline struct open_how build_open_how(int flags, umode_t mode) > > > > { > > > > @@ -1250,6 +1250,8 @@ inline int build_open_flags(const struct open_how *how, struct open_flags *op) > > > > return -EINVAL; > > > > if (!(acc_mode & MAY_WRITE)) > > > > return -EINVAL; > > > > + } else if ((flags & O_DIRECTORY) && (flags & O_REGULAR)) { > > > > + return -EINVAL; > > > > } > > > > if (flags & O_PATH) { > > > > /* O_PATH only permits certain other flags to be set. */ > > > > diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h > > > > index a332e79b3207..4fd07b0e0a17 100644 > > > > --- a/include/linux/fcntl.h > > > > +++ b/include/linux/fcntl.h > > > > @@ -10,7 +10,7 @@ > > > > (O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | \ > > > > O_APPEND | O_NDELAY | O_NONBLOCK | __O_SYNC | O_DSYNC | \ > > > > FASYNC | O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | \ > > > > - O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE) > > > > + O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE | O_REGULAR) > > > > > > > > /* List of all valid flags for the how->resolve argument: */ > > > > #define VALID_RESOLVE_FLAGS \ > > > > diff --git a/include/uapi/asm-generic/errno.h b/include/uapi/asm-generic/errno.h > > > > index 92e7ae493ee3..2216ab9aa32e 100644 > > > > --- a/include/uapi/asm-generic/errno.h > > > > +++ b/include/uapi/asm-generic/errno.h > > > > @@ -122,4 +122,6 @@ > > > > > > > > #define EHWPOISON 133 /* Memory page has hardware error */ > > > > > > > > +#define ENOTREG 134 /* Not a regular file */ > > > > + > > > > #endif > > > > diff --git a/include/uapi/asm-generic/fcntl.h b/include/uapi/asm-generic/fcntl.h > > > > index 613475285643..3468b352a575 100644 > > > > --- a/include/uapi/asm-generic/fcntl.h > > > > +++ b/include/uapi/asm-generic/fcntl.h > > > > @@ -88,6 +88,10 @@ > > > > #define __O_TMPFILE 020000000 > > > > #endif > > > > > > > > +#ifndef O_REGULAR > > > > +#define O_REGULAR 040000000 > > > > +#endif > > > > + > > > > /* a horrid kludge trying to make sure that this will fail on old kernels */ > > > > #define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) > > > > > > > > diff --git a/tools/arch/alpha/include/uapi/asm/errno.h b/tools/arch/alpha/include/uapi/asm/errno.h > > > > index 6791f6508632..8bbcaa9024f9 100644 > > > > --- a/tools/arch/alpha/include/uapi/asm/errno.h > > > > +++ b/tools/arch/alpha/include/uapi/asm/errno.h > > > > @@ -127,4 +127,6 @@ > > > > > > > > #define EHWPOISON 139 /* Memory page has hardware error */ > > > > > > > > +#define ENOTREG 140 /* Not a regular file */ > > > > + > > > > #endif > > > > diff --git a/tools/arch/mips/include/uapi/asm/errno.h b/tools/arch/mips/include/uapi/asm/errno.h > > > > index c01ed91b1ef4..293c78777254 100644 > > > > --- a/tools/arch/mips/include/uapi/asm/errno.h > > > > +++ b/tools/arch/mips/include/uapi/asm/errno.h > > > > @@ -126,6 +126,8 @@ > > > > > > > > #define EHWPOISON 168 /* Memory page has hardware error */ > > > > > > > > +#define ENOTREG 169 /* Not a regular file */ > > > > + > > > > #define EDQUOT 1133 /* Quota exceeded */ > > > > > > > > > > > > diff --git a/tools/arch/parisc/include/uapi/asm/errno.h b/tools/arch/parisc/include/uapi/asm/errno.h > > > > index 8cbc07c1903e..442917484f99 100644 > > > > --- a/tools/arch/parisc/include/uapi/asm/errno.h > > > > +++ b/tools/arch/parisc/include/uapi/asm/errno.h > > > > @@ -124,4 +124,6 @@ > > > > > > > > #define EHWPOISON 257 /* Memory page has hardware error */ > > > > > > > > +#define ENOTREG 258 /* Not a regular file */ > > > > + > > > > #endif > > > > diff --git a/tools/arch/sparc/include/uapi/asm/errno.h b/tools/arch/sparc/include/uapi/asm/errno.h > > > > index 4a41e7835fd5..8dce0bfeab74 100644 > > > > --- a/tools/arch/sparc/include/uapi/asm/errno.h > > > > +++ b/tools/arch/sparc/include/uapi/asm/errno.h > > > > @@ -117,4 +117,6 @@ > > > > > > > > #define EHWPOISON 135 /* Memory page has hardware error */ > > > > > > > > +#define ENOTREG 136 /* Not a regular file */ > > > > + > > > > #endif > > > > diff --git a/tools/include/uapi/asm-generic/errno.h b/tools/include/uapi/asm-generic/errno.h > > > > index 92e7ae493ee3..2216ab9aa32e 100644 > > > > --- a/tools/include/uapi/asm-generic/errno.h > > > > +++ b/tools/include/uapi/asm-generic/errno.h > > > > @@ -122,4 +122,6 @@ > > > > > > > > #define EHWPOISON 133 /* Memory page has hardware error */ > > > > > > > > +#define ENOTREG 134 /* Not a regular file */ > > > > + > > > > #endif > > > > > > One thing this patch is missing is handling for ->atomic_open(). I > > > imagine most of the filesystems that provide that op can't support > > > O_REGULAR properly (maybe cifs can? idk). What you probably want to do > > > is add in some patches that make all of the atomic_open operations in > > > the kernel return -EINVAL if O_REGULAR is set. > > > > > > Then, once the basic support is in, you or someone else can go back and > > > implement support for O_REGULAR where possible. > > > > Thank you for the feedback. I don't quite understand what I need to > > fix. I thought open system calls always create regular files, so > > atomic_open probably always creates regular files? Can you please give > > me some more details as to where I need to fix this and what the > > actual bug here is that is related to atomic_open? I think I had done > > some normal testing and when using O_CREAT | O_REGULAR, if the file > > doesn't exist, the file gets created and the file that gets created is > > a regular file, so it probably makes sense? Or should the behavior be > > that if file doesn't exist, -EINVAL is returned and if file exists it > > is opened if regular, otherwise -ENOTREG is returned? > > > > atomic_open() is a combination lookup+open for when the dentry isn't > present in the dcache. The normal open codepath that you're patching > does not get called in this case when ->atomic_open is set for the > filesystem. It's mostly used by network filesystems that need to > optimize away the lookup since it's wasted round trip, and is often > racy anyway. Your patchset doesn't address those filesystems. They will > likely end up ignoring O_REGULAR in that case, which is not what you > want. > > What I was suggesting is that, as an interim step, you find all of the > atomic_open operations in the kernel (there are maybe a dozen or so), > and just make them return -EINVAL if someone sets O_DIRECTORY. Later, Sorry, I am just trying to fully understand this. Do you mean to return -EINVAL from all atomic_open implementations in the kernel if both O_REGULAR and O_DIRECTORY are set (or just only if O_REGULAR is set, we need to return -EINVAL)? I am already returning -EINVAL when both these are set from the build_open_flags function, so that should already handle the cases, right? I think after atomic_open get called, all code paths eventually go through the do_open function where I have this check "if ((open_flag & O_REGULAR) && !d_is_reg(nd->path.dentry)) return -ENOTREG". This is right before if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry)) return -ENOTDIR; which I had initially followed. So should I just return -EINVAL from the atomic_open functions too if both O_REGULAR and O_DIRECTORY are set? Sorry if I am misunderstanding this. Regards, Dorjoy ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v3 1/4] open: new O_REGULAR flag support 2026-01-28 15:51 ` Jeff Layton 2026-01-28 16:29 ` Dorjoy Chowdhury @ 2026-01-29 12:33 ` Christian Brauner 2026-01-29 13:12 ` Jeff Layton 2026-01-29 14:01 ` Jeff Layton 1 sibling, 2 replies; 26+ messages in thread From: Christian Brauner @ 2026-01-29 12:33 UTC (permalink / raw) To: Jeff Layton Cc: Dorjoy Chowdhury, linux-fsdevel, linux-kernel, viro, jack, chuck.lever, alex.aring, arnd, adilger On Wed, Jan 28, 2026 at 10:51:07AM -0500, Jeff Layton wrote: > On Wed, 2026-01-28 at 21:36 +0600, Dorjoy Chowdhury wrote: > > On Wed, Jan 28, 2026 at 5:52 AM Jeff Layton <jlayton@kernel.org> wrote: > > > > > > On Tue, 2026-01-27 at 23:58 +0600, Dorjoy Chowdhury wrote: > > > > This flag indicates the path should be opened if it's a regular file. > > > > This is useful to write secure programs that want to avoid being tricked > > > > into opening device nodes with special semantics while thinking they > > > > operate on regular files. > > > > > > > > A corresponding error code ENOTREG has been introduced. For example, if > > > > open is called on path /dev/null with O_REGULAR in the flag param, it > > > > will return -ENOTREG. > > > > > > > > When used in combination with O_CREAT, either the regular file is > > > > created, or if the path already exists, it is opened if it's a regular > > > > file. Otherwise, -ENOTREG is returned. > > > > > > > > -EINVAL is returned when O_REGULAR is combined with O_DIRECTORY (not > > > > part of O_TMPFILE) because it doesn't make sense to open a path that > > > > is both a directory and a regular file. > > > > > > > > Signed-off-by: Dorjoy Chowdhury <dorjoychy111@gmail.com> > > > > --- > > > > arch/alpha/include/uapi/asm/errno.h | 2 ++ > > > > arch/alpha/include/uapi/asm/fcntl.h | 1 + > > > > arch/mips/include/uapi/asm/errno.h | 2 ++ > > > > arch/parisc/include/uapi/asm/errno.h | 2 ++ > > > > arch/parisc/include/uapi/asm/fcntl.h | 1 + > > > > arch/sparc/include/uapi/asm/errno.h | 2 ++ > > > > arch/sparc/include/uapi/asm/fcntl.h | 1 + > > > > fs/fcntl.c | 2 +- > > > > fs/namei.c | 6 ++++++ > > > > fs/open.c | 4 +++- > > > > include/linux/fcntl.h | 2 +- > > > > include/uapi/asm-generic/errno.h | 2 ++ > > > > include/uapi/asm-generic/fcntl.h | 4 ++++ > > > > tools/arch/alpha/include/uapi/asm/errno.h | 2 ++ > > > > tools/arch/mips/include/uapi/asm/errno.h | 2 ++ > > > > tools/arch/parisc/include/uapi/asm/errno.h | 2 ++ > > > > tools/arch/sparc/include/uapi/asm/errno.h | 2 ++ > > > > tools/include/uapi/asm-generic/errno.h | 2 ++ > > > > 18 files changed, 38 insertions(+), 3 deletions(-) > > > > > > > > diff --git a/arch/alpha/include/uapi/asm/errno.h b/arch/alpha/include/uapi/asm/errno.h > > > > index 6791f6508632..8bbcaa9024f9 100644 > > > > --- a/arch/alpha/include/uapi/asm/errno.h > > > > +++ b/arch/alpha/include/uapi/asm/errno.h > > > > @@ -127,4 +127,6 @@ > > > > > > > > #define EHWPOISON 139 /* Memory page has hardware error */ > > > > > > > > +#define ENOTREG 140 /* Not a regular file */ > > > > + > > > > #endif > > > > diff --git a/arch/alpha/include/uapi/asm/fcntl.h b/arch/alpha/include/uapi/asm/fcntl.h > > > > index 50bdc8e8a271..4da5a64c23bd 100644 > > > > --- a/arch/alpha/include/uapi/asm/fcntl.h > > > > +++ b/arch/alpha/include/uapi/asm/fcntl.h > > > > @@ -34,6 +34,7 @@ > > > > > > > > #define O_PATH 040000000 > > > > #define __O_TMPFILE 0100000000 > > > > +#define O_REGULAR 0200000000 > > > > > > > > #define F_GETLK 7 > > > > #define F_SETLK 8 > > > > diff --git a/arch/mips/include/uapi/asm/errno.h b/arch/mips/include/uapi/asm/errno.h > > > > index c01ed91b1ef4..293c78777254 100644 > > > > --- a/arch/mips/include/uapi/asm/errno.h > > > > +++ b/arch/mips/include/uapi/asm/errno.h > > > > @@ -126,6 +126,8 @@ > > > > > > > > #define EHWPOISON 168 /* Memory page has hardware error */ > > > > > > > > +#define ENOTREG 169 /* Not a regular file */ > > > > + > > > > #define EDQUOT 1133 /* Quota exceeded */ > > > > > > > > > > > > diff --git a/arch/parisc/include/uapi/asm/errno.h b/arch/parisc/include/uapi/asm/errno.h > > > > index 8cbc07c1903e..442917484f99 100644 > > > > --- a/arch/parisc/include/uapi/asm/errno.h > > > > +++ b/arch/parisc/include/uapi/asm/errno.h > > > > @@ -124,4 +124,6 @@ > > > > > > > > #define EHWPOISON 257 /* Memory page has hardware error */ > > > > > > > > +#define ENOTREG 258 /* Not a regular file */ > > > > + > > > > #endif > > > > diff --git a/arch/parisc/include/uapi/asm/fcntl.h b/arch/parisc/include/uapi/asm/fcntl.h > > > > index 03dee816cb13..0cc3320fe326 100644 > > > > --- a/arch/parisc/include/uapi/asm/fcntl.h > > > > +++ b/arch/parisc/include/uapi/asm/fcntl.h > > > > @@ -19,6 +19,7 @@ > > > > > > > > #define O_PATH 020000000 > > > > #define __O_TMPFILE 040000000 > > > > +#define O_REGULAR 0100000000 > > > > > > > > #define F_GETLK64 8 > > > > #define F_SETLK64 9 > > > > diff --git a/arch/sparc/include/uapi/asm/errno.h b/arch/sparc/include/uapi/asm/errno.h > > > > index 4a41e7835fd5..8dce0bfeab74 100644 > > > > --- a/arch/sparc/include/uapi/asm/errno.h > > > > +++ b/arch/sparc/include/uapi/asm/errno.h > > > > @@ -117,4 +117,6 @@ > > > > > > > > #define EHWPOISON 135 /* Memory page has hardware error */ > > > > > > > > +#define ENOTREG 136 /* Not a regular file */ > > > > + > > > > #endif > > > > diff --git a/arch/sparc/include/uapi/asm/fcntl.h b/arch/sparc/include/uapi/asm/fcntl.h > > > > index 67dae75e5274..a93d18d2c23e 100644 > > > > --- a/arch/sparc/include/uapi/asm/fcntl.h > > > > +++ b/arch/sparc/include/uapi/asm/fcntl.h > > > > @@ -37,6 +37,7 @@ > > > > > > > > #define O_PATH 0x1000000 > > > > #define __O_TMPFILE 0x2000000 > > > > +#define O_REGULAR 0x4000000 > > > > > > > > #define F_GETOWN 5 /* for sockets. */ > > > > #define F_SETOWN 6 /* for sockets. */ > > > > diff --git a/fs/fcntl.c b/fs/fcntl.c > > > > index f93dbca08435..62ab4ad2b6f5 100644 > > > > --- a/fs/fcntl.c > > > > +++ b/fs/fcntl.c > > > > @@ -1169,7 +1169,7 @@ static int __init fcntl_init(void) > > > > * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY > > > > * is defined as O_NONBLOCK on some platforms and not on others. > > > > */ > > > > - BUILD_BUG_ON(20 - 1 /* for O_RDONLY being 0 */ != > > > > + BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ != > > > > HWEIGHT32( > > > > (VALID_OPEN_FLAGS & ~(O_NONBLOCK | O_NDELAY)) | > > > > __FMODE_EXEC)); > > > > diff --git a/fs/namei.c b/fs/namei.c > > > > index b28ecb699f32..f5504ae4b03c 100644 > > > > --- a/fs/namei.c > > > > +++ b/fs/namei.c > > > > @@ -4616,6 +4616,10 @@ static int do_open(struct nameidata *nd, > > > > if (unlikely(error)) > > > > return error; > > > > } > > > > + > > > > + if ((open_flag & O_REGULAR) && !d_is_reg(nd->path.dentry)) > > > > + return -ENOTREG; > > > > + > > > > if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry)) > > > > return -ENOTDIR; > > > > > > > > @@ -4765,6 +4769,8 @@ static int do_o_path(struct nameidata *nd, unsigned flags, struct file *file) > > > > struct path path; > > > > int error = path_lookupat(nd, flags, &path); > > > > if (!error) { > > > > + if ((file->f_flags & O_REGULAR) && !d_is_reg(path.dentry)) > > > > + return -ENOTREG; > > > > audit_inode(nd->name, path.dentry, 0); > > > > error = vfs_open(&path, file); > > > > path_put(&path); > > > > diff --git a/fs/open.c b/fs/open.c > > > > index 74c4c1462b3e..82153e21907e 100644 > > > > --- a/fs/open.c > > > > +++ b/fs/open.c > > > > @@ -1173,7 +1173,7 @@ struct file *kernel_file_open(const struct path *path, int flags, > > > > EXPORT_SYMBOL_GPL(kernel_file_open); > > > > > > > > #define WILL_CREATE(flags) (flags & (O_CREAT | __O_TMPFILE)) > > > > -#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC) > > > > +#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC | O_REGULAR) > > > > > > > > inline struct open_how build_open_how(int flags, umode_t mode) > > > > { > > > > @@ -1250,6 +1250,8 @@ inline int build_open_flags(const struct open_how *how, struct open_flags *op) > > > > return -EINVAL; > > > > if (!(acc_mode & MAY_WRITE)) > > > > return -EINVAL; > > > > + } else if ((flags & O_DIRECTORY) && (flags & O_REGULAR)) { > > > > + return -EINVAL; > > > > } > > > > if (flags & O_PATH) { > > > > /* O_PATH only permits certain other flags to be set. */ > > > > diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h > > > > index a332e79b3207..4fd07b0e0a17 100644 > > > > --- a/include/linux/fcntl.h > > > > +++ b/include/linux/fcntl.h > > > > @@ -10,7 +10,7 @@ > > > > (O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | \ > > > > O_APPEND | O_NDELAY | O_NONBLOCK | __O_SYNC | O_DSYNC | \ > > > > FASYNC | O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | \ > > > > - O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE) > > > > + O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE | O_REGULAR) > > > > > > > > /* List of all valid flags for the how->resolve argument: */ > > > > #define VALID_RESOLVE_FLAGS \ > > > > diff --git a/include/uapi/asm-generic/errno.h b/include/uapi/asm-generic/errno.h > > > > index 92e7ae493ee3..2216ab9aa32e 100644 > > > > --- a/include/uapi/asm-generic/errno.h > > > > +++ b/include/uapi/asm-generic/errno.h > > > > @@ -122,4 +122,6 @@ > > > > > > > > #define EHWPOISON 133 /* Memory page has hardware error */ > > > > > > > > +#define ENOTREG 134 /* Not a regular file */ > > > > + > > > > #endif > > > > diff --git a/include/uapi/asm-generic/fcntl.h b/include/uapi/asm-generic/fcntl.h > > > > index 613475285643..3468b352a575 100644 > > > > --- a/include/uapi/asm-generic/fcntl.h > > > > +++ b/include/uapi/asm-generic/fcntl.h > > > > @@ -88,6 +88,10 @@ > > > > #define __O_TMPFILE 020000000 > > > > #endif > > > > > > > > +#ifndef O_REGULAR > > > > +#define O_REGULAR 040000000 > > > > +#endif > > > > + > > > > /* a horrid kludge trying to make sure that this will fail on old kernels */ > > > > #define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) > > > > > > > > diff --git a/tools/arch/alpha/include/uapi/asm/errno.h b/tools/arch/alpha/include/uapi/asm/errno.h > > > > index 6791f6508632..8bbcaa9024f9 100644 > > > > --- a/tools/arch/alpha/include/uapi/asm/errno.h > > > > +++ b/tools/arch/alpha/include/uapi/asm/errno.h > > > > @@ -127,4 +127,6 @@ > > > > > > > > #define EHWPOISON 139 /* Memory page has hardware error */ > > > > > > > > +#define ENOTREG 140 /* Not a regular file */ > > > > + > > > > #endif > > > > diff --git a/tools/arch/mips/include/uapi/asm/errno.h b/tools/arch/mips/include/uapi/asm/errno.h > > > > index c01ed91b1ef4..293c78777254 100644 > > > > --- a/tools/arch/mips/include/uapi/asm/errno.h > > > > +++ b/tools/arch/mips/include/uapi/asm/errno.h > > > > @@ -126,6 +126,8 @@ > > > > > > > > #define EHWPOISON 168 /* Memory page has hardware error */ > > > > > > > > +#define ENOTREG 169 /* Not a regular file */ > > > > + > > > > #define EDQUOT 1133 /* Quota exceeded */ > > > > > > > > > > > > diff --git a/tools/arch/parisc/include/uapi/asm/errno.h b/tools/arch/parisc/include/uapi/asm/errno.h > > > > index 8cbc07c1903e..442917484f99 100644 > > > > --- a/tools/arch/parisc/include/uapi/asm/errno.h > > > > +++ b/tools/arch/parisc/include/uapi/asm/errno.h > > > > @@ -124,4 +124,6 @@ > > > > > > > > #define EHWPOISON 257 /* Memory page has hardware error */ > > > > > > > > +#define ENOTREG 258 /* Not a regular file */ > > > > + > > > > #endif > > > > diff --git a/tools/arch/sparc/include/uapi/asm/errno.h b/tools/arch/sparc/include/uapi/asm/errno.h > > > > index 4a41e7835fd5..8dce0bfeab74 100644 > > > > --- a/tools/arch/sparc/include/uapi/asm/errno.h > > > > +++ b/tools/arch/sparc/include/uapi/asm/errno.h > > > > @@ -117,4 +117,6 @@ > > > > > > > > #define EHWPOISON 135 /* Memory page has hardware error */ > > > > > > > > +#define ENOTREG 136 /* Not a regular file */ > > > > + > > > > #endif > > > > diff --git a/tools/include/uapi/asm-generic/errno.h b/tools/include/uapi/asm-generic/errno.h > > > > index 92e7ae493ee3..2216ab9aa32e 100644 > > > > --- a/tools/include/uapi/asm-generic/errno.h > > > > +++ b/tools/include/uapi/asm-generic/errno.h > > > > @@ -122,4 +122,6 @@ > > > > > > > > #define EHWPOISON 133 /* Memory page has hardware error */ > > > > > > > > +#define ENOTREG 134 /* Not a regular file */ > > > > + > > > > #endif > > > > > > One thing this patch is missing is handling for ->atomic_open(). I > > > imagine most of the filesystems that provide that op can't support > > > O_REGULAR properly (maybe cifs can? idk). What you probably want to do > > > is add in some patches that make all of the atomic_open operations in > > > the kernel return -EINVAL if O_REGULAR is set. > > > > > > Then, once the basic support is in, you or someone else can go back and > > > implement support for O_REGULAR where possible. > > > > Thank you for the feedback. I don't quite understand what I need to > > fix. I thought open system calls always create regular files, so > > atomic_open probably always creates regular files? Can you please give > > me some more details as to where I need to fix this and what the > > actual bug here is that is related to atomic_open? I think I had done > > some normal testing and when using O_CREAT | O_REGULAR, if the file > > doesn't exist, the file gets created and the file that gets created is > > a regular file, so it probably makes sense? Or should the behavior be > > that if file doesn't exist, -EINVAL is returned and if file exists it > > is opened if regular, otherwise -ENOTREG is returned? > > > > atomic_open() is a combination lookup+open for when the dentry isn't > present in the dcache. The normal open codepath that you're patching > does not get called in this case when ->atomic_open is set for the > filesystem. It's mostly used by network filesystems that need to > optimize away the lookup since it's wasted round trip, and is often > racy anyway. Your patchset doesn't address those filesystems. They will > likely end up ignoring O_REGULAR in that case, which is not what you > want. > > What I was suggesting is that, as an interim step, you find all of the > atomic_open operations in the kernel (there are maybe a dozen or so), > and just make them return -EINVAL if someone sets O_DIRECTORY. Later, > you or someone else can then go back and do a proper implementation of > O_REGULAR handling on those filesystems, at least on the ones where > it's possible. You will probably also need to similarly patch the > open() routines for those filesystems too. Otherwise you'll get > inconsistent behavior vs. when the dentry is in the cache. > > One note: I think NFS probably can support O_DIRECTORY, since its OPEN > call only works on files. We'll need to change how we handle errors > from the server when it's set though. So I think you're proposing two separate things or there's a typo: (1) blocking O_DIRECTORY for ->atomic_open:: (2) blocking O_REGULAR for ->atomic_open:: The (1) point implies that O_DIRECTORY currently doesn't work correctly with atomic open for all filesystems. Ever since 43b450632676 ("open: return EINVAL for O_DIRECTORY | O_CREAT") O_DIRECTORY with O_CREAT is blocked. It was accidently allowed and completely broken before that. For O_DIRECTORY without O_CREAT the kernel will pass that down through ->atomic_open:: to the filesystem. The worry that I see is that a network filesystem via ->atomic_open:: somehow already called open on the server side on something that wasn't a directory. At that point the damage such as side-effects from device opening is already done. But I suspect that every filesystem implementing ->atomic_open:: just does finish_no_open() and punts to the VFS for the actual open. And the VFS will catch it in do_open() for it actually opens the file. So the only real worry for O_DIRECTORY I see is that there's an fs that handles it wrong. For (2) it is problematic as there surely are filesystems with ->atomic_open:: that do handle the ~O_CREAT case and return with FMODE_OPENED. So that'll be problematic if the intention is to not trigger an actual open on a non-regular file such as a device/socket/fifo etc. before the VFS had a chance to validate what's going on. So I'm not excited about having this 70% working and punting on ->atomic_open:: waiting for someone to fix this. One option would be to bypass ->atomic_open:: for OPENAT2_REGULAR without O_CREAT and fallback to racy and pricy lookup + open for now. How problematic would that be? If possible I'd prefer this a lot over merging something that works half-way. I guess to make that really work you'd need some protocol extension? ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v3 1/4] open: new O_REGULAR flag support 2026-01-29 12:33 ` Christian Brauner @ 2026-01-29 13:12 ` Jeff Layton 2026-01-29 13:42 ` Jeff Layton 2026-02-18 18:26 ` Dorjoy Chowdhury 2026-01-29 14:01 ` Jeff Layton 1 sibling, 2 replies; 26+ messages in thread From: Jeff Layton @ 2026-01-29 13:12 UTC (permalink / raw) To: Christian Brauner Cc: Dorjoy Chowdhury, linux-fsdevel, linux-kernel, viro, jack, chuck.lever, alex.aring, arnd, adilger, smfrench On Thu, 2026-01-29 at 13:33 +0100, Christian Brauner wrote: > On Wed, Jan 28, 2026 at 10:51:07AM -0500, Jeff Layton wrote: > > On Wed, 2026-01-28 at 21:36 +0600, Dorjoy Chowdhury wrote: > > > On Wed, Jan 28, 2026 at 5:52 AM Jeff Layton <jlayton@kernel.org> wrote: > > > > > > > > On Tue, 2026-01-27 at 23:58 +0600, Dorjoy Chowdhury wrote: > > > > > This flag indicates the path should be opened if it's a regular file. > > > > > This is useful to write secure programs that want to avoid being tricked > > > > > into opening device nodes with special semantics while thinking they > > > > > operate on regular files. > > > > > > > > > > A corresponding error code ENOTREG has been introduced. For example, if > > > > > open is called on path /dev/null with O_REGULAR in the flag param, it > > > > > will return -ENOTREG. > > > > > > > > > > When used in combination with O_CREAT, either the regular file is > > > > > created, or if the path already exists, it is opened if it's a regular > > > > > file. Otherwise, -ENOTREG is returned. > > > > > > > > > > -EINVAL is returned when O_REGULAR is combined with O_DIRECTORY (not > > > > > part of O_TMPFILE) because it doesn't make sense to open a path that > > > > > is both a directory and a regular file. > > > > > > > > > > Signed-off-by: Dorjoy Chowdhury <dorjoychy111@gmail.com> > > > > > --- > > > > > arch/alpha/include/uapi/asm/errno.h | 2 ++ > > > > > arch/alpha/include/uapi/asm/fcntl.h | 1 + > > > > > arch/mips/include/uapi/asm/errno.h | 2 ++ > > > > > arch/parisc/include/uapi/asm/errno.h | 2 ++ > > > > > arch/parisc/include/uapi/asm/fcntl.h | 1 + > > > > > arch/sparc/include/uapi/asm/errno.h | 2 ++ > > > > > arch/sparc/include/uapi/asm/fcntl.h | 1 + > > > > > fs/fcntl.c | 2 +- > > > > > fs/namei.c | 6 ++++++ > > > > > fs/open.c | 4 +++- > > > > > include/linux/fcntl.h | 2 +- > > > > > include/uapi/asm-generic/errno.h | 2 ++ > > > > > include/uapi/asm-generic/fcntl.h | 4 ++++ > > > > > tools/arch/alpha/include/uapi/asm/errno.h | 2 ++ > > > > > tools/arch/mips/include/uapi/asm/errno.h | 2 ++ > > > > > tools/arch/parisc/include/uapi/asm/errno.h | 2 ++ > > > > > tools/arch/sparc/include/uapi/asm/errno.h | 2 ++ > > > > > tools/include/uapi/asm-generic/errno.h | 2 ++ > > > > > 18 files changed, 38 insertions(+), 3 deletions(-) > > > > > > > > > > diff --git a/arch/alpha/include/uapi/asm/errno.h b/arch/alpha/include/uapi/asm/errno.h > > > > > index 6791f6508632..8bbcaa9024f9 100644 > > > > > --- a/arch/alpha/include/uapi/asm/errno.h > > > > > +++ b/arch/alpha/include/uapi/asm/errno.h > > > > > @@ -127,4 +127,6 @@ > > > > > > > > > > #define EHWPOISON 139 /* Memory page has hardware error */ > > > > > > > > > > +#define ENOTREG 140 /* Not a regular file */ > > > > > + > > > > > #endif > > > > > diff --git a/arch/alpha/include/uapi/asm/fcntl.h b/arch/alpha/include/uapi/asm/fcntl.h > > > > > index 50bdc8e8a271..4da5a64c23bd 100644 > > > > > --- a/arch/alpha/include/uapi/asm/fcntl.h > > > > > +++ b/arch/alpha/include/uapi/asm/fcntl.h > > > > > @@ -34,6 +34,7 @@ > > > > > > > > > > #define O_PATH 040000000 > > > > > #define __O_TMPFILE 0100000000 > > > > > +#define O_REGULAR 0200000000 > > > > > > > > > > #define F_GETLK 7 > > > > > #define F_SETLK 8 > > > > > diff --git a/arch/mips/include/uapi/asm/errno.h b/arch/mips/include/uapi/asm/errno.h > > > > > index c01ed91b1ef4..293c78777254 100644 > > > > > --- a/arch/mips/include/uapi/asm/errno.h > > > > > +++ b/arch/mips/include/uapi/asm/errno.h > > > > > @@ -126,6 +126,8 @@ > > > > > > > > > > #define EHWPOISON 168 /* Memory page has hardware error */ > > > > > > > > > > +#define ENOTREG 169 /* Not a regular file */ > > > > > + > > > > > #define EDQUOT 1133 /* Quota exceeded */ > > > > > > > > > > > > > > > diff --git a/arch/parisc/include/uapi/asm/errno.h b/arch/parisc/include/uapi/asm/errno.h > > > > > index 8cbc07c1903e..442917484f99 100644 > > > > > --- a/arch/parisc/include/uapi/asm/errno.h > > > > > +++ b/arch/parisc/include/uapi/asm/errno.h > > > > > @@ -124,4 +124,6 @@ > > > > > > > > > > #define EHWPOISON 257 /* Memory page has hardware error */ > > > > > > > > > > +#define ENOTREG 258 /* Not a regular file */ > > > > > + > > > > > #endif > > > > > diff --git a/arch/parisc/include/uapi/asm/fcntl.h b/arch/parisc/include/uapi/asm/fcntl.h > > > > > index 03dee816cb13..0cc3320fe326 100644 > > > > > --- a/arch/parisc/include/uapi/asm/fcntl.h > > > > > +++ b/arch/parisc/include/uapi/asm/fcntl.h > > > > > @@ -19,6 +19,7 @@ > > > > > > > > > > #define O_PATH 020000000 > > > > > #define __O_TMPFILE 040000000 > > > > > +#define O_REGULAR 0100000000 > > > > > > > > > > #define F_GETLK64 8 > > > > > #define F_SETLK64 9 > > > > > diff --git a/arch/sparc/include/uapi/asm/errno.h b/arch/sparc/include/uapi/asm/errno.h > > > > > index 4a41e7835fd5..8dce0bfeab74 100644 > > > > > --- a/arch/sparc/include/uapi/asm/errno.h > > > > > +++ b/arch/sparc/include/uapi/asm/errno.h > > > > > @@ -117,4 +117,6 @@ > > > > > > > > > > #define EHWPOISON 135 /* Memory page has hardware error */ > > > > > > > > > > +#define ENOTREG 136 /* Not a regular file */ > > > > > + > > > > > #endif > > > > > diff --git a/arch/sparc/include/uapi/asm/fcntl.h b/arch/sparc/include/uapi/asm/fcntl.h > > > > > index 67dae75e5274..a93d18d2c23e 100644 > > > > > --- a/arch/sparc/include/uapi/asm/fcntl.h > > > > > +++ b/arch/sparc/include/uapi/asm/fcntl.h > > > > > @@ -37,6 +37,7 @@ > > > > > > > > > > #define O_PATH 0x1000000 > > > > > #define __O_TMPFILE 0x2000000 > > > > > +#define O_REGULAR 0x4000000 > > > > > > > > > > #define F_GETOWN 5 /* for sockets. */ > > > > > #define F_SETOWN 6 /* for sockets. */ > > > > > diff --git a/fs/fcntl.c b/fs/fcntl.c > > > > > index f93dbca08435..62ab4ad2b6f5 100644 > > > > > --- a/fs/fcntl.c > > > > > +++ b/fs/fcntl.c > > > > > @@ -1169,7 +1169,7 @@ static int __init fcntl_init(void) > > > > > * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY > > > > > * is defined as O_NONBLOCK on some platforms and not on others. > > > > > */ > > > > > - BUILD_BUG_ON(20 - 1 /* for O_RDONLY being 0 */ != > > > > > + BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ != > > > > > HWEIGHT32( > > > > > (VALID_OPEN_FLAGS & ~(O_NONBLOCK | O_NDELAY)) | > > > > > __FMODE_EXEC)); > > > > > diff --git a/fs/namei.c b/fs/namei.c > > > > > index b28ecb699f32..f5504ae4b03c 100644 > > > > > --- a/fs/namei.c > > > > > +++ b/fs/namei.c > > > > > @@ -4616,6 +4616,10 @@ static int do_open(struct nameidata *nd, > > > > > if (unlikely(error)) > > > > > return error; > > > > > } > > > > > + > > > > > + if ((open_flag & O_REGULAR) && !d_is_reg(nd->path.dentry)) > > > > > + return -ENOTREG; > > > > > + > > > > > if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry)) > > > > > return -ENOTDIR; > > > > > > > > > > @@ -4765,6 +4769,8 @@ static int do_o_path(struct nameidata *nd, unsigned flags, struct file *file) > > > > > struct path path; > > > > > int error = path_lookupat(nd, flags, &path); > > > > > if (!error) { > > > > > + if ((file->f_flags & O_REGULAR) && !d_is_reg(path.dentry)) > > > > > + return -ENOTREG; > > > > > audit_inode(nd->name, path.dentry, 0); > > > > > error = vfs_open(&path, file); > > > > > path_put(&path); > > > > > diff --git a/fs/open.c b/fs/open.c > > > > > index 74c4c1462b3e..82153e21907e 100644 > > > > > --- a/fs/open.c > > > > > +++ b/fs/open.c > > > > > @@ -1173,7 +1173,7 @@ struct file *kernel_file_open(const struct path *path, int flags, > > > > > EXPORT_SYMBOL_GPL(kernel_file_open); > > > > > > > > > > #define WILL_CREATE(flags) (flags & (O_CREAT | __O_TMPFILE)) > > > > > -#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC) > > > > > +#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC | O_REGULAR) > > > > > > > > > > inline struct open_how build_open_how(int flags, umode_t mode) > > > > > { > > > > > @@ -1250,6 +1250,8 @@ inline int build_open_flags(const struct open_how *how, struct open_flags *op) > > > > > return -EINVAL; > > > > > if (!(acc_mode & MAY_WRITE)) > > > > > return -EINVAL; > > > > > + } else if ((flags & O_DIRECTORY) && (flags & O_REGULAR)) { > > > > > + return -EINVAL; > > > > > } > > > > > if (flags & O_PATH) { > > > > > /* O_PATH only permits certain other flags to be set. */ > > > > > diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h > > > > > index a332e79b3207..4fd07b0e0a17 100644 > > > > > --- a/include/linux/fcntl.h > > > > > +++ b/include/linux/fcntl.h > > > > > @@ -10,7 +10,7 @@ > > > > > (O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | \ > > > > > O_APPEND | O_NDELAY | O_NONBLOCK | __O_SYNC | O_DSYNC | \ > > > > > FASYNC | O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | \ > > > > > - O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE) > > > > > + O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE | O_REGULAR) > > > > > > > > > > /* List of all valid flags for the how->resolve argument: */ > > > > > #define VALID_RESOLVE_FLAGS \ > > > > > diff --git a/include/uapi/asm-generic/errno.h b/include/uapi/asm-generic/errno.h > > > > > index 92e7ae493ee3..2216ab9aa32e 100644 > > > > > --- a/include/uapi/asm-generic/errno.h > > > > > +++ b/include/uapi/asm-generic/errno.h > > > > > @@ -122,4 +122,6 @@ > > > > > > > > > > #define EHWPOISON 133 /* Memory page has hardware error */ > > > > > > > > > > +#define ENOTREG 134 /* Not a regular file */ > > > > > + > > > > > #endif > > > > > diff --git a/include/uapi/asm-generic/fcntl.h b/include/uapi/asm-generic/fcntl.h > > > > > index 613475285643..3468b352a575 100644 > > > > > --- a/include/uapi/asm-generic/fcntl.h > > > > > +++ b/include/uapi/asm-generic/fcntl.h > > > > > @@ -88,6 +88,10 @@ > > > > > #define __O_TMPFILE 020000000 > > > > > #endif > > > > > > > > > > +#ifndef O_REGULAR > > > > > +#define O_REGULAR 040000000 > > > > > +#endif > > > > > + > > > > > /* a horrid kludge trying to make sure that this will fail on old kernels */ > > > > > #define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) > > > > > > > > > > diff --git a/tools/arch/alpha/include/uapi/asm/errno.h b/tools/arch/alpha/include/uapi/asm/errno.h > > > > > index 6791f6508632..8bbcaa9024f9 100644 > > > > > --- a/tools/arch/alpha/include/uapi/asm/errno.h > > > > > +++ b/tools/arch/alpha/include/uapi/asm/errno.h > > > > > @@ -127,4 +127,6 @@ > > > > > > > > > > #define EHWPOISON 139 /* Memory page has hardware error */ > > > > > > > > > > +#define ENOTREG 140 /* Not a regular file */ > > > > > + > > > > > #endif > > > > > diff --git a/tools/arch/mips/include/uapi/asm/errno.h b/tools/arch/mips/include/uapi/asm/errno.h > > > > > index c01ed91b1ef4..293c78777254 100644 > > > > > --- a/tools/arch/mips/include/uapi/asm/errno.h > > > > > +++ b/tools/arch/mips/include/uapi/asm/errno.h > > > > > @@ -126,6 +126,8 @@ > > > > > > > > > > #define EHWPOISON 168 /* Memory page has hardware error */ > > > > > > > > > > +#define ENOTREG 169 /* Not a regular file */ > > > > > + > > > > > #define EDQUOT 1133 /* Quota exceeded */ > > > > > > > > > > > > > > > diff --git a/tools/arch/parisc/include/uapi/asm/errno.h b/tools/arch/parisc/include/uapi/asm/errno.h > > > > > index 8cbc07c1903e..442917484f99 100644 > > > > > --- a/tools/arch/parisc/include/uapi/asm/errno.h > > > > > +++ b/tools/arch/parisc/include/uapi/asm/errno.h > > > > > @@ -124,4 +124,6 @@ > > > > > > > > > > #define EHWPOISON 257 /* Memory page has hardware error */ > > > > > > > > > > +#define ENOTREG 258 /* Not a regular file */ > > > > > + > > > > > #endif > > > > > diff --git a/tools/arch/sparc/include/uapi/asm/errno.h b/tools/arch/sparc/include/uapi/asm/errno.h > > > > > index 4a41e7835fd5..8dce0bfeab74 100644 > > > > > --- a/tools/arch/sparc/include/uapi/asm/errno.h > > > > > +++ b/tools/arch/sparc/include/uapi/asm/errno.h > > > > > @@ -117,4 +117,6 @@ > > > > > > > > > > #define EHWPOISON 135 /* Memory page has hardware error */ > > > > > > > > > > +#define ENOTREG 136 /* Not a regular file */ > > > > > + > > > > > #endif > > > > > diff --git a/tools/include/uapi/asm-generic/errno.h b/tools/include/uapi/asm-generic/errno.h > > > > > index 92e7ae493ee3..2216ab9aa32e 100644 > > > > > --- a/tools/include/uapi/asm-generic/errno.h > > > > > +++ b/tools/include/uapi/asm-generic/errno.h > > > > > @@ -122,4 +122,6 @@ > > > > > > > > > > #define EHWPOISON 133 /* Memory page has hardware error */ > > > > > > > > > > +#define ENOTREG 134 /* Not a regular file */ > > > > > + > > > > > #endif > > > > > > > > One thing this patch is missing is handling for ->atomic_open(). I > > > > imagine most of the filesystems that provide that op can't support > > > > O_REGULAR properly (maybe cifs can? idk). What you probably want to do > > > > is add in some patches that make all of the atomic_open operations in > > > > the kernel return -EINVAL if O_REGULAR is set. > > > > > > > > Then, once the basic support is in, you or someone else can go back and > > > > implement support for O_REGULAR where possible. > > > > > > Thank you for the feedback. I don't quite understand what I need to > > > fix. I thought open system calls always create regular files, so > > > atomic_open probably always creates regular files? Can you please give > > > me some more details as to where I need to fix this and what the > > > actual bug here is that is related to atomic_open? I think I had done > > > some normal testing and when using O_CREAT | O_REGULAR, if the file > > > doesn't exist, the file gets created and the file that gets created is > > > a regular file, so it probably makes sense? Or should the behavior be > > > that if file doesn't exist, -EINVAL is returned and if file exists it > > > is opened if regular, otherwise -ENOTREG is returned? > > > > > > > atomic_open() is a combination lookup+open for when the dentry isn't > > present in the dcache. The normal open codepath that you're patching > > does not get called in this case when ->atomic_open is set for the > > filesystem. It's mostly used by network filesystems that need to > > optimize away the lookup since it's wasted round trip, and is often > > racy anyway. Your patchset doesn't address those filesystems. They will > > likely end up ignoring O_REGULAR in that case, which is not what you > > want. > > > > What I was suggesting is that, as an interim step, you find all of the > > atomic_open operations in the kernel (there are maybe a dozen or so), > > and just make them return -EINVAL if someone sets O_DIRECTORY. Later, > > you or someone else can then go back and do a proper implementation of > > O_REGULAR handling on those filesystems, at least on the ones where > > it's possible. You will probably also need to similarly patch the > > open() routines for those filesystems too. Otherwise you'll get > > inconsistent behavior vs. when the dentry is in the cache. > > > > One note: I think NFS probably can support O_DIRECTORY, since its OPEN > > call only works on files. We'll need to change how we handle errors > > from the server when it's set though. > > So I think you're proposing two separate things or there's a typo: > > (1) blocking O_DIRECTORY for ->atomic_open:: > (2) blocking O_REGULAR for ->atomic_open:: > > The (1) point implies that O_DIRECTORY currently doesn't work correctly > with atomic open for all filesystems. > > Ever since 43b450632676 ("open: return EINVAL for O_DIRECTORY | > O_CREAT") O_DIRECTORY with O_CREAT is blocked. It was accidently allowed > and completely broken before that. > > For O_DIRECTORY without O_CREAT the kernel will pass that down through > ->atomic_open:: to the filesystem. > > The worry that I see is that a network filesystem via ->atomic_open:: > somehow already called open on the server side on something that wasn't > a directory. At that point the damage such as side-effects from device > opening is already done. > > Exactly. I guess you could send an immediate close, but that's not without side effects. > > But I suspect that every filesystem implementing ->atomic_open:: just > does finish_no_open() and punts to the VFS for the actual open. And the > VFS will catch it in do_open() for it actually opens the file. So the > only real worry for O_DIRECTORY I see is that there's an fs that handles > it wrong. > > For (2) it is problematic as there surely are filesystems with > ->atomic_open:: that do handle the ~O_CREAT case and return with > FMODE_OPENED. So that'll be problematic if the intention is to not > trigger an actual open on a non-regular file such as a > device/socket/fifo etc. before the VFS had a chance to validate what's > going on. > > So I'm not excited about having this 70% working and punting on > ->atomic_open:: waiting for someone to fix this. One option would be to > bypass ->atomic_open:: for OPENAT2_REGULAR without O_CREAT and fallback > to racy and pricy lookup + open for now. How problematic would that be? > If possible I'd prefer this a lot over merging something that works > half-way. > > I guess to make that really work you'd need some protocol extension? For NFS, I think we're OK. The OPEN call on NFSv4 only works for regular files, so it should be able to handle O_REGULAR. We just need to rejigger the error handling when it's set (just return an error instead of doing the open of a directory or whatever it is). The others (at a quick glance): cifs: I don't see a way to specify an O_REGULAR equivalent to the SMB2_CREATE call and it looks like it can create directories. Maybe SteveF (cc'ed) knows if this is possible? ceph: I think CEPH_MDS_OP_OPEN might only work for files, in which case O_REGULAR can probably be supported similarly to NFS. fuse: probably ok? Does finish_no_open() in most cases. May depend on the userland driver though. gfs2: is ok, it just does finish_no_open() in most cases anyway vboxsf: does finish_no_open on non-creates, so you could probably just punt to that if O_REGULAR is set. So, it's probably possible to do this across the board. I'm not sure about cifs though. -- Jeff Layton <jlayton@kernel.org> ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v3 1/4] open: new O_REGULAR flag support 2026-01-29 13:12 ` Jeff Layton @ 2026-01-29 13:42 ` Jeff Layton 2026-02-18 18:26 ` Dorjoy Chowdhury 1 sibling, 0 replies; 26+ messages in thread From: Jeff Layton @ 2026-01-29 13:42 UTC (permalink / raw) To: Christian Brauner Cc: Dorjoy Chowdhury, linux-fsdevel, linux-kernel, viro, jack, chuck.lever, alex.aring, arnd, adilger, smfrench On Thu, 2026-01-29 at 08:12 -0500, Jeff Layton wrote: > On Thu, 2026-01-29 at 13:33 +0100, Christian Brauner wrote: > > On Wed, Jan 28, 2026 at 10:51:07AM -0500, Jeff Layton wrote: > > > On Wed, 2026-01-28 at 21:36 +0600, Dorjoy Chowdhury wrote: > > > > On Wed, Jan 28, 2026 at 5:52 AM Jeff Layton <jlayton@kernel.org> wrote: > > > > > > > > > > On Tue, 2026-01-27 at 23:58 +0600, Dorjoy Chowdhury wrote: > > > > > > This flag indicates the path should be opened if it's a regular file. > > > > > > This is useful to write secure programs that want to avoid being tricked > > > > > > into opening device nodes with special semantics while thinking they > > > > > > operate on regular files. > > > > > > > > > > > > A corresponding error code ENOTREG has been introduced. For example, if > > > > > > open is called on path /dev/null with O_REGULAR in the flag param, it > > > > > > will return -ENOTREG. > > > > > > > > > > > > When used in combination with O_CREAT, either the regular file is > > > > > > created, or if the path already exists, it is opened if it's a regular > > > > > > file. Otherwise, -ENOTREG is returned. > > > > > > > > > > > > -EINVAL is returned when O_REGULAR is combined with O_DIRECTORY (not > > > > > > part of O_TMPFILE) because it doesn't make sense to open a path that > > > > > > is both a directory and a regular file. > > > > > > > > > > > > Signed-off-by: Dorjoy Chowdhury <dorjoychy111@gmail.com> > > > > > > --- > > > > > > arch/alpha/include/uapi/asm/errno.h | 2 ++ > > > > > > arch/alpha/include/uapi/asm/fcntl.h | 1 + > > > > > > arch/mips/include/uapi/asm/errno.h | 2 ++ > > > > > > arch/parisc/include/uapi/asm/errno.h | 2 ++ > > > > > > arch/parisc/include/uapi/asm/fcntl.h | 1 + > > > > > > arch/sparc/include/uapi/asm/errno.h | 2 ++ > > > > > > arch/sparc/include/uapi/asm/fcntl.h | 1 + > > > > > > fs/fcntl.c | 2 +- > > > > > > fs/namei.c | 6 ++++++ > > > > > > fs/open.c | 4 +++- > > > > > > include/linux/fcntl.h | 2 +- > > > > > > include/uapi/asm-generic/errno.h | 2 ++ > > > > > > include/uapi/asm-generic/fcntl.h | 4 ++++ > > > > > > tools/arch/alpha/include/uapi/asm/errno.h | 2 ++ > > > > > > tools/arch/mips/include/uapi/asm/errno.h | 2 ++ > > > > > > tools/arch/parisc/include/uapi/asm/errno.h | 2 ++ > > > > > > tools/arch/sparc/include/uapi/asm/errno.h | 2 ++ > > > > > > tools/include/uapi/asm-generic/errno.h | 2 ++ > > > > > > 18 files changed, 38 insertions(+), 3 deletions(-) > > > > > > > > > > > > diff --git a/arch/alpha/include/uapi/asm/errno.h b/arch/alpha/include/uapi/asm/errno.h > > > > > > index 6791f6508632..8bbcaa9024f9 100644 > > > > > > --- a/arch/alpha/include/uapi/asm/errno.h > > > > > > +++ b/arch/alpha/include/uapi/asm/errno.h > > > > > > @@ -127,4 +127,6 @@ > > > > > > > > > > > > #define EHWPOISON 139 /* Memory page has hardware error */ > > > > > > > > > > > > +#define ENOTREG 140 /* Not a regular file */ > > > > > > + > > > > > > #endif > > > > > > diff --git a/arch/alpha/include/uapi/asm/fcntl.h b/arch/alpha/include/uapi/asm/fcntl.h > > > > > > index 50bdc8e8a271..4da5a64c23bd 100644 > > > > > > --- a/arch/alpha/include/uapi/asm/fcntl.h > > > > > > +++ b/arch/alpha/include/uapi/asm/fcntl.h > > > > > > @@ -34,6 +34,7 @@ > > > > > > > > > > > > #define O_PATH 040000000 > > > > > > #define __O_TMPFILE 0100000000 > > > > > > +#define O_REGULAR 0200000000 > > > > > > > > > > > > #define F_GETLK 7 > > > > > > #define F_SETLK 8 > > > > > > diff --git a/arch/mips/include/uapi/asm/errno.h b/arch/mips/include/uapi/asm/errno.h > > > > > > index c01ed91b1ef4..293c78777254 100644 > > > > > > --- a/arch/mips/include/uapi/asm/errno.h > > > > > > +++ b/arch/mips/include/uapi/asm/errno.h > > > > > > @@ -126,6 +126,8 @@ > > > > > > > > > > > > #define EHWPOISON 168 /* Memory page has hardware error */ > > > > > > > > > > > > +#define ENOTREG 169 /* Not a regular file */ > > > > > > + > > > > > > #define EDQUOT 1133 /* Quota exceeded */ > > > > > > > > > > > > > > > > > > diff --git a/arch/parisc/include/uapi/asm/errno.h b/arch/parisc/include/uapi/asm/errno.h > > > > > > index 8cbc07c1903e..442917484f99 100644 > > > > > > --- a/arch/parisc/include/uapi/asm/errno.h > > > > > > +++ b/arch/parisc/include/uapi/asm/errno.h > > > > > > @@ -124,4 +124,6 @@ > > > > > > > > > > > > #define EHWPOISON 257 /* Memory page has hardware error */ > > > > > > > > > > > > +#define ENOTREG 258 /* Not a regular file */ > > > > > > + > > > > > > #endif > > > > > > diff --git a/arch/parisc/include/uapi/asm/fcntl.h b/arch/parisc/include/uapi/asm/fcntl.h > > > > > > index 03dee816cb13..0cc3320fe326 100644 > > > > > > --- a/arch/parisc/include/uapi/asm/fcntl.h > > > > > > +++ b/arch/parisc/include/uapi/asm/fcntl.h > > > > > > @@ -19,6 +19,7 @@ > > > > > > > > > > > > #define O_PATH 020000000 > > > > > > #define __O_TMPFILE 040000000 > > > > > > +#define O_REGULAR 0100000000 > > > > > > > > > > > > #define F_GETLK64 8 > > > > > > #define F_SETLK64 9 > > > > > > diff --git a/arch/sparc/include/uapi/asm/errno.h b/arch/sparc/include/uapi/asm/errno.h > > > > > > index 4a41e7835fd5..8dce0bfeab74 100644 > > > > > > --- a/arch/sparc/include/uapi/asm/errno.h > > > > > > +++ b/arch/sparc/include/uapi/asm/errno.h > > > > > > @@ -117,4 +117,6 @@ > > > > > > > > > > > > #define EHWPOISON 135 /* Memory page has hardware error */ > > > > > > > > > > > > +#define ENOTREG 136 /* Not a regular file */ > > > > > > + > > > > > > #endif > > > > > > diff --git a/arch/sparc/include/uapi/asm/fcntl.h b/arch/sparc/include/uapi/asm/fcntl.h > > > > > > index 67dae75e5274..a93d18d2c23e 100644 > > > > > > --- a/arch/sparc/include/uapi/asm/fcntl.h > > > > > > +++ b/arch/sparc/include/uapi/asm/fcntl.h > > > > > > @@ -37,6 +37,7 @@ > > > > > > > > > > > > #define O_PATH 0x1000000 > > > > > > #define __O_TMPFILE 0x2000000 > > > > > > +#define O_REGULAR 0x4000000 > > > > > > > > > > > > #define F_GETOWN 5 /* for sockets. */ > > > > > > #define F_SETOWN 6 /* for sockets. */ > > > > > > diff --git a/fs/fcntl.c b/fs/fcntl.c > > > > > > index f93dbca08435..62ab4ad2b6f5 100644 > > > > > > --- a/fs/fcntl.c > > > > > > +++ b/fs/fcntl.c > > > > > > @@ -1169,7 +1169,7 @@ static int __init fcntl_init(void) > > > > > > * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY > > > > > > * is defined as O_NONBLOCK on some platforms and not on others. > > > > > > */ > > > > > > - BUILD_BUG_ON(20 - 1 /* for O_RDONLY being 0 */ != > > > > > > + BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ != > > > > > > HWEIGHT32( > > > > > > (VALID_OPEN_FLAGS & ~(O_NONBLOCK | O_NDELAY)) | > > > > > > __FMODE_EXEC)); > > > > > > diff --git a/fs/namei.c b/fs/namei.c > > > > > > index b28ecb699f32..f5504ae4b03c 100644 > > > > > > --- a/fs/namei.c > > > > > > +++ b/fs/namei.c > > > > > > @@ -4616,6 +4616,10 @@ static int do_open(struct nameidata *nd, > > > > > > if (unlikely(error)) > > > > > > return error; > > > > > > } > > > > > > + > > > > > > + if ((open_flag & O_REGULAR) && !d_is_reg(nd->path.dentry)) > > > > > > + return -ENOTREG; > > > > > > + > > > > > > if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry)) > > > > > > return -ENOTDIR; > > > > > > > > > > > > @@ -4765,6 +4769,8 @@ static int do_o_path(struct nameidata *nd, unsigned flags, struct file *file) > > > > > > struct path path; > > > > > > int error = path_lookupat(nd, flags, &path); > > > > > > if (!error) { > > > > > > + if ((file->f_flags & O_REGULAR) && !d_is_reg(path.dentry)) > > > > > > + return -ENOTREG; > > > > > > audit_inode(nd->name, path.dentry, 0); > > > > > > error = vfs_open(&path, file); > > > > > > path_put(&path); > > > > > > diff --git a/fs/open.c b/fs/open.c > > > > > > index 74c4c1462b3e..82153e21907e 100644 > > > > > > --- a/fs/open.c > > > > > > +++ b/fs/open.c > > > > > > @@ -1173,7 +1173,7 @@ struct file *kernel_file_open(const struct path *path, int flags, > > > > > > EXPORT_SYMBOL_GPL(kernel_file_open); > > > > > > > > > > > > #define WILL_CREATE(flags) (flags & (O_CREAT | __O_TMPFILE)) > > > > > > -#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC) > > > > > > +#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC | O_REGULAR) > > > > > > > > > > > > inline struct open_how build_open_how(int flags, umode_t mode) > > > > > > { > > > > > > @@ -1250,6 +1250,8 @@ inline int build_open_flags(const struct open_how *how, struct open_flags *op) > > > > > > return -EINVAL; > > > > > > if (!(acc_mode & MAY_WRITE)) > > > > > > return -EINVAL; > > > > > > + } else if ((flags & O_DIRECTORY) && (flags & O_REGULAR)) { > > > > > > + return -EINVAL; > > > > > > } > > > > > > if (flags & O_PATH) { > > > > > > /* O_PATH only permits certain other flags to be set. */ > > > > > > diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h > > > > > > index a332e79b3207..4fd07b0e0a17 100644 > > > > > > --- a/include/linux/fcntl.h > > > > > > +++ b/include/linux/fcntl.h > > > > > > @@ -10,7 +10,7 @@ > > > > > > (O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | \ > > > > > > O_APPEND | O_NDELAY | O_NONBLOCK | __O_SYNC | O_DSYNC | \ > > > > > > FASYNC | O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | \ > > > > > > - O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE) > > > > > > + O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE | O_REGULAR) > > > > > > > > > > > > /* List of all valid flags for the how->resolve argument: */ > > > > > > #define VALID_RESOLVE_FLAGS \ > > > > > > diff --git a/include/uapi/asm-generic/errno.h b/include/uapi/asm-generic/errno.h > > > > > > index 92e7ae493ee3..2216ab9aa32e 100644 > > > > > > --- a/include/uapi/asm-generic/errno.h > > > > > > +++ b/include/uapi/asm-generic/errno.h > > > > > > @@ -122,4 +122,6 @@ > > > > > > > > > > > > #define EHWPOISON 133 /* Memory page has hardware error */ > > > > > > > > > > > > +#define ENOTREG 134 /* Not a regular file */ > > > > > > + > > > > > > #endif > > > > > > diff --git a/include/uapi/asm-generic/fcntl.h b/include/uapi/asm-generic/fcntl.h > > > > > > index 613475285643..3468b352a575 100644 > > > > > > --- a/include/uapi/asm-generic/fcntl.h > > > > > > +++ b/include/uapi/asm-generic/fcntl.h > > > > > > @@ -88,6 +88,10 @@ > > > > > > #define __O_TMPFILE 020000000 > > > > > > #endif > > > > > > > > > > > > +#ifndef O_REGULAR > > > > > > +#define O_REGULAR 040000000 > > > > > > +#endif > > > > > > + > > > > > > /* a horrid kludge trying to make sure that this will fail on old kernels */ > > > > > > #define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) > > > > > > > > > > > > diff --git a/tools/arch/alpha/include/uapi/asm/errno.h b/tools/arch/alpha/include/uapi/asm/errno.h > > > > > > index 6791f6508632..8bbcaa9024f9 100644 > > > > > > --- a/tools/arch/alpha/include/uapi/asm/errno.h > > > > > > +++ b/tools/arch/alpha/include/uapi/asm/errno.h > > > > > > @@ -127,4 +127,6 @@ > > > > > > > > > > > > #define EHWPOISON 139 /* Memory page has hardware error */ > > > > > > > > > > > > +#define ENOTREG 140 /* Not a regular file */ > > > > > > + > > > > > > #endif > > > > > > diff --git a/tools/arch/mips/include/uapi/asm/errno.h b/tools/arch/mips/include/uapi/asm/errno.h > > > > > > index c01ed91b1ef4..293c78777254 100644 > > > > > > --- a/tools/arch/mips/include/uapi/asm/errno.h > > > > > > +++ b/tools/arch/mips/include/uapi/asm/errno.h > > > > > > @@ -126,6 +126,8 @@ > > > > > > > > > > > > #define EHWPOISON 168 /* Memory page has hardware error */ > > > > > > > > > > > > +#define ENOTREG 169 /* Not a regular file */ > > > > > > + > > > > > > #define EDQUOT 1133 /* Quota exceeded */ > > > > > > > > > > > > > > > > > > diff --git a/tools/arch/parisc/include/uapi/asm/errno.h b/tools/arch/parisc/include/uapi/asm/errno.h > > > > > > index 8cbc07c1903e..442917484f99 100644 > > > > > > --- a/tools/arch/parisc/include/uapi/asm/errno.h > > > > > > +++ b/tools/arch/parisc/include/uapi/asm/errno.h > > > > > > @@ -124,4 +124,6 @@ > > > > > > > > > > > > #define EHWPOISON 257 /* Memory page has hardware error */ > > > > > > > > > > > > +#define ENOTREG 258 /* Not a regular file */ > > > > > > + > > > > > > #endif > > > > > > diff --git a/tools/arch/sparc/include/uapi/asm/errno.h b/tools/arch/sparc/include/uapi/asm/errno.h > > > > > > index 4a41e7835fd5..8dce0bfeab74 100644 > > > > > > --- a/tools/arch/sparc/include/uapi/asm/errno.h > > > > > > +++ b/tools/arch/sparc/include/uapi/asm/errno.h > > > > > > @@ -117,4 +117,6 @@ > > > > > > > > > > > > #define EHWPOISON 135 /* Memory page has hardware error */ > > > > > > > > > > > > +#define ENOTREG 136 /* Not a regular file */ > > > > > > + > > > > > > #endif > > > > > > diff --git a/tools/include/uapi/asm-generic/errno.h b/tools/include/uapi/asm-generic/errno.h > > > > > > index 92e7ae493ee3..2216ab9aa32e 100644 > > > > > > --- a/tools/include/uapi/asm-generic/errno.h > > > > > > +++ b/tools/include/uapi/asm-generic/errno.h > > > > > > @@ -122,4 +122,6 @@ > > > > > > > > > > > > #define EHWPOISON 133 /* Memory page has hardware error */ > > > > > > > > > > > > +#define ENOTREG 134 /* Not a regular file */ > > > > > > + > > > > > > #endif > > > > > > > > > > One thing this patch is missing is handling for ->atomic_open(). I > > > > > imagine most of the filesystems that provide that op can't support > > > > > O_REGULAR properly (maybe cifs can? idk). What you probably want to do > > > > > is add in some patches that make all of the atomic_open operations in > > > > > the kernel return -EINVAL if O_REGULAR is set. > > > > > > > > > > Then, once the basic support is in, you or someone else can go back and > > > > > implement support for O_REGULAR where possible. > > > > > > > > Thank you for the feedback. I don't quite understand what I need to > > > > fix. I thought open system calls always create regular files, so > > > > atomic_open probably always creates regular files? Can you please give > > > > me some more details as to where I need to fix this and what the > > > > actual bug here is that is related to atomic_open? I think I had done > > > > some normal testing and when using O_CREAT | O_REGULAR, if the file > > > > doesn't exist, the file gets created and the file that gets created is > > > > a regular file, so it probably makes sense? Or should the behavior be > > > > that if file doesn't exist, -EINVAL is returned and if file exists it > > > > is opened if regular, otherwise -ENOTREG is returned? > > > > > > > > > > atomic_open() is a combination lookup+open for when the dentry isn't > > > present in the dcache. The normal open codepath that you're patching > > > does not get called in this case when ->atomic_open is set for the > > > filesystem. It's mostly used by network filesystems that need to > > > optimize away the lookup since it's wasted round trip, and is often > > > racy anyway. Your patchset doesn't address those filesystems. They will > > > likely end up ignoring O_REGULAR in that case, which is not what you > > > want. > > > > > > What I was suggesting is that, as an interim step, you find all of the > > > atomic_open operations in the kernel (there are maybe a dozen or so), > > > and just make them return -EINVAL if someone sets O_DIRECTORY. Later, > > > you or someone else can then go back and do a proper implementation of > > > O_REGULAR handling on those filesystems, at least on the ones where > > > it's possible. You will probably also need to similarly patch the > > > open() routines for those filesystems too. Otherwise you'll get > > > inconsistent behavior vs. when the dentry is in the cache. > > > > > > One note: I think NFS probably can support O_DIRECTORY, since its OPEN > > > call only works on files. We'll need to change how we handle errors > > > from the server when it's set though. > > > > So I think you're proposing two separate things or there's a typo: > > > > (1) blocking O_DIRECTORY for ->atomic_open:: > > (2) blocking O_REGULAR for ->atomic_open:: > > > > The (1) point implies that O_DIRECTORY currently doesn't work correctly > > with atomic open for all filesystems. > > > > Ever since 43b450632676 ("open: return EINVAL for O_DIRECTORY | > > O_CREAT") O_DIRECTORY with O_CREAT is blocked. It was accidently allowed > > and completely broken before that. > > > > For O_DIRECTORY without O_CREAT the kernel will pass that down through > > ->atomic_open:: to the filesystem. > > > > The worry that I see is that a network filesystem via ->atomic_open:: > > somehow already called open on the server side on something that wasn't > > a directory. At that point the damage such as side-effects from device > > opening is already done. > > > > > > Exactly. I guess you could send an immediate close, but that's not > without side effects. > > > > > But I suspect that every filesystem implementing ->atomic_open:: just > > does finish_no_open() and punts to the VFS for the actual open. And the > > VFS will catch it in do_open() for it actually opens the file. So the > > only real worry for O_DIRECTORY I see is that there's an fs that handles > > it wrong. > > > > For (2) it is problematic as there surely are filesystems with > > ->atomic_open:: that do handle the ~O_CREAT case and return with > > FMODE_OPENED. So that'll be problematic if the intention is to not > > trigger an actual open on a non-regular file such as a > > device/socket/fifo etc. before the VFS had a chance to validate what's > > going on. > > > > So I'm not excited about having this 70% working and punting on > > ->atomic_open:: waiting for someone to fix this. One option would be to > > bypass ->atomic_open:: for OPENAT2_REGULAR without O_CREAT and fallback > > to racy and pricy lookup + open for now. How problematic would that be? > > If possible I'd prefer this a lot over merging something that works > > half-way. > > > > I guess to make that really work you'd need some protocol extension? > > For NFS, I think we're OK. The OPEN call on NFSv4 only works for > regular files, so it should be able to handle O_REGULAR. We just need > to rejigger the error handling when it's set (just return an error > instead of doing the open of a directory or whatever it is). > > The others (at a quick glance): > > cifs: I don't see a way to specify an O_REGULAR equivalent to the > SMB2_CREATE call and it looks like it can create directories. Maybe > SteveF (cc'ed) knows if this is possible? > SMB2 does have this flag: FILE_NON_DIRECTORY_FILE 0x00000040 If the name of the file being created or opened matches with an existing directory file, the server MUST fail the request with STATUS_FILE_IS_A_DIRECTORY. This flag MUST NOT be used with FILE_DIRECTORY_FILE or the server MUST fail the request with STATUS_INVALID_PARAMETER. SMB2 can also present named pipes and printer files. Not sure if there is a way to exclude those with this. > ceph: I think CEPH_MDS_OP_OPEN might only work for files, in which case > O_REGULAR can probably be supported similarly to NFS. > Actually I'm wrong here. That op can open a directory. We'll need someone to look at the MDS code and tell us whether this can be done in a non-racy way. > fuse: probably ok? Does finish_no_open() in most cases. May depend on > the userland driver though. > > gfs2: is ok, it just does finish_no_open() in most cases anyway > > vboxsf: does finish_no_open on non-creates, so you could probably just > punt to that if O_REGULAR is set. > > So, it's probably possible to do this across the board. I'm not sure > about cifs though. -- Jeff Layton <jlayton@kernel.org> ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v3 1/4] open: new O_REGULAR flag support 2026-01-29 13:12 ` Jeff Layton 2026-01-29 13:42 ` Jeff Layton @ 2026-02-18 18:26 ` Dorjoy Chowdhury 2026-02-18 19:01 ` Jeff Layton 1 sibling, 1 reply; 26+ messages in thread From: Dorjoy Chowdhury @ 2026-02-18 18:26 UTC (permalink / raw) To: Jeff Layton Cc: Christian Brauner, linux-fsdevel, linux-kernel, viro, jack, chuck.lever, alex.aring, arnd, adilger, smfrench On Thu, Jan 29, 2026 at 7:12 PM Jeff Layton <jlayton@kernel.org> wrote: > > On Thu, 2026-01-29 at 13:33 +0100, Christian Brauner wrote: > > On Wed, Jan 28, 2026 at 10:51:07AM -0500, Jeff Layton wrote: > > > On Wed, 2026-01-28 at 21:36 +0600, Dorjoy Chowdhury wrote: > > > > On Wed, Jan 28, 2026 at 5:52 AM Jeff Layton <jlayton@kernel.org> wrote: > > > > > > > > > > On Tue, 2026-01-27 at 23:58 +0600, Dorjoy Chowdhury wrote: > > > > > > This flag indicates the path should be opened if it's a regular file. > > > > > > This is useful to write secure programs that want to avoid being tricked > > > > > > into opening device nodes with special semantics while thinking they > > > > > > operate on regular files. > > > > > > > > > > > > A corresponding error code ENOTREG has been introduced. For example, if > > > > > > open is called on path /dev/null with O_REGULAR in the flag param, it > > > > > > will return -ENOTREG. > > > > > > > > > > > > When used in combination with O_CREAT, either the regular file is > > > > > > created, or if the path already exists, it is opened if it's a regular > > > > > > file. Otherwise, -ENOTREG is returned. > > > > > > > > > > > > -EINVAL is returned when O_REGULAR is combined with O_DIRECTORY (not > > > > > > part of O_TMPFILE) because it doesn't make sense to open a path that > > > > > > is both a directory and a regular file. > > > > > > > > > > > > Signed-off-by: Dorjoy Chowdhury <dorjoychy111@gmail.com> > > > > > > --- > > > > > > arch/alpha/include/uapi/asm/errno.h | 2 ++ > > > > > > arch/alpha/include/uapi/asm/fcntl.h | 1 + > > > > > > arch/mips/include/uapi/asm/errno.h | 2 ++ > > > > > > arch/parisc/include/uapi/asm/errno.h | 2 ++ > > > > > > arch/parisc/include/uapi/asm/fcntl.h | 1 + > > > > > > arch/sparc/include/uapi/asm/errno.h | 2 ++ > > > > > > arch/sparc/include/uapi/asm/fcntl.h | 1 + > > > > > > fs/fcntl.c | 2 +- > > > > > > fs/namei.c | 6 ++++++ > > > > > > fs/open.c | 4 +++- > > > > > > include/linux/fcntl.h | 2 +- > > > > > > include/uapi/asm-generic/errno.h | 2 ++ > > > > > > include/uapi/asm-generic/fcntl.h | 4 ++++ > > > > > > tools/arch/alpha/include/uapi/asm/errno.h | 2 ++ > > > > > > tools/arch/mips/include/uapi/asm/errno.h | 2 ++ > > > > > > tools/arch/parisc/include/uapi/asm/errno.h | 2 ++ > > > > > > tools/arch/sparc/include/uapi/asm/errno.h | 2 ++ > > > > > > tools/include/uapi/asm-generic/errno.h | 2 ++ > > > > > > 18 files changed, 38 insertions(+), 3 deletions(-) > > > > > > > > > > > > diff --git a/arch/alpha/include/uapi/asm/errno.h b/arch/alpha/include/uapi/asm/errno.h > > > > > > index 6791f6508632..8bbcaa9024f9 100644 > > > > > > --- a/arch/alpha/include/uapi/asm/errno.h > > > > > > +++ b/arch/alpha/include/uapi/asm/errno.h > > > > > > @@ -127,4 +127,6 @@ > > > > > > > > > > > > #define EHWPOISON 139 /* Memory page has hardware error */ > > > > > > > > > > > > +#define ENOTREG 140 /* Not a regular file */ > > > > > > + > > > > > > #endif > > > > > > diff --git a/arch/alpha/include/uapi/asm/fcntl.h b/arch/alpha/include/uapi/asm/fcntl.h > > > > > > index 50bdc8e8a271..4da5a64c23bd 100644 > > > > > > --- a/arch/alpha/include/uapi/asm/fcntl.h > > > > > > +++ b/arch/alpha/include/uapi/asm/fcntl.h > > > > > > @@ -34,6 +34,7 @@ > > > > > > > > > > > > #define O_PATH 040000000 > > > > > > #define __O_TMPFILE 0100000000 > > > > > > +#define O_REGULAR 0200000000 > > > > > > > > > > > > #define F_GETLK 7 > > > > > > #define F_SETLK 8 > > > > > > diff --git a/arch/mips/include/uapi/asm/errno.h b/arch/mips/include/uapi/asm/errno.h > > > > > > index c01ed91b1ef4..293c78777254 100644 > > > > > > --- a/arch/mips/include/uapi/asm/errno.h > > > > > > +++ b/arch/mips/include/uapi/asm/errno.h > > > > > > @@ -126,6 +126,8 @@ > > > > > > > > > > > > #define EHWPOISON 168 /* Memory page has hardware error */ > > > > > > > > > > > > +#define ENOTREG 169 /* Not a regular file */ > > > > > > + > > > > > > #define EDQUOT 1133 /* Quota exceeded */ > > > > > > > > > > > > > > > > > > diff --git a/arch/parisc/include/uapi/asm/errno.h b/arch/parisc/include/uapi/asm/errno.h > > > > > > index 8cbc07c1903e..442917484f99 100644 > > > > > > --- a/arch/parisc/include/uapi/asm/errno.h > > > > > > +++ b/arch/parisc/include/uapi/asm/errno.h > > > > > > @@ -124,4 +124,6 @@ > > > > > > > > > > > > #define EHWPOISON 257 /* Memory page has hardware error */ > > > > > > > > > > > > +#define ENOTREG 258 /* Not a regular file */ > > > > > > + > > > > > > #endif > > > > > > diff --git a/arch/parisc/include/uapi/asm/fcntl.h b/arch/parisc/include/uapi/asm/fcntl.h > > > > > > index 03dee816cb13..0cc3320fe326 100644 > > > > > > --- a/arch/parisc/include/uapi/asm/fcntl.h > > > > > > +++ b/arch/parisc/include/uapi/asm/fcntl.h > > > > > > @@ -19,6 +19,7 @@ > > > > > > > > > > > > #define O_PATH 020000000 > > > > > > #define __O_TMPFILE 040000000 > > > > > > +#define O_REGULAR 0100000000 > > > > > > > > > > > > #define F_GETLK64 8 > > > > > > #define F_SETLK64 9 > > > > > > diff --git a/arch/sparc/include/uapi/asm/errno.h b/arch/sparc/include/uapi/asm/errno.h > > > > > > index 4a41e7835fd5..8dce0bfeab74 100644 > > > > > > --- a/arch/sparc/include/uapi/asm/errno.h > > > > > > +++ b/arch/sparc/include/uapi/asm/errno.h > > > > > > @@ -117,4 +117,6 @@ > > > > > > > > > > > > #define EHWPOISON 135 /* Memory page has hardware error */ > > > > > > > > > > > > +#define ENOTREG 136 /* Not a regular file */ > > > > > > + > > > > > > #endif > > > > > > diff --git a/arch/sparc/include/uapi/asm/fcntl.h b/arch/sparc/include/uapi/asm/fcntl.h > > > > > > index 67dae75e5274..a93d18d2c23e 100644 > > > > > > --- a/arch/sparc/include/uapi/asm/fcntl.h > > > > > > +++ b/arch/sparc/include/uapi/asm/fcntl.h > > > > > > @@ -37,6 +37,7 @@ > > > > > > > > > > > > #define O_PATH 0x1000000 > > > > > > #define __O_TMPFILE 0x2000000 > > > > > > +#define O_REGULAR 0x4000000 > > > > > > > > > > > > #define F_GETOWN 5 /* for sockets. */ > > > > > > #define F_SETOWN 6 /* for sockets. */ > > > > > > diff --git a/fs/fcntl.c b/fs/fcntl.c > > > > > > index f93dbca08435..62ab4ad2b6f5 100644 > > > > > > --- a/fs/fcntl.c > > > > > > +++ b/fs/fcntl.c > > > > > > @@ -1169,7 +1169,7 @@ static int __init fcntl_init(void) > > > > > > * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY > > > > > > * is defined as O_NONBLOCK on some platforms and not on others. > > > > > > */ > > > > > > - BUILD_BUG_ON(20 - 1 /* for O_RDONLY being 0 */ != > > > > > > + BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ != > > > > > > HWEIGHT32( > > > > > > (VALID_OPEN_FLAGS & ~(O_NONBLOCK | O_NDELAY)) | > > > > > > __FMODE_EXEC)); > > > > > > diff --git a/fs/namei.c b/fs/namei.c > > > > > > index b28ecb699f32..f5504ae4b03c 100644 > > > > > > --- a/fs/namei.c > > > > > > +++ b/fs/namei.c > > > > > > @@ -4616,6 +4616,10 @@ static int do_open(struct nameidata *nd, > > > > > > if (unlikely(error)) > > > > > > return error; > > > > > > } > > > > > > + > > > > > > + if ((open_flag & O_REGULAR) && !d_is_reg(nd->path.dentry)) > > > > > > + return -ENOTREG; > > > > > > + > > > > > > if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry)) > > > > > > return -ENOTDIR; > > > > > > > > > > > > @@ -4765,6 +4769,8 @@ static int do_o_path(struct nameidata *nd, unsigned flags, struct file *file) > > > > > > struct path path; > > > > > > int error = path_lookupat(nd, flags, &path); > > > > > > if (!error) { > > > > > > + if ((file->f_flags & O_REGULAR) && !d_is_reg(path.dentry)) > > > > > > + return -ENOTREG; > > > > > > audit_inode(nd->name, path.dentry, 0); > > > > > > error = vfs_open(&path, file); > > > > > > path_put(&path); > > > > > > diff --git a/fs/open.c b/fs/open.c > > > > > > index 74c4c1462b3e..82153e21907e 100644 > > > > > > --- a/fs/open.c > > > > > > +++ b/fs/open.c > > > > > > @@ -1173,7 +1173,7 @@ struct file *kernel_file_open(const struct path *path, int flags, > > > > > > EXPORT_SYMBOL_GPL(kernel_file_open); > > > > > > > > > > > > #define WILL_CREATE(flags) (flags & (O_CREAT | __O_TMPFILE)) > > > > > > -#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC) > > > > > > +#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC | O_REGULAR) > > > > > > > > > > > > inline struct open_how build_open_how(int flags, umode_t mode) > > > > > > { > > > > > > @@ -1250,6 +1250,8 @@ inline int build_open_flags(const struct open_how *how, struct open_flags *op) > > > > > > return -EINVAL; > > > > > > if (!(acc_mode & MAY_WRITE)) > > > > > > return -EINVAL; > > > > > > + } else if ((flags & O_DIRECTORY) && (flags & O_REGULAR)) { > > > > > > + return -EINVAL; > > > > > > } > > > > > > if (flags & O_PATH) { > > > > > > /* O_PATH only permits certain other flags to be set. */ > > > > > > diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h > > > > > > index a332e79b3207..4fd07b0e0a17 100644 > > > > > > --- a/include/linux/fcntl.h > > > > > > +++ b/include/linux/fcntl.h > > > > > > @@ -10,7 +10,7 @@ > > > > > > (O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | \ > > > > > > O_APPEND | O_NDELAY | O_NONBLOCK | __O_SYNC | O_DSYNC | \ > > > > > > FASYNC | O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | \ > > > > > > - O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE) > > > > > > + O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE | O_REGULAR) > > > > > > > > > > > > /* List of all valid flags for the how->resolve argument: */ > > > > > > #define VALID_RESOLVE_FLAGS \ > > > > > > diff --git a/include/uapi/asm-generic/errno.h b/include/uapi/asm-generic/errno.h > > > > > > index 92e7ae493ee3..2216ab9aa32e 100644 > > > > > > --- a/include/uapi/asm-generic/errno.h > > > > > > +++ b/include/uapi/asm-generic/errno.h > > > > > > @@ -122,4 +122,6 @@ > > > > > > > > > > > > #define EHWPOISON 133 /* Memory page has hardware error */ > > > > > > > > > > > > +#define ENOTREG 134 /* Not a regular file */ > > > > > > + > > > > > > #endif > > > > > > diff --git a/include/uapi/asm-generic/fcntl.h b/include/uapi/asm-generic/fcntl.h > > > > > > index 613475285643..3468b352a575 100644 > > > > > > --- a/include/uapi/asm-generic/fcntl.h > > > > > > +++ b/include/uapi/asm-generic/fcntl.h > > > > > > @@ -88,6 +88,10 @@ > > > > > > #define __O_TMPFILE 020000000 > > > > > > #endif > > > > > > > > > > > > +#ifndef O_REGULAR > > > > > > +#define O_REGULAR 040000000 > > > > > > +#endif > > > > > > + > > > > > > /* a horrid kludge trying to make sure that this will fail on old kernels */ > > > > > > #define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) > > > > > > > > > > > > diff --git a/tools/arch/alpha/include/uapi/asm/errno.h b/tools/arch/alpha/include/uapi/asm/errno.h > > > > > > index 6791f6508632..8bbcaa9024f9 100644 > > > > > > --- a/tools/arch/alpha/include/uapi/asm/errno.h > > > > > > +++ b/tools/arch/alpha/include/uapi/asm/errno.h > > > > > > @@ -127,4 +127,6 @@ > > > > > > > > > > > > #define EHWPOISON 139 /* Memory page has hardware error */ > > > > > > > > > > > > +#define ENOTREG 140 /* Not a regular file */ > > > > > > + > > > > > > #endif > > > > > > diff --git a/tools/arch/mips/include/uapi/asm/errno.h b/tools/arch/mips/include/uapi/asm/errno.h > > > > > > index c01ed91b1ef4..293c78777254 100644 > > > > > > --- a/tools/arch/mips/include/uapi/asm/errno.h > > > > > > +++ b/tools/arch/mips/include/uapi/asm/errno.h > > > > > > @@ -126,6 +126,8 @@ > > > > > > > > > > > > #define EHWPOISON 168 /* Memory page has hardware error */ > > > > > > > > > > > > +#define ENOTREG 169 /* Not a regular file */ > > > > > > + > > > > > > #define EDQUOT 1133 /* Quota exceeded */ > > > > > > > > > > > > > > > > > > diff --git a/tools/arch/parisc/include/uapi/asm/errno.h b/tools/arch/parisc/include/uapi/asm/errno.h > > > > > > index 8cbc07c1903e..442917484f99 100644 > > > > > > --- a/tools/arch/parisc/include/uapi/asm/errno.h > > > > > > +++ b/tools/arch/parisc/include/uapi/asm/errno.h > > > > > > @@ -124,4 +124,6 @@ > > > > > > > > > > > > #define EHWPOISON 257 /* Memory page has hardware error */ > > > > > > > > > > > > +#define ENOTREG 258 /* Not a regular file */ > > > > > > + > > > > > > #endif > > > > > > diff --git a/tools/arch/sparc/include/uapi/asm/errno.h b/tools/arch/sparc/include/uapi/asm/errno.h > > > > > > index 4a41e7835fd5..8dce0bfeab74 100644 > > > > > > --- a/tools/arch/sparc/include/uapi/asm/errno.h > > > > > > +++ b/tools/arch/sparc/include/uapi/asm/errno.h > > > > > > @@ -117,4 +117,6 @@ > > > > > > > > > > > > #define EHWPOISON 135 /* Memory page has hardware error */ > > > > > > > > > > > > +#define ENOTREG 136 /* Not a regular file */ > > > > > > + > > > > > > #endif > > > > > > diff --git a/tools/include/uapi/asm-generic/errno.h b/tools/include/uapi/asm-generic/errno.h > > > > > > index 92e7ae493ee3..2216ab9aa32e 100644 > > > > > > --- a/tools/include/uapi/asm-generic/errno.h > > > > > > +++ b/tools/include/uapi/asm-generic/errno.h > > > > > > @@ -122,4 +122,6 @@ > > > > > > > > > > > > #define EHWPOISON 133 /* Memory page has hardware error */ > > > > > > > > > > > > +#define ENOTREG 134 /* Not a regular file */ > > > > > > + > > > > > > #endif > > > > > > > > > > One thing this patch is missing is handling for ->atomic_open(). I > > > > > imagine most of the filesystems that provide that op can't support > > > > > O_REGULAR properly (maybe cifs can? idk). What you probably want to do > > > > > is add in some patches that make all of the atomic_open operations in > > > > > the kernel return -EINVAL if O_REGULAR is set. > > > > > > > > > > Then, once the basic support is in, you or someone else can go back and > > > > > implement support for O_REGULAR where possible. > > > > > > > > Thank you for the feedback. I don't quite understand what I need to > > > > fix. I thought open system calls always create regular files, so > > > > atomic_open probably always creates regular files? Can you please give > > > > me some more details as to where I need to fix this and what the > > > > actual bug here is that is related to atomic_open? I think I had done > > > > some normal testing and when using O_CREAT | O_REGULAR, if the file > > > > doesn't exist, the file gets created and the file that gets created is > > > > a regular file, so it probably makes sense? Or should the behavior be > > > > that if file doesn't exist, -EINVAL is returned and if file exists it > > > > is opened if regular, otherwise -ENOTREG is returned? > > > > > > > > > > atomic_open() is a combination lookup+open for when the dentry isn't > > > present in the dcache. The normal open codepath that you're patching > > > does not get called in this case when ->atomic_open is set for the > > > filesystem. It's mostly used by network filesystems that need to > > > optimize away the lookup since it's wasted round trip, and is often > > > racy anyway. Your patchset doesn't address those filesystems. They will > > > likely end up ignoring O_REGULAR in that case, which is not what you > > > want. > > > > > > What I was suggesting is that, as an interim step, you find all of the > > > atomic_open operations in the kernel (there are maybe a dozen or so), > > > and just make them return -EINVAL if someone sets O_DIRECTORY. Later, > > > you or someone else can then go back and do a proper implementation of > > > O_REGULAR handling on those filesystems, at least on the ones where > > > it's possible. You will probably also need to similarly patch the > > > open() routines for those filesystems too. Otherwise you'll get > > > inconsistent behavior vs. when the dentry is in the cache. > > > > > > One note: I think NFS probably can support O_DIRECTORY, since its OPEN > > > call only works on files. We'll need to change how we handle errors > > > from the server when it's set though. > > > > So I think you're proposing two separate things or there's a typo: > > > > (1) blocking O_DIRECTORY for ->atomic_open:: > > (2) blocking O_REGULAR for ->atomic_open:: > > > > The (1) point implies that O_DIRECTORY currently doesn't work correctly > > with atomic open for all filesystems. > > > > Ever since 43b450632676 ("open: return EINVAL for O_DIRECTORY | > > O_CREAT") O_DIRECTORY with O_CREAT is blocked. It was accidently allowed > > and completely broken before that. > > > > For O_DIRECTORY without O_CREAT the kernel will pass that down through > > ->atomic_open:: to the filesystem. > > > > The worry that I see is that a network filesystem via ->atomic_open:: > > somehow already called open on the server side on something that wasn't > > a directory. At that point the damage such as side-effects from device > > opening is already done. > > > > > > Exactly. I guess you could send an immediate close, but that's not > without side effects. > > > > > But I suspect that every filesystem implementing ->atomic_open:: just > > does finish_no_open() and punts to the VFS for the actual open. And the > > VFS will catch it in do_open() for it actually opens the file. So the > > only real worry for O_DIRECTORY I see is that there's an fs that handles > > it wrong. > > > > For (2) it is problematic as there surely are filesystems with > > ->atomic_open:: that do handle the ~O_CREAT case and return with > > FMODE_OPENED. So that'll be problematic if the intention is to not > > trigger an actual open on a non-regular file such as a > > device/socket/fifo etc. before the VFS had a chance to validate what's > > going on. > > > > So I'm not excited about having this 70% working and punting on > > ->atomic_open:: waiting for someone to fix this. One option would be to > > bypass ->atomic_open:: for OPENAT2_REGULAR without O_CREAT and fallback > > to racy and pricy lookup + open for now. How problematic would that be? > > If possible I'd prefer this a lot over merging something that works > > half-way. > > > > I guess to make that really work you'd need some protocol extension? > > For NFS, I think we're OK. The OPEN call on NFSv4 only works for > regular files, so it should be able to handle O_REGULAR. We just need > to rejigger the error handling when it's set (just return an error > instead of doing the open of a directory or whatever it is). > Thank you for the details. Do you remember which codepath this is? Is this the inode_operations.atomic_open codepath or file_operations.open codepath? I am a bit confused also about where exactly the error handling that needs to be done. > The others (at a quick glance): > > cifs: I don't see a way to specify an O_REGULAR equivalent to the > SMB2_CREATE call and it looks like it can create directories. Maybe > SteveF (cc'ed) knows if this is possible? > > ceph: I think CEPH_MDS_OP_OPEN might only work for files, in which case > O_REGULAR can probably be supported similarly to NFS. > > fuse: probably ok? Does finish_no_open() in most cases. May depend on > the userland driver though. > > gfs2: is ok, it just does finish_no_open() in most cases anyway > > vboxsf: does finish_no_open on non-creates, so you could probably just > punt to that if O_REGULAR is set. > These are all inode_operations.atomic_open code paths, right? Because you mentioned finish_no_open and I see finish_no_open in the atomic_open code paths as opposed to file_operations.open code paths. Regards, Dorjoy ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v3 1/4] open: new O_REGULAR flag support 2026-02-18 18:26 ` Dorjoy Chowdhury @ 2026-02-18 19:01 ` Jeff Layton 2026-02-18 19:19 ` Dorjoy Chowdhury 0 siblings, 1 reply; 26+ messages in thread From: Jeff Layton @ 2026-02-18 19:01 UTC (permalink / raw) To: Dorjoy Chowdhury Cc: Christian Brauner, linux-fsdevel, linux-kernel, viro, jack, chuck.lever, alex.aring, arnd, adilger, smfrench On Thu, 2026-02-19 at 00:26 +0600, Dorjoy Chowdhury wrote: > On Thu, Jan 29, 2026 at 7:12 PM Jeff Layton <jlayton@kernel.org> wrote: > > > > On Thu, 2026-01-29 at 13:33 +0100, Christian Brauner wrote: > > > On Wed, Jan 28, 2026 at 10:51:07AM -0500, Jeff Layton wrote: > > > > On Wed, 2026-01-28 at 21:36 +0600, Dorjoy Chowdhury wrote: > > > > > On Wed, Jan 28, 2026 at 5:52 AM Jeff Layton <jlayton@kernel.org> wrote: > > > > > > > > > > > > On Tue, 2026-01-27 at 23:58 +0600, Dorjoy Chowdhury wrote: > > > > > > > This flag indicates the path should be opened if it's a regular file. > > > > > > > This is useful to write secure programs that want to avoid being tricked > > > > > > > into opening device nodes with special semantics while thinking they > > > > > > > operate on regular files. > > > > > > > > > > > > > > A corresponding error code ENOTREG has been introduced. For example, if > > > > > > > open is called on path /dev/null with O_REGULAR in the flag param, it > > > > > > > will return -ENOTREG. > > > > > > > > > > > > > > When used in combination with O_CREAT, either the regular file is > > > > > > > created, or if the path already exists, it is opened if it's a regular > > > > > > > file. Otherwise, -ENOTREG is returned. > > > > > > > > > > > > > > -EINVAL is returned when O_REGULAR is combined with O_DIRECTORY (not > > > > > > > part of O_TMPFILE) because it doesn't make sense to open a path that > > > > > > > is both a directory and a regular file. > > > > > > > > > > > > > > Signed-off-by: Dorjoy Chowdhury <dorjoychy111@gmail.com> > > > > > > > --- > > > > > > > arch/alpha/include/uapi/asm/errno.h | 2 ++ > > > > > > > arch/alpha/include/uapi/asm/fcntl.h | 1 + > > > > > > > arch/mips/include/uapi/asm/errno.h | 2 ++ > > > > > > > arch/parisc/include/uapi/asm/errno.h | 2 ++ > > > > > > > arch/parisc/include/uapi/asm/fcntl.h | 1 + > > > > > > > arch/sparc/include/uapi/asm/errno.h | 2 ++ > > > > > > > arch/sparc/include/uapi/asm/fcntl.h | 1 + > > > > > > > fs/fcntl.c | 2 +- > > > > > > > fs/namei.c | 6 ++++++ > > > > > > > fs/open.c | 4 +++- > > > > > > > include/linux/fcntl.h | 2 +- > > > > > > > include/uapi/asm-generic/errno.h | 2 ++ > > > > > > > include/uapi/asm-generic/fcntl.h | 4 ++++ > > > > > > > tools/arch/alpha/include/uapi/asm/errno.h | 2 ++ > > > > > > > tools/arch/mips/include/uapi/asm/errno.h | 2 ++ > > > > > > > tools/arch/parisc/include/uapi/asm/errno.h | 2 ++ > > > > > > > tools/arch/sparc/include/uapi/asm/errno.h | 2 ++ > > > > > > > tools/include/uapi/asm-generic/errno.h | 2 ++ > > > > > > > 18 files changed, 38 insertions(+), 3 deletions(-) > > > > > > > > > > > > > > diff --git a/arch/alpha/include/uapi/asm/errno.h b/arch/alpha/include/uapi/asm/errno.h > > > > > > > index 6791f6508632..8bbcaa9024f9 100644 > > > > > > > --- a/arch/alpha/include/uapi/asm/errno.h > > > > > > > +++ b/arch/alpha/include/uapi/asm/errno.h > > > > > > > @@ -127,4 +127,6 @@ > > > > > > > > > > > > > > #define EHWPOISON 139 /* Memory page has hardware error */ > > > > > > > > > > > > > > +#define ENOTREG 140 /* Not a regular file */ > > > > > > > + > > > > > > > #endif > > > > > > > diff --git a/arch/alpha/include/uapi/asm/fcntl.h b/arch/alpha/include/uapi/asm/fcntl.h > > > > > > > index 50bdc8e8a271..4da5a64c23bd 100644 > > > > > > > --- a/arch/alpha/include/uapi/asm/fcntl.h > > > > > > > +++ b/arch/alpha/include/uapi/asm/fcntl.h > > > > > > > @@ -34,6 +34,7 @@ > > > > > > > > > > > > > > #define O_PATH 040000000 > > > > > > > #define __O_TMPFILE 0100000000 > > > > > > > +#define O_REGULAR 0200000000 > > > > > > > > > > > > > > #define F_GETLK 7 > > > > > > > #define F_SETLK 8 > > > > > > > diff --git a/arch/mips/include/uapi/asm/errno.h b/arch/mips/include/uapi/asm/errno.h > > > > > > > index c01ed91b1ef4..293c78777254 100644 > > > > > > > --- a/arch/mips/include/uapi/asm/errno.h > > > > > > > +++ b/arch/mips/include/uapi/asm/errno.h > > > > > > > @@ -126,6 +126,8 @@ > > > > > > > > > > > > > > #define EHWPOISON 168 /* Memory page has hardware error */ > > > > > > > > > > > > > > +#define ENOTREG 169 /* Not a regular file */ > > > > > > > + > > > > > > > #define EDQUOT 1133 /* Quota exceeded */ > > > > > > > > > > > > > > > > > > > > > diff --git a/arch/parisc/include/uapi/asm/errno.h b/arch/parisc/include/uapi/asm/errno.h > > > > > > > index 8cbc07c1903e..442917484f99 100644 > > > > > > > --- a/arch/parisc/include/uapi/asm/errno.h > > > > > > > +++ b/arch/parisc/include/uapi/asm/errno.h > > > > > > > @@ -124,4 +124,6 @@ > > > > > > > > > > > > > > #define EHWPOISON 257 /* Memory page has hardware error */ > > > > > > > > > > > > > > +#define ENOTREG 258 /* Not a regular file */ > > > > > > > + > > > > > > > #endif > > > > > > > diff --git a/arch/parisc/include/uapi/asm/fcntl.h b/arch/parisc/include/uapi/asm/fcntl.h > > > > > > > index 03dee816cb13..0cc3320fe326 100644 > > > > > > > --- a/arch/parisc/include/uapi/asm/fcntl.h > > > > > > > +++ b/arch/parisc/include/uapi/asm/fcntl.h > > > > > > > @@ -19,6 +19,7 @@ > > > > > > > > > > > > > > #define O_PATH 020000000 > > > > > > > #define __O_TMPFILE 040000000 > > > > > > > +#define O_REGULAR 0100000000 > > > > > > > > > > > > > > #define F_GETLK64 8 > > > > > > > #define F_SETLK64 9 > > > > > > > diff --git a/arch/sparc/include/uapi/asm/errno.h b/arch/sparc/include/uapi/asm/errno.h > > > > > > > index 4a41e7835fd5..8dce0bfeab74 100644 > > > > > > > --- a/arch/sparc/include/uapi/asm/errno.h > > > > > > > +++ b/arch/sparc/include/uapi/asm/errno.h > > > > > > > @@ -117,4 +117,6 @@ > > > > > > > > > > > > > > #define EHWPOISON 135 /* Memory page has hardware error */ > > > > > > > > > > > > > > +#define ENOTREG 136 /* Not a regular file */ > > > > > > > + > > > > > > > #endif > > > > > > > diff --git a/arch/sparc/include/uapi/asm/fcntl.h b/arch/sparc/include/uapi/asm/fcntl.h > > > > > > > index 67dae75e5274..a93d18d2c23e 100644 > > > > > > > --- a/arch/sparc/include/uapi/asm/fcntl.h > > > > > > > +++ b/arch/sparc/include/uapi/asm/fcntl.h > > > > > > > @@ -37,6 +37,7 @@ > > > > > > > > > > > > > > #define O_PATH 0x1000000 > > > > > > > #define __O_TMPFILE 0x2000000 > > > > > > > +#define O_REGULAR 0x4000000 > > > > > > > > > > > > > > #define F_GETOWN 5 /* for sockets. */ > > > > > > > #define F_SETOWN 6 /* for sockets. */ > > > > > > > diff --git a/fs/fcntl.c b/fs/fcntl.c > > > > > > > index f93dbca08435..62ab4ad2b6f5 100644 > > > > > > > --- a/fs/fcntl.c > > > > > > > +++ b/fs/fcntl.c > > > > > > > @@ -1169,7 +1169,7 @@ static int __init fcntl_init(void) > > > > > > > * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY > > > > > > > * is defined as O_NONBLOCK on some platforms and not on others. > > > > > > > */ > > > > > > > - BUILD_BUG_ON(20 - 1 /* for O_RDONLY being 0 */ != > > > > > > > + BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ != > > > > > > > HWEIGHT32( > > > > > > > (VALID_OPEN_FLAGS & ~(O_NONBLOCK | O_NDELAY)) | > > > > > > > __FMODE_EXEC)); > > > > > > > diff --git a/fs/namei.c b/fs/namei.c > > > > > > > index b28ecb699f32..f5504ae4b03c 100644 > > > > > > > --- a/fs/namei.c > > > > > > > +++ b/fs/namei.c > > > > > > > @@ -4616,6 +4616,10 @@ static int do_open(struct nameidata *nd, > > > > > > > if (unlikely(error)) > > > > > > > return error; > > > > > > > } > > > > > > > + > > > > > > > + if ((open_flag & O_REGULAR) && !d_is_reg(nd->path.dentry)) > > > > > > > + return -ENOTREG; > > > > > > > + > > > > > > > if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry)) > > > > > > > return -ENOTDIR; > > > > > > > > > > > > > > @@ -4765,6 +4769,8 @@ static int do_o_path(struct nameidata *nd, unsigned flags, struct file *file) > > > > > > > struct path path; > > > > > > > int error = path_lookupat(nd, flags, &path); > > > > > > > if (!error) { > > > > > > > + if ((file->f_flags & O_REGULAR) && !d_is_reg(path.dentry)) > > > > > > > + return -ENOTREG; > > > > > > > audit_inode(nd->name, path.dentry, 0); > > > > > > > error = vfs_open(&path, file); > > > > > > > path_put(&path); > > > > > > > diff --git a/fs/open.c b/fs/open.c > > > > > > > index 74c4c1462b3e..82153e21907e 100644 > > > > > > > --- a/fs/open.c > > > > > > > +++ b/fs/open.c > > > > > > > @@ -1173,7 +1173,7 @@ struct file *kernel_file_open(const struct path *path, int flags, > > > > > > > EXPORT_SYMBOL_GPL(kernel_file_open); > > > > > > > > > > > > > > #define WILL_CREATE(flags) (flags & (O_CREAT | __O_TMPFILE)) > > > > > > > -#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC) > > > > > > > +#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC | O_REGULAR) > > > > > > > > > > > > > > inline struct open_how build_open_how(int flags, umode_t mode) > > > > > > > { > > > > > > > @@ -1250,6 +1250,8 @@ inline int build_open_flags(const struct open_how *how, struct open_flags *op) > > > > > > > return -EINVAL; > > > > > > > if (!(acc_mode & MAY_WRITE)) > > > > > > > return -EINVAL; > > > > > > > + } else if ((flags & O_DIRECTORY) && (flags & O_REGULAR)) { > > > > > > > + return -EINVAL; > > > > > > > } > > > > > > > if (flags & O_PATH) { > > > > > > > /* O_PATH only permits certain other flags to be set. */ > > > > > > > diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h > > > > > > > index a332e79b3207..4fd07b0e0a17 100644 > > > > > > > --- a/include/linux/fcntl.h > > > > > > > +++ b/include/linux/fcntl.h > > > > > > > @@ -10,7 +10,7 @@ > > > > > > > (O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | \ > > > > > > > O_APPEND | O_NDELAY | O_NONBLOCK | __O_SYNC | O_DSYNC | \ > > > > > > > FASYNC | O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | \ > > > > > > > - O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE) > > > > > > > + O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE | O_REGULAR) > > > > > > > > > > > > > > /* List of all valid flags for the how->resolve argument: */ > > > > > > > #define VALID_RESOLVE_FLAGS \ > > > > > > > diff --git a/include/uapi/asm-generic/errno.h b/include/uapi/asm-generic/errno.h > > > > > > > index 92e7ae493ee3..2216ab9aa32e 100644 > > > > > > > --- a/include/uapi/asm-generic/errno.h > > > > > > > +++ b/include/uapi/asm-generic/errno.h > > > > > > > @@ -122,4 +122,6 @@ > > > > > > > > > > > > > > #define EHWPOISON 133 /* Memory page has hardware error */ > > > > > > > > > > > > > > +#define ENOTREG 134 /* Not a regular file */ > > > > > > > + > > > > > > > #endif > > > > > > > diff --git a/include/uapi/asm-generic/fcntl.h b/include/uapi/asm-generic/fcntl.h > > > > > > > index 613475285643..3468b352a575 100644 > > > > > > > --- a/include/uapi/asm-generic/fcntl.h > > > > > > > +++ b/include/uapi/asm-generic/fcntl.h > > > > > > > @@ -88,6 +88,10 @@ > > > > > > > #define __O_TMPFILE 020000000 > > > > > > > #endif > > > > > > > > > > > > > > +#ifndef O_REGULAR > > > > > > > +#define O_REGULAR 040000000 > > > > > > > +#endif > > > > > > > + > > > > > > > /* a horrid kludge trying to make sure that this will fail on old kernels */ > > > > > > > #define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) > > > > > > > > > > > > > > diff --git a/tools/arch/alpha/include/uapi/asm/errno.h b/tools/arch/alpha/include/uapi/asm/errno.h > > > > > > > index 6791f6508632..8bbcaa9024f9 100644 > > > > > > > --- a/tools/arch/alpha/include/uapi/asm/errno.h > > > > > > > +++ b/tools/arch/alpha/include/uapi/asm/errno.h > > > > > > > @@ -127,4 +127,6 @@ > > > > > > > > > > > > > > #define EHWPOISON 139 /* Memory page has hardware error */ > > > > > > > > > > > > > > +#define ENOTREG 140 /* Not a regular file */ > > > > > > > + > > > > > > > #endif > > > > > > > diff --git a/tools/arch/mips/include/uapi/asm/errno.h b/tools/arch/mips/include/uapi/asm/errno.h > > > > > > > index c01ed91b1ef4..293c78777254 100644 > > > > > > > --- a/tools/arch/mips/include/uapi/asm/errno.h > > > > > > > +++ b/tools/arch/mips/include/uapi/asm/errno.h > > > > > > > @@ -126,6 +126,8 @@ > > > > > > > > > > > > > > #define EHWPOISON 168 /* Memory page has hardware error */ > > > > > > > > > > > > > > +#define ENOTREG 169 /* Not a regular file */ > > > > > > > + > > > > > > > #define EDQUOT 1133 /* Quota exceeded */ > > > > > > > > > > > > > > > > > > > > > diff --git a/tools/arch/parisc/include/uapi/asm/errno.h b/tools/arch/parisc/include/uapi/asm/errno.h > > > > > > > index 8cbc07c1903e..442917484f99 100644 > > > > > > > --- a/tools/arch/parisc/include/uapi/asm/errno.h > > > > > > > +++ b/tools/arch/parisc/include/uapi/asm/errno.h > > > > > > > @@ -124,4 +124,6 @@ > > > > > > > > > > > > > > #define EHWPOISON 257 /* Memory page has hardware error */ > > > > > > > > > > > > > > +#define ENOTREG 258 /* Not a regular file */ > > > > > > > + > > > > > > > #endif > > > > > > > diff --git a/tools/arch/sparc/include/uapi/asm/errno.h b/tools/arch/sparc/include/uapi/asm/errno.h > > > > > > > index 4a41e7835fd5..8dce0bfeab74 100644 > > > > > > > --- a/tools/arch/sparc/include/uapi/asm/errno.h > > > > > > > +++ b/tools/arch/sparc/include/uapi/asm/errno.h > > > > > > > @@ -117,4 +117,6 @@ > > > > > > > > > > > > > > #define EHWPOISON 135 /* Memory page has hardware error */ > > > > > > > > > > > > > > +#define ENOTREG 136 /* Not a regular file */ > > > > > > > + > > > > > > > #endif > > > > > > > diff --git a/tools/include/uapi/asm-generic/errno.h b/tools/include/uapi/asm-generic/errno.h > > > > > > > index 92e7ae493ee3..2216ab9aa32e 100644 > > > > > > > --- a/tools/include/uapi/asm-generic/errno.h > > > > > > > +++ b/tools/include/uapi/asm-generic/errno.h > > > > > > > @@ -122,4 +122,6 @@ > > > > > > > > > > > > > > #define EHWPOISON 133 /* Memory page has hardware error */ > > > > > > > > > > > > > > +#define ENOTREG 134 /* Not a regular file */ > > > > > > > + > > > > > > > #endif > > > > > > > > > > > > One thing this patch is missing is handling for ->atomic_open(). I > > > > > > imagine most of the filesystems that provide that op can't support > > > > > > O_REGULAR properly (maybe cifs can? idk). What you probably want to do > > > > > > is add in some patches that make all of the atomic_open operations in > > > > > > the kernel return -EINVAL if O_REGULAR is set. > > > > > > > > > > > > Then, once the basic support is in, you or someone else can go back and > > > > > > implement support for O_REGULAR where possible. > > > > > > > > > > Thank you for the feedback. I don't quite understand what I need to > > > > > fix. I thought open system calls always create regular files, so > > > > > atomic_open probably always creates regular files? Can you please give > > > > > me some more details as to where I need to fix this and what the > > > > > actual bug here is that is related to atomic_open? I think I had done > > > > > some normal testing and when using O_CREAT | O_REGULAR, if the file > > > > > doesn't exist, the file gets created and the file that gets created is > > > > > a regular file, so it probably makes sense? Or should the behavior be > > > > > that if file doesn't exist, -EINVAL is returned and if file exists it > > > > > is opened if regular, otherwise -ENOTREG is returned? > > > > > > > > > > > > > atomic_open() is a combination lookup+open for when the dentry isn't > > > > present in the dcache. The normal open codepath that you're patching > > > > does not get called in this case when ->atomic_open is set for the > > > > filesystem. It's mostly used by network filesystems that need to > > > > optimize away the lookup since it's wasted round trip, and is often > > > > racy anyway. Your patchset doesn't address those filesystems. They will > > > > likely end up ignoring O_REGULAR in that case, which is not what you > > > > want. > > > > > > > > What I was suggesting is that, as an interim step, you find all of the > > > > atomic_open operations in the kernel (there are maybe a dozen or so), > > > > and just make them return -EINVAL if someone sets O_DIRECTORY. Later, > > > > you or someone else can then go back and do a proper implementation of > > > > O_REGULAR handling on those filesystems, at least on the ones where > > > > it's possible. You will probably also need to similarly patch the > > > > open() routines for those filesystems too. Otherwise you'll get > > > > inconsistent behavior vs. when the dentry is in the cache. > > > > > > > > One note: I think NFS probably can support O_DIRECTORY, since its OPEN > > > > call only works on files. We'll need to change how we handle errors > > > > from the server when it's set though. > > > > > > So I think you're proposing two separate things or there's a typo: > > > > > > (1) blocking O_DIRECTORY for ->atomic_open:: > > > (2) blocking O_REGULAR for ->atomic_open:: > > > > > > The (1) point implies that O_DIRECTORY currently doesn't work correctly > > > with atomic open for all filesystems. > > > > > > Ever since 43b450632676 ("open: return EINVAL for O_DIRECTORY | > > > O_CREAT") O_DIRECTORY with O_CREAT is blocked. It was accidently allowed > > > and completely broken before that. > > > > > > For O_DIRECTORY without O_CREAT the kernel will pass that down through > > > ->atomic_open:: to the filesystem. > > > > > > The worry that I see is that a network filesystem via ->atomic_open:: > > > somehow already called open on the server side on something that wasn't > > > a directory. At that point the damage such as side-effects from device > > > opening is already done. > > > > > > > > > > Exactly. I guess you could send an immediate close, but that's not > > without side effects. > > > > > > > > But I suspect that every filesystem implementing ->atomic_open:: just > > > does finish_no_open() and punts to the VFS for the actual open. And the > > > VFS will catch it in do_open() for it actually opens the file. So the > > > only real worry for O_DIRECTORY I see is that there's an fs that handles > > > it wrong. > > > > > > For (2) it is problematic as there surely are filesystems with > > > ->atomic_open:: that do handle the ~O_CREAT case and return with > > > FMODE_OPENED. So that'll be problematic if the intention is to not > > > trigger an actual open on a non-regular file such as a > > > device/socket/fifo etc. before the VFS had a chance to validate what's > > > going on. > > > > > > So I'm not excited about having this 70% working and punting on > > > ->atomic_open:: waiting for someone to fix this. One option would be to > > > bypass ->atomic_open:: for OPENAT2_REGULAR without O_CREAT and fallback > > > to racy and pricy lookup + open for now. How problematic would that be? > > > If possible I'd prefer this a lot over merging something that works > > > half-way. > > > > > > I guess to make that really work you'd need some protocol extension? > > > > For NFS, I think we're OK. The OPEN call on NFSv4 only works for > > regular files, so it should be able to handle O_REGULAR. We just need > > to rejigger the error handling when it's set (just return an error > > instead of doing the open of a directory or whatever it is). > > > > Thank you for the details. Do you remember which codepath this is? Is > this the inode_operations.atomic_open codepath or file_operations.open > codepath? I am a bit confused also about where exactly the error > handling that needs to be done. > I was thinking nfs_atomic_open(). Looking now, I think it might actually work OK without changes. It just might not be terribly efficient about it. If the open_context() call returns -EISDIR or similar, then you really don't need to do the call to nfs_lookup() and the like. You can just return an immediate error when O_REGULAR is set since you know it's not suitable to be opened. > > The others (at a quick glance): > > > > cifs: I don't see a way to specify an O_REGULAR equivalent to the > > SMB2_CREATE call and it looks like it can create directories. Maybe > > SteveF (cc'ed) knows if this is possible? > > > > ceph: I think CEPH_MDS_OP_OPEN might only work for files, in which case > > O_REGULAR can probably be supported similarly to NFS. > > > > fuse: probably ok? Does finish_no_open() in most cases. May depend on > > the userland driver though. > > > > gfs2: is ok, it just does finish_no_open() in most cases anyway > > > > vboxsf: does finish_no_open on non-creates, so you could probably just > > punt to that if O_REGULAR is set. > > > > These are all inode_operations.atomic_open code paths, right? Because > you mentioned finish_no_open and I see finish_no_open in the > atomic_open code paths as opposed to file_operations.open code paths. > Note that this was just a cursory look. Someone will need to do a deeper dive and test these cases. I think most will end up working ok, since most fall back to doing a finish_no_open(). There may be opportunities to optimize some of these cases though (similarly to how I mentioned with NFS). -- Jeff Layton <jlayton@kernel.org> ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v3 1/4] open: new O_REGULAR flag support 2026-02-18 19:01 ` Jeff Layton @ 2026-02-18 19:19 ` Dorjoy Chowdhury 2026-02-18 19:32 ` Jeff Layton 0 siblings, 1 reply; 26+ messages in thread From: Dorjoy Chowdhury @ 2026-02-18 19:19 UTC (permalink / raw) To: Jeff Layton Cc: Christian Brauner, linux-fsdevel, linux-kernel, viro, jack, chuck.lever, alex.aring, arnd, adilger, smfrench On Thu, Feb 19, 2026 at 1:01 AM Jeff Layton <jlayton@kernel.org> wrote: > > On Thu, 2026-02-19 at 00:26 +0600, Dorjoy Chowdhury wrote: > > On Thu, Jan 29, 2026 at 7:12 PM Jeff Layton <jlayton@kernel.org> wrote: > > > > > > On Thu, 2026-01-29 at 13:33 +0100, Christian Brauner wrote: > > > > On Wed, Jan 28, 2026 at 10:51:07AM -0500, Jeff Layton wrote: > > > > > On Wed, 2026-01-28 at 21:36 +0600, Dorjoy Chowdhury wrote: > > > > > > On Wed, Jan 28, 2026 at 5:52 AM Jeff Layton <jlayton@kernel.org> wrote: > > > > > > > > > > > > > > On Tue, 2026-01-27 at 23:58 +0600, Dorjoy Chowdhury wrote: > > > > > > > > This flag indicates the path should be opened if it's a regular file. > > > > > > > > This is useful to write secure programs that want to avoid being tricked > > > > > > > > into opening device nodes with special semantics while thinking they > > > > > > > > operate on regular files. > > > > > > > > > > > > > > > > A corresponding error code ENOTREG has been introduced. For example, if > > > > > > > > open is called on path /dev/null with O_REGULAR in the flag param, it > > > > > > > > will return -ENOTREG. > > > > > > > > > > > > > > > > When used in combination with O_CREAT, either the regular file is > > > > > > > > created, or if the path already exists, it is opened if it's a regular > > > > > > > > file. Otherwise, -ENOTREG is returned. > > > > > > > > > > > > > > > > -EINVAL is returned when O_REGULAR is combined with O_DIRECTORY (not > > > > > > > > part of O_TMPFILE) because it doesn't make sense to open a path that > > > > > > > > is both a directory and a regular file. > > > > > > > > > > > > > > > > Signed-off-by: Dorjoy Chowdhury <dorjoychy111@gmail.com> > > > > > > > > --- > > > > > > > > arch/alpha/include/uapi/asm/errno.h | 2 ++ > > > > > > > > arch/alpha/include/uapi/asm/fcntl.h | 1 + > > > > > > > > arch/mips/include/uapi/asm/errno.h | 2 ++ > > > > > > > > arch/parisc/include/uapi/asm/errno.h | 2 ++ > > > > > > > > arch/parisc/include/uapi/asm/fcntl.h | 1 + > > > > > > > > arch/sparc/include/uapi/asm/errno.h | 2 ++ > > > > > > > > arch/sparc/include/uapi/asm/fcntl.h | 1 + > > > > > > > > fs/fcntl.c | 2 +- > > > > > > > > fs/namei.c | 6 ++++++ > > > > > > > > fs/open.c | 4 +++- > > > > > > > > include/linux/fcntl.h | 2 +- > > > > > > > > include/uapi/asm-generic/errno.h | 2 ++ > > > > > > > > include/uapi/asm-generic/fcntl.h | 4 ++++ > > > > > > > > tools/arch/alpha/include/uapi/asm/errno.h | 2 ++ > > > > > > > > tools/arch/mips/include/uapi/asm/errno.h | 2 ++ > > > > > > > > tools/arch/parisc/include/uapi/asm/errno.h | 2 ++ > > > > > > > > tools/arch/sparc/include/uapi/asm/errno.h | 2 ++ > > > > > > > > tools/include/uapi/asm-generic/errno.h | 2 ++ > > > > > > > > 18 files changed, 38 insertions(+), 3 deletions(-) > > > > > > > > > > > > > > > > diff --git a/arch/alpha/include/uapi/asm/errno.h b/arch/alpha/include/uapi/asm/errno.h > > > > > > > > index 6791f6508632..8bbcaa9024f9 100644 > > > > > > > > --- a/arch/alpha/include/uapi/asm/errno.h > > > > > > > > +++ b/arch/alpha/include/uapi/asm/errno.h > > > > > > > > @@ -127,4 +127,6 @@ > > > > > > > > > > > > > > > > #define EHWPOISON 139 /* Memory page has hardware error */ > > > > > > > > > > > > > > > > +#define ENOTREG 140 /* Not a regular file */ > > > > > > > > + > > > > > > > > #endif > > > > > > > > diff --git a/arch/alpha/include/uapi/asm/fcntl.h b/arch/alpha/include/uapi/asm/fcntl.h > > > > > > > > index 50bdc8e8a271..4da5a64c23bd 100644 > > > > > > > > --- a/arch/alpha/include/uapi/asm/fcntl.h > > > > > > > > +++ b/arch/alpha/include/uapi/asm/fcntl.h > > > > > > > > @@ -34,6 +34,7 @@ > > > > > > > > > > > > > > > > #define O_PATH 040000000 > > > > > > > > #define __O_TMPFILE 0100000000 > > > > > > > > +#define O_REGULAR 0200000000 > > > > > > > > > > > > > > > > #define F_GETLK 7 > > > > > > > > #define F_SETLK 8 > > > > > > > > diff --git a/arch/mips/include/uapi/asm/errno.h b/arch/mips/include/uapi/asm/errno.h > > > > > > > > index c01ed91b1ef4..293c78777254 100644 > > > > > > > > --- a/arch/mips/include/uapi/asm/errno.h > > > > > > > > +++ b/arch/mips/include/uapi/asm/errno.h > > > > > > > > @@ -126,6 +126,8 @@ > > > > > > > > > > > > > > > > #define EHWPOISON 168 /* Memory page has hardware error */ > > > > > > > > > > > > > > > > +#define ENOTREG 169 /* Not a regular file */ > > > > > > > > + > > > > > > > > #define EDQUOT 1133 /* Quota exceeded */ > > > > > > > > > > > > > > > > > > > > > > > > diff --git a/arch/parisc/include/uapi/asm/errno.h b/arch/parisc/include/uapi/asm/errno.h > > > > > > > > index 8cbc07c1903e..442917484f99 100644 > > > > > > > > --- a/arch/parisc/include/uapi/asm/errno.h > > > > > > > > +++ b/arch/parisc/include/uapi/asm/errno.h > > > > > > > > @@ -124,4 +124,6 @@ > > > > > > > > > > > > > > > > #define EHWPOISON 257 /* Memory page has hardware error */ > > > > > > > > > > > > > > > > +#define ENOTREG 258 /* Not a regular file */ > > > > > > > > + > > > > > > > > #endif > > > > > > > > diff --git a/arch/parisc/include/uapi/asm/fcntl.h b/arch/parisc/include/uapi/asm/fcntl.h > > > > > > > > index 03dee816cb13..0cc3320fe326 100644 > > > > > > > > --- a/arch/parisc/include/uapi/asm/fcntl.h > > > > > > > > +++ b/arch/parisc/include/uapi/asm/fcntl.h > > > > > > > > @@ -19,6 +19,7 @@ > > > > > > > > > > > > > > > > #define O_PATH 020000000 > > > > > > > > #define __O_TMPFILE 040000000 > > > > > > > > +#define O_REGULAR 0100000000 > > > > > > > > > > > > > > > > #define F_GETLK64 8 > > > > > > > > #define F_SETLK64 9 > > > > > > > > diff --git a/arch/sparc/include/uapi/asm/errno.h b/arch/sparc/include/uapi/asm/errno.h > > > > > > > > index 4a41e7835fd5..8dce0bfeab74 100644 > > > > > > > > --- a/arch/sparc/include/uapi/asm/errno.h > > > > > > > > +++ b/arch/sparc/include/uapi/asm/errno.h > > > > > > > > @@ -117,4 +117,6 @@ > > > > > > > > > > > > > > > > #define EHWPOISON 135 /* Memory page has hardware error */ > > > > > > > > > > > > > > > > +#define ENOTREG 136 /* Not a regular file */ > > > > > > > > + > > > > > > > > #endif > > > > > > > > diff --git a/arch/sparc/include/uapi/asm/fcntl.h b/arch/sparc/include/uapi/asm/fcntl.h > > > > > > > > index 67dae75e5274..a93d18d2c23e 100644 > > > > > > > > --- a/arch/sparc/include/uapi/asm/fcntl.h > > > > > > > > +++ b/arch/sparc/include/uapi/asm/fcntl.h > > > > > > > > @@ -37,6 +37,7 @@ > > > > > > > > > > > > > > > > #define O_PATH 0x1000000 > > > > > > > > #define __O_TMPFILE 0x2000000 > > > > > > > > +#define O_REGULAR 0x4000000 > > > > > > > > > > > > > > > > #define F_GETOWN 5 /* for sockets. */ > > > > > > > > #define F_SETOWN 6 /* for sockets. */ > > > > > > > > diff --git a/fs/fcntl.c b/fs/fcntl.c > > > > > > > > index f93dbca08435..62ab4ad2b6f5 100644 > > > > > > > > --- a/fs/fcntl.c > > > > > > > > +++ b/fs/fcntl.c > > > > > > > > @@ -1169,7 +1169,7 @@ static int __init fcntl_init(void) > > > > > > > > * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY > > > > > > > > * is defined as O_NONBLOCK on some platforms and not on others. > > > > > > > > */ > > > > > > > > - BUILD_BUG_ON(20 - 1 /* for O_RDONLY being 0 */ != > > > > > > > > + BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ != > > > > > > > > HWEIGHT32( > > > > > > > > (VALID_OPEN_FLAGS & ~(O_NONBLOCK | O_NDELAY)) | > > > > > > > > __FMODE_EXEC)); > > > > > > > > diff --git a/fs/namei.c b/fs/namei.c > > > > > > > > index b28ecb699f32..f5504ae4b03c 100644 > > > > > > > > --- a/fs/namei.c > > > > > > > > +++ b/fs/namei.c > > > > > > > > @@ -4616,6 +4616,10 @@ static int do_open(struct nameidata *nd, > > > > > > > > if (unlikely(error)) > > > > > > > > return error; > > > > > > > > } > > > > > > > > + > > > > > > > > + if ((open_flag & O_REGULAR) && !d_is_reg(nd->path.dentry)) > > > > > > > > + return -ENOTREG; > > > > > > > > + > > > > > > > > if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry)) > > > > > > > > return -ENOTDIR; > > > > > > > > > > > > > > > > @@ -4765,6 +4769,8 @@ static int do_o_path(struct nameidata *nd, unsigned flags, struct file *file) > > > > > > > > struct path path; > > > > > > > > int error = path_lookupat(nd, flags, &path); > > > > > > > > if (!error) { > > > > > > > > + if ((file->f_flags & O_REGULAR) && !d_is_reg(path.dentry)) > > > > > > > > + return -ENOTREG; > > > > > > > > audit_inode(nd->name, path.dentry, 0); > > > > > > > > error = vfs_open(&path, file); > > > > > > > > path_put(&path); > > > > > > > > diff --git a/fs/open.c b/fs/open.c > > > > > > > > index 74c4c1462b3e..82153e21907e 100644 > > > > > > > > --- a/fs/open.c > > > > > > > > +++ b/fs/open.c > > > > > > > > @@ -1173,7 +1173,7 @@ struct file *kernel_file_open(const struct path *path, int flags, > > > > > > > > EXPORT_SYMBOL_GPL(kernel_file_open); > > > > > > > > > > > > > > > > #define WILL_CREATE(flags) (flags & (O_CREAT | __O_TMPFILE)) > > > > > > > > -#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC) > > > > > > > > +#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC | O_REGULAR) > > > > > > > > > > > > > > > > inline struct open_how build_open_how(int flags, umode_t mode) > > > > > > > > { > > > > > > > > @@ -1250,6 +1250,8 @@ inline int build_open_flags(const struct open_how *how, struct open_flags *op) > > > > > > > > return -EINVAL; > > > > > > > > if (!(acc_mode & MAY_WRITE)) > > > > > > > > return -EINVAL; > > > > > > > > + } else if ((flags & O_DIRECTORY) && (flags & O_REGULAR)) { > > > > > > > > + return -EINVAL; > > > > > > > > } > > > > > > > > if (flags & O_PATH) { > > > > > > > > /* O_PATH only permits certain other flags to be set. */ > > > > > > > > diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h > > > > > > > > index a332e79b3207..4fd07b0e0a17 100644 > > > > > > > > --- a/include/linux/fcntl.h > > > > > > > > +++ b/include/linux/fcntl.h > > > > > > > > @@ -10,7 +10,7 @@ > > > > > > > > (O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | \ > > > > > > > > O_APPEND | O_NDELAY | O_NONBLOCK | __O_SYNC | O_DSYNC | \ > > > > > > > > FASYNC | O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | \ > > > > > > > > - O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE) > > > > > > > > + O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE | O_REGULAR) > > > > > > > > > > > > > > > > /* List of all valid flags for the how->resolve argument: */ > > > > > > > > #define VALID_RESOLVE_FLAGS \ > > > > > > > > diff --git a/include/uapi/asm-generic/errno.h b/include/uapi/asm-generic/errno.h > > > > > > > > index 92e7ae493ee3..2216ab9aa32e 100644 > > > > > > > > --- a/include/uapi/asm-generic/errno.h > > > > > > > > +++ b/include/uapi/asm-generic/errno.h > > > > > > > > @@ -122,4 +122,6 @@ > > > > > > > > > > > > > > > > #define EHWPOISON 133 /* Memory page has hardware error */ > > > > > > > > > > > > > > > > +#define ENOTREG 134 /* Not a regular file */ > > > > > > > > + > > > > > > > > #endif > > > > > > > > diff --git a/include/uapi/asm-generic/fcntl.h b/include/uapi/asm-generic/fcntl.h > > > > > > > > index 613475285643..3468b352a575 100644 > > > > > > > > --- a/include/uapi/asm-generic/fcntl.h > > > > > > > > +++ b/include/uapi/asm-generic/fcntl.h > > > > > > > > @@ -88,6 +88,10 @@ > > > > > > > > #define __O_TMPFILE 020000000 > > > > > > > > #endif > > > > > > > > > > > > > > > > +#ifndef O_REGULAR > > > > > > > > +#define O_REGULAR 040000000 > > > > > > > > +#endif > > > > > > > > + > > > > > > > > /* a horrid kludge trying to make sure that this will fail on old kernels */ > > > > > > > > #define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) > > > > > > > > > > > > > > > > diff --git a/tools/arch/alpha/include/uapi/asm/errno.h b/tools/arch/alpha/include/uapi/asm/errno.h > > > > > > > > index 6791f6508632..8bbcaa9024f9 100644 > > > > > > > > --- a/tools/arch/alpha/include/uapi/asm/errno.h > > > > > > > > +++ b/tools/arch/alpha/include/uapi/asm/errno.h > > > > > > > > @@ -127,4 +127,6 @@ > > > > > > > > > > > > > > > > #define EHWPOISON 139 /* Memory page has hardware error */ > > > > > > > > > > > > > > > > +#define ENOTREG 140 /* Not a regular file */ > > > > > > > > + > > > > > > > > #endif > > > > > > > > diff --git a/tools/arch/mips/include/uapi/asm/errno.h b/tools/arch/mips/include/uapi/asm/errno.h > > > > > > > > index c01ed91b1ef4..293c78777254 100644 > > > > > > > > --- a/tools/arch/mips/include/uapi/asm/errno.h > > > > > > > > +++ b/tools/arch/mips/include/uapi/asm/errno.h > > > > > > > > @@ -126,6 +126,8 @@ > > > > > > > > > > > > > > > > #define EHWPOISON 168 /* Memory page has hardware error */ > > > > > > > > > > > > > > > > +#define ENOTREG 169 /* Not a regular file */ > > > > > > > > + > > > > > > > > #define EDQUOT 1133 /* Quota exceeded */ > > > > > > > > > > > > > > > > > > > > > > > > diff --git a/tools/arch/parisc/include/uapi/asm/errno.h b/tools/arch/parisc/include/uapi/asm/errno.h > > > > > > > > index 8cbc07c1903e..442917484f99 100644 > > > > > > > > --- a/tools/arch/parisc/include/uapi/asm/errno.h > > > > > > > > +++ b/tools/arch/parisc/include/uapi/asm/errno.h > > > > > > > > @@ -124,4 +124,6 @@ > > > > > > > > > > > > > > > > #define EHWPOISON 257 /* Memory page has hardware error */ > > > > > > > > > > > > > > > > +#define ENOTREG 258 /* Not a regular file */ > > > > > > > > + > > > > > > > > #endif > > > > > > > > diff --git a/tools/arch/sparc/include/uapi/asm/errno.h b/tools/arch/sparc/include/uapi/asm/errno.h > > > > > > > > index 4a41e7835fd5..8dce0bfeab74 100644 > > > > > > > > --- a/tools/arch/sparc/include/uapi/asm/errno.h > > > > > > > > +++ b/tools/arch/sparc/include/uapi/asm/errno.h > > > > > > > > @@ -117,4 +117,6 @@ > > > > > > > > > > > > > > > > #define EHWPOISON 135 /* Memory page has hardware error */ > > > > > > > > > > > > > > > > +#define ENOTREG 136 /* Not a regular file */ > > > > > > > > + > > > > > > > > #endif > > > > > > > > diff --git a/tools/include/uapi/asm-generic/errno.h b/tools/include/uapi/asm-generic/errno.h > > > > > > > > index 92e7ae493ee3..2216ab9aa32e 100644 > > > > > > > > --- a/tools/include/uapi/asm-generic/errno.h > > > > > > > > +++ b/tools/include/uapi/asm-generic/errno.h > > > > > > > > @@ -122,4 +122,6 @@ > > > > > > > > > > > > > > > > #define EHWPOISON 133 /* Memory page has hardware error */ > > > > > > > > > > > > > > > > +#define ENOTREG 134 /* Not a regular file */ > > > > > > > > + > > > > > > > > #endif > > > > > > > > > > > > > > One thing this patch is missing is handling for ->atomic_open(). I > > > > > > > imagine most of the filesystems that provide that op can't support > > > > > > > O_REGULAR properly (maybe cifs can? idk). What you probably want to do > > > > > > > is add in some patches that make all of the atomic_open operations in > > > > > > > the kernel return -EINVAL if O_REGULAR is set. > > > > > > > > > > > > > > Then, once the basic support is in, you or someone else can go back and > > > > > > > implement support for O_REGULAR where possible. > > > > > > > > > > > > Thank you for the feedback. I don't quite understand what I need to > > > > > > fix. I thought open system calls always create regular files, so > > > > > > atomic_open probably always creates regular files? Can you please give > > > > > > me some more details as to where I need to fix this and what the > > > > > > actual bug here is that is related to atomic_open? I think I had done > > > > > > some normal testing and when using O_CREAT | O_REGULAR, if the file > > > > > > doesn't exist, the file gets created and the file that gets created is > > > > > > a regular file, so it probably makes sense? Or should the behavior be > > > > > > that if file doesn't exist, -EINVAL is returned and if file exists it > > > > > > is opened if regular, otherwise -ENOTREG is returned? > > > > > > > > > > > > > > > > atomic_open() is a combination lookup+open for when the dentry isn't > > > > > present in the dcache. The normal open codepath that you're patching > > > > > does not get called in this case when ->atomic_open is set for the > > > > > filesystem. It's mostly used by network filesystems that need to > > > > > optimize away the lookup since it's wasted round trip, and is often > > > > > racy anyway. Your patchset doesn't address those filesystems. They will > > > > > likely end up ignoring O_REGULAR in that case, which is not what you > > > > > want. > > > > > > > > > > What I was suggesting is that, as an interim step, you find all of the > > > > > atomic_open operations in the kernel (there are maybe a dozen or so), > > > > > and just make them return -EINVAL if someone sets O_DIRECTORY. Later, > > > > > you or someone else can then go back and do a proper implementation of > > > > > O_REGULAR handling on those filesystems, at least on the ones where > > > > > it's possible. You will probably also need to similarly patch the > > > > > open() routines for those filesystems too. Otherwise you'll get > > > > > inconsistent behavior vs. when the dentry is in the cache. > > > > > > > > > > One note: I think NFS probably can support O_DIRECTORY, since its OPEN > > > > > call only works on files. We'll need to change how we handle errors > > > > > from the server when it's set though. > > > > > > > > So I think you're proposing two separate things or there's a typo: > > > > > > > > (1) blocking O_DIRECTORY for ->atomic_open:: > > > > (2) blocking O_REGULAR for ->atomic_open:: > > > > > > > > The (1) point implies that O_DIRECTORY currently doesn't work correctly > > > > with atomic open for all filesystems. > > > > > > > > Ever since 43b450632676 ("open: return EINVAL for O_DIRECTORY | > > > > O_CREAT") O_DIRECTORY with O_CREAT is blocked. It was accidently allowed > > > > and completely broken before that. > > > > > > > > For O_DIRECTORY without O_CREAT the kernel will pass that down through > > > > ->atomic_open:: to the filesystem. > > > > > > > > The worry that I see is that a network filesystem via ->atomic_open:: > > > > somehow already called open on the server side on something that wasn't > > > > a directory. At that point the damage such as side-effects from device > > > > opening is already done. > > > > > > > > > > > > > > Exactly. I guess you could send an immediate close, but that's not > > > without side effects. > > > > > > > > > > > But I suspect that every filesystem implementing ->atomic_open:: just > > > > does finish_no_open() and punts to the VFS for the actual open. And the > > > > VFS will catch it in do_open() for it actually opens the file. So the > > > > only real worry for O_DIRECTORY I see is that there's an fs that handles > > > > it wrong. > > > > > > > > For (2) it is problematic as there surely are filesystems with > > > > ->atomic_open:: that do handle the ~O_CREAT case and return with > > > > FMODE_OPENED. So that'll be problematic if the intention is to not > > > > trigger an actual open on a non-regular file such as a > > > > device/socket/fifo etc. before the VFS had a chance to validate what's > > > > going on. > > > > > > > > So I'm not excited about having this 70% working and punting on > > > > ->atomic_open:: waiting for someone to fix this. One option would be to > > > > bypass ->atomic_open:: for OPENAT2_REGULAR without O_CREAT and fallback > > > > to racy and pricy lookup + open for now. How problematic would that be? > > > > If possible I'd prefer this a lot over merging something that works > > > > half-way. > > > > > > > > I guess to make that really work you'd need some protocol extension? > > > > > > For NFS, I think we're OK. The OPEN call on NFSv4 only works for > > > regular files, so it should be able to handle O_REGULAR. We just need > > > to rejigger the error handling when it's set (just return an error > > > instead of doing the open of a directory or whatever it is). > > > > > > > Thank you for the details. Do you remember which codepath this is? Is > > this the inode_operations.atomic_open codepath or file_operations.open > > codepath? I am a bit confused also about where exactly the error > > handling that needs to be done. > > > > I was thinking nfs_atomic_open(). > > Looking now, I think it might actually work OK without changes. It just > might not be terribly efficient about it. > > If the open_context() call returns -EISDIR or similar, then you really > don't need to do the call to nfs_lookup() and the like. You can just > return an immediate error when O_REGULAR is set since you know it's not > suitable to be opened. > Right. And I guess we don't need to worry about O_REGULAR being an unknown flag when it gets sent to the server (not only for NFS / but others as well)? > > > The others (at a quick glance): > > > > > > cifs: I don't see a way to specify an O_REGULAR equivalent to the > > > SMB2_CREATE call and it looks like it can create directories. Maybe > > > SteveF (cc'ed) knows if this is possible? > > > > > > ceph: I think CEPH_MDS_OP_OPEN might only work for files, in which case > > > O_REGULAR can probably be supported similarly to NFS. > > > > > > fuse: probably ok? Does finish_no_open() in most cases. May depend on > > > the userland driver though. > > > > > > gfs2: is ok, it just does finish_no_open() in most cases anyway > > > > > > vboxsf: does finish_no_open on non-creates, so you could probably just > > > punt to that if O_REGULAR is set. > > > > > > > These are all inode_operations.atomic_open code paths, right? Because > > you mentioned finish_no_open and I see finish_no_open in the > > atomic_open code paths as opposed to file_operations.open code paths. > > > > Note that this was just a cursory look. Someone will need to do a > deeper dive and test these cases. > > I think most will end up working ok, since most fall back to doing a > finish_no_open(). There may be opportunities to optimize some of these > cases though (similarly to how I mentioned with NFS). I can try to look into these and see if I can implement handling for O_REGULAR flag for these filesystems in the atomic_open code paths. Thanks for the details. Will I need to modify the corresponding file_operations.open code paths as well along with atomic_open code paths? Regards, Dorjoy ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v3 1/4] open: new O_REGULAR flag support 2026-02-18 19:19 ` Dorjoy Chowdhury @ 2026-02-18 19:32 ` Jeff Layton 2026-02-18 19:44 ` Dorjoy Chowdhury 0 siblings, 1 reply; 26+ messages in thread From: Jeff Layton @ 2026-02-18 19:32 UTC (permalink / raw) To: Dorjoy Chowdhury Cc: Christian Brauner, linux-fsdevel, linux-kernel, viro, jack, chuck.lever, alex.aring, arnd, adilger, smfrench On Thu, 2026-02-19 at 01:19 +0600, Dorjoy Chowdhury wrote: > On Thu, Feb 19, 2026 at 1:01 AM Jeff Layton <jlayton@kernel.org> wrote: > > > > On Thu, 2026-02-19 at 00:26 +0600, Dorjoy Chowdhury wrote: > > > On Thu, Jan 29, 2026 at 7:12 PM Jeff Layton <jlayton@kernel.org> wrote: > > > > > > > > On Thu, 2026-01-29 at 13:33 +0100, Christian Brauner wrote: > > > > > On Wed, Jan 28, 2026 at 10:51:07AM -0500, Jeff Layton wrote: > > > > > > On Wed, 2026-01-28 at 21:36 +0600, Dorjoy Chowdhury wrote: > > > > > > > On Wed, Jan 28, 2026 at 5:52 AM Jeff Layton <jlayton@kernel.org> wrote: > > > > > > > > > > > > > > > > On Tue, 2026-01-27 at 23:58 +0600, Dorjoy Chowdhury wrote: > > > > > > > > > This flag indicates the path should be opened if it's a regular file. > > > > > > > > > This is useful to write secure programs that want to avoid being tricked > > > > > > > > > into opening device nodes with special semantics while thinking they > > > > > > > > > operate on regular files. > > > > > > > > > > > > > > > > > > A corresponding error code ENOTREG has been introduced. For example, if > > > > > > > > > open is called on path /dev/null with O_REGULAR in the flag param, it > > > > > > > > > will return -ENOTREG. > > > > > > > > > > > > > > > > > > When used in combination with O_CREAT, either the regular file is > > > > > > > > > created, or if the path already exists, it is opened if it's a regular > > > > > > > > > file. Otherwise, -ENOTREG is returned. > > > > > > > > > > > > > > > > > > -EINVAL is returned when O_REGULAR is combined with O_DIRECTORY (not > > > > > > > > > part of O_TMPFILE) because it doesn't make sense to open a path that > > > > > > > > > is both a directory and a regular file. > > > > > > > > > > > > > > > > > > Signed-off-by: Dorjoy Chowdhury <dorjoychy111@gmail.com> > > > > > > > > > --- > > > > > > > > > arch/alpha/include/uapi/asm/errno.h | 2 ++ > > > > > > > > > arch/alpha/include/uapi/asm/fcntl.h | 1 + > > > > > > > > > arch/mips/include/uapi/asm/errno.h | 2 ++ > > > > > > > > > arch/parisc/include/uapi/asm/errno.h | 2 ++ > > > > > > > > > arch/parisc/include/uapi/asm/fcntl.h | 1 + > > > > > > > > > arch/sparc/include/uapi/asm/errno.h | 2 ++ > > > > > > > > > arch/sparc/include/uapi/asm/fcntl.h | 1 + > > > > > > > > > fs/fcntl.c | 2 +- > > > > > > > > > fs/namei.c | 6 ++++++ > > > > > > > > > fs/open.c | 4 +++- > > > > > > > > > include/linux/fcntl.h | 2 +- > > > > > > > > > include/uapi/asm-generic/errno.h | 2 ++ > > > > > > > > > include/uapi/asm-generic/fcntl.h | 4 ++++ > > > > > > > > > tools/arch/alpha/include/uapi/asm/errno.h | 2 ++ > > > > > > > > > tools/arch/mips/include/uapi/asm/errno.h | 2 ++ > > > > > > > > > tools/arch/parisc/include/uapi/asm/errno.h | 2 ++ > > > > > > > > > tools/arch/sparc/include/uapi/asm/errno.h | 2 ++ > > > > > > > > > tools/include/uapi/asm-generic/errno.h | 2 ++ > > > > > > > > > 18 files changed, 38 insertions(+), 3 deletions(-) > > > > > > > > > > > > > > > > > > diff --git a/arch/alpha/include/uapi/asm/errno.h b/arch/alpha/include/uapi/asm/errno.h > > > > > > > > > index 6791f6508632..8bbcaa9024f9 100644 > > > > > > > > > --- a/arch/alpha/include/uapi/asm/errno.h > > > > > > > > > +++ b/arch/alpha/include/uapi/asm/errno.h > > > > > > > > > @@ -127,4 +127,6 @@ > > > > > > > > > > > > > > > > > > #define EHWPOISON 139 /* Memory page has hardware error */ > > > > > > > > > > > > > > > > > > +#define ENOTREG 140 /* Not a regular file */ > > > > > > > > > + > > > > > > > > > #endif > > > > > > > > > diff --git a/arch/alpha/include/uapi/asm/fcntl.h b/arch/alpha/include/uapi/asm/fcntl.h > > > > > > > > > index 50bdc8e8a271..4da5a64c23bd 100644 > > > > > > > > > --- a/arch/alpha/include/uapi/asm/fcntl.h > > > > > > > > > +++ b/arch/alpha/include/uapi/asm/fcntl.h > > > > > > > > > @@ -34,6 +34,7 @@ > > > > > > > > > > > > > > > > > > #define O_PATH 040000000 > > > > > > > > > #define __O_TMPFILE 0100000000 > > > > > > > > > +#define O_REGULAR 0200000000 > > > > > > > > > > > > > > > > > > #define F_GETLK 7 > > > > > > > > > #define F_SETLK 8 > > > > > > > > > diff --git a/arch/mips/include/uapi/asm/errno.h b/arch/mips/include/uapi/asm/errno.h > > > > > > > > > index c01ed91b1ef4..293c78777254 100644 > > > > > > > > > --- a/arch/mips/include/uapi/asm/errno.h > > > > > > > > > +++ b/arch/mips/include/uapi/asm/errno.h > > > > > > > > > @@ -126,6 +126,8 @@ > > > > > > > > > > > > > > > > > > #define EHWPOISON 168 /* Memory page has hardware error */ > > > > > > > > > > > > > > > > > > +#define ENOTREG 169 /* Not a regular file */ > > > > > > > > > + > > > > > > > > > #define EDQUOT 1133 /* Quota exceeded */ > > > > > > > > > > > > > > > > > > > > > > > > > > > diff --git a/arch/parisc/include/uapi/asm/errno.h b/arch/parisc/include/uapi/asm/errno.h > > > > > > > > > index 8cbc07c1903e..442917484f99 100644 > > > > > > > > > --- a/arch/parisc/include/uapi/asm/errno.h > > > > > > > > > +++ b/arch/parisc/include/uapi/asm/errno.h > > > > > > > > > @@ -124,4 +124,6 @@ > > > > > > > > > > > > > > > > > > #define EHWPOISON 257 /* Memory page has hardware error */ > > > > > > > > > > > > > > > > > > +#define ENOTREG 258 /* Not a regular file */ > > > > > > > > > + > > > > > > > > > #endif > > > > > > > > > diff --git a/arch/parisc/include/uapi/asm/fcntl.h b/arch/parisc/include/uapi/asm/fcntl.h > > > > > > > > > index 03dee816cb13..0cc3320fe326 100644 > > > > > > > > > --- a/arch/parisc/include/uapi/asm/fcntl.h > > > > > > > > > +++ b/arch/parisc/include/uapi/asm/fcntl.h > > > > > > > > > @@ -19,6 +19,7 @@ > > > > > > > > > > > > > > > > > > #define O_PATH 020000000 > > > > > > > > > #define __O_TMPFILE 040000000 > > > > > > > > > +#define O_REGULAR 0100000000 > > > > > > > > > > > > > > > > > > #define F_GETLK64 8 > > > > > > > > > #define F_SETLK64 9 > > > > > > > > > diff --git a/arch/sparc/include/uapi/asm/errno.h b/arch/sparc/include/uapi/asm/errno.h > > > > > > > > > index 4a41e7835fd5..8dce0bfeab74 100644 > > > > > > > > > --- a/arch/sparc/include/uapi/asm/errno.h > > > > > > > > > +++ b/arch/sparc/include/uapi/asm/errno.h > > > > > > > > > @@ -117,4 +117,6 @@ > > > > > > > > > > > > > > > > > > #define EHWPOISON 135 /* Memory page has hardware error */ > > > > > > > > > > > > > > > > > > +#define ENOTREG 136 /* Not a regular file */ > > > > > > > > > + > > > > > > > > > #endif > > > > > > > > > diff --git a/arch/sparc/include/uapi/asm/fcntl.h b/arch/sparc/include/uapi/asm/fcntl.h > > > > > > > > > index 67dae75e5274..a93d18d2c23e 100644 > > > > > > > > > --- a/arch/sparc/include/uapi/asm/fcntl.h > > > > > > > > > +++ b/arch/sparc/include/uapi/asm/fcntl.h > > > > > > > > > @@ -37,6 +37,7 @@ > > > > > > > > > > > > > > > > > > #define O_PATH 0x1000000 > > > > > > > > > #define __O_TMPFILE 0x2000000 > > > > > > > > > +#define O_REGULAR 0x4000000 > > > > > > > > > > > > > > > > > > #define F_GETOWN 5 /* for sockets. */ > > > > > > > > > #define F_SETOWN 6 /* for sockets. */ > > > > > > > > > diff --git a/fs/fcntl.c b/fs/fcntl.c > > > > > > > > > index f93dbca08435..62ab4ad2b6f5 100644 > > > > > > > > > --- a/fs/fcntl.c > > > > > > > > > +++ b/fs/fcntl.c > > > > > > > > > @@ -1169,7 +1169,7 @@ static int __init fcntl_init(void) > > > > > > > > > * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY > > > > > > > > > * is defined as O_NONBLOCK on some platforms and not on others. > > > > > > > > > */ > > > > > > > > > - BUILD_BUG_ON(20 - 1 /* for O_RDONLY being 0 */ != > > > > > > > > > + BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ != > > > > > > > > > HWEIGHT32( > > > > > > > > > (VALID_OPEN_FLAGS & ~(O_NONBLOCK | O_NDELAY)) | > > > > > > > > > __FMODE_EXEC)); > > > > > > > > > diff --git a/fs/namei.c b/fs/namei.c > > > > > > > > > index b28ecb699f32..f5504ae4b03c 100644 > > > > > > > > > --- a/fs/namei.c > > > > > > > > > +++ b/fs/namei.c > > > > > > > > > @@ -4616,6 +4616,10 @@ static int do_open(struct nameidata *nd, > > > > > > > > > if (unlikely(error)) > > > > > > > > > return error; > > > > > > > > > } > > > > > > > > > + > > > > > > > > > + if ((open_flag & O_REGULAR) && !d_is_reg(nd->path.dentry)) > > > > > > > > > + return -ENOTREG; > > > > > > > > > + > > > > > > > > > if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry)) > > > > > > > > > return -ENOTDIR; > > > > > > > > > > > > > > > > > > @@ -4765,6 +4769,8 @@ static int do_o_path(struct nameidata *nd, unsigned flags, struct file *file) > > > > > > > > > struct path path; > > > > > > > > > int error = path_lookupat(nd, flags, &path); > > > > > > > > > if (!error) { > > > > > > > > > + if ((file->f_flags & O_REGULAR) && !d_is_reg(path.dentry)) > > > > > > > > > + return -ENOTREG; > > > > > > > > > audit_inode(nd->name, path.dentry, 0); > > > > > > > > > error = vfs_open(&path, file); > > > > > > > > > path_put(&path); > > > > > > > > > diff --git a/fs/open.c b/fs/open.c > > > > > > > > > index 74c4c1462b3e..82153e21907e 100644 > > > > > > > > > --- a/fs/open.c > > > > > > > > > +++ b/fs/open.c > > > > > > > > > @@ -1173,7 +1173,7 @@ struct file *kernel_file_open(const struct path *path, int flags, > > > > > > > > > EXPORT_SYMBOL_GPL(kernel_file_open); > > > > > > > > > > > > > > > > > > #define WILL_CREATE(flags) (flags & (O_CREAT | __O_TMPFILE)) > > > > > > > > > -#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC) > > > > > > > > > +#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC | O_REGULAR) > > > > > > > > > > > > > > > > > > inline struct open_how build_open_how(int flags, umode_t mode) > > > > > > > > > { > > > > > > > > > @@ -1250,6 +1250,8 @@ inline int build_open_flags(const struct open_how *how, struct open_flags *op) > > > > > > > > > return -EINVAL; > > > > > > > > > if (!(acc_mode & MAY_WRITE)) > > > > > > > > > return -EINVAL; > > > > > > > > > + } else if ((flags & O_DIRECTORY) && (flags & O_REGULAR)) { > > > > > > > > > + return -EINVAL; > > > > > > > > > } > > > > > > > > > if (flags & O_PATH) { > > > > > > > > > /* O_PATH only permits certain other flags to be set. */ > > > > > > > > > diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h > > > > > > > > > index a332e79b3207..4fd07b0e0a17 100644 > > > > > > > > > --- a/include/linux/fcntl.h > > > > > > > > > +++ b/include/linux/fcntl.h > > > > > > > > > @@ -10,7 +10,7 @@ > > > > > > > > > (O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | \ > > > > > > > > > O_APPEND | O_NDELAY | O_NONBLOCK | __O_SYNC | O_DSYNC | \ > > > > > > > > > FASYNC | O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | \ > > > > > > > > > - O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE) > > > > > > > > > + O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE | O_REGULAR) > > > > > > > > > > > > > > > > > > /* List of all valid flags for the how->resolve argument: */ > > > > > > > > > #define VALID_RESOLVE_FLAGS \ > > > > > > > > > diff --git a/include/uapi/asm-generic/errno.h b/include/uapi/asm-generic/errno.h > > > > > > > > > index 92e7ae493ee3..2216ab9aa32e 100644 > > > > > > > > > --- a/include/uapi/asm-generic/errno.h > > > > > > > > > +++ b/include/uapi/asm-generic/errno.h > > > > > > > > > @@ -122,4 +122,6 @@ > > > > > > > > > > > > > > > > > > #define EHWPOISON 133 /* Memory page has hardware error */ > > > > > > > > > > > > > > > > > > +#define ENOTREG 134 /* Not a regular file */ > > > > > > > > > + > > > > > > > > > #endif > > > > > > > > > diff --git a/include/uapi/asm-generic/fcntl.h b/include/uapi/asm-generic/fcntl.h > > > > > > > > > index 613475285643..3468b352a575 100644 > > > > > > > > > --- a/include/uapi/asm-generic/fcntl.h > > > > > > > > > +++ b/include/uapi/asm-generic/fcntl.h > > > > > > > > > @@ -88,6 +88,10 @@ > > > > > > > > > #define __O_TMPFILE 020000000 > > > > > > > > > #endif > > > > > > > > > > > > > > > > > > +#ifndef O_REGULAR > > > > > > > > > +#define O_REGULAR 040000000 > > > > > > > > > +#endif > > > > > > > > > + > > > > > > > > > /* a horrid kludge trying to make sure that this will fail on old kernels */ > > > > > > > > > #define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) > > > > > > > > > > > > > > > > > > diff --git a/tools/arch/alpha/include/uapi/asm/errno.h b/tools/arch/alpha/include/uapi/asm/errno.h > > > > > > > > > index 6791f6508632..8bbcaa9024f9 100644 > > > > > > > > > --- a/tools/arch/alpha/include/uapi/asm/errno.h > > > > > > > > > +++ b/tools/arch/alpha/include/uapi/asm/errno.h > > > > > > > > > @@ -127,4 +127,6 @@ > > > > > > > > > > > > > > > > > > #define EHWPOISON 139 /* Memory page has hardware error */ > > > > > > > > > > > > > > > > > > +#define ENOTREG 140 /* Not a regular file */ > > > > > > > > > + > > > > > > > > > #endif > > > > > > > > > diff --git a/tools/arch/mips/include/uapi/asm/errno.h b/tools/arch/mips/include/uapi/asm/errno.h > > > > > > > > > index c01ed91b1ef4..293c78777254 100644 > > > > > > > > > --- a/tools/arch/mips/include/uapi/asm/errno.h > > > > > > > > > +++ b/tools/arch/mips/include/uapi/asm/errno.h > > > > > > > > > @@ -126,6 +126,8 @@ > > > > > > > > > > > > > > > > > > #define EHWPOISON 168 /* Memory page has hardware error */ > > > > > > > > > > > > > > > > > > +#define ENOTREG 169 /* Not a regular file */ > > > > > > > > > + > > > > > > > > > #define EDQUOT 1133 /* Quota exceeded */ > > > > > > > > > > > > > > > > > > > > > > > > > > > diff --git a/tools/arch/parisc/include/uapi/asm/errno.h b/tools/arch/parisc/include/uapi/asm/errno.h > > > > > > > > > index 8cbc07c1903e..442917484f99 100644 > > > > > > > > > --- a/tools/arch/parisc/include/uapi/asm/errno.h > > > > > > > > > +++ b/tools/arch/parisc/include/uapi/asm/errno.h > > > > > > > > > @@ -124,4 +124,6 @@ > > > > > > > > > > > > > > > > > > #define EHWPOISON 257 /* Memory page has hardware error */ > > > > > > > > > > > > > > > > > > +#define ENOTREG 258 /* Not a regular file */ > > > > > > > > > + > > > > > > > > > #endif > > > > > > > > > diff --git a/tools/arch/sparc/include/uapi/asm/errno.h b/tools/arch/sparc/include/uapi/asm/errno.h > > > > > > > > > index 4a41e7835fd5..8dce0bfeab74 100644 > > > > > > > > > --- a/tools/arch/sparc/include/uapi/asm/errno.h > > > > > > > > > +++ b/tools/arch/sparc/include/uapi/asm/errno.h > > > > > > > > > @@ -117,4 +117,6 @@ > > > > > > > > > > > > > > > > > > #define EHWPOISON 135 /* Memory page has hardware error */ > > > > > > > > > > > > > > > > > > +#define ENOTREG 136 /* Not a regular file */ > > > > > > > > > + > > > > > > > > > #endif > > > > > > > > > diff --git a/tools/include/uapi/asm-generic/errno.h b/tools/include/uapi/asm-generic/errno.h > > > > > > > > > index 92e7ae493ee3..2216ab9aa32e 100644 > > > > > > > > > --- a/tools/include/uapi/asm-generic/errno.h > > > > > > > > > +++ b/tools/include/uapi/asm-generic/errno.h > > > > > > > > > @@ -122,4 +122,6 @@ > > > > > > > > > > > > > > > > > > #define EHWPOISON 133 /* Memory page has hardware error */ > > > > > > > > > > > > > > > > > > +#define ENOTREG 134 /* Not a regular file */ > > > > > > > > > + > > > > > > > > > #endif > > > > > > > > > > > > > > > > One thing this patch is missing is handling for ->atomic_open(). I > > > > > > > > imagine most of the filesystems that provide that op can't support > > > > > > > > O_REGULAR properly (maybe cifs can? idk). What you probably want to do > > > > > > > > is add in some patches that make all of the atomic_open operations in > > > > > > > > the kernel return -EINVAL if O_REGULAR is set. > > > > > > > > > > > > > > > > Then, once the basic support is in, you or someone else can go back and > > > > > > > > implement support for O_REGULAR where possible. > > > > > > > > > > > > > > Thank you for the feedback. I don't quite understand what I need to > > > > > > > fix. I thought open system calls always create regular files, so > > > > > > > atomic_open probably always creates regular files? Can you please give > > > > > > > me some more details as to where I need to fix this and what the > > > > > > > actual bug here is that is related to atomic_open? I think I had done > > > > > > > some normal testing and when using O_CREAT | O_REGULAR, if the file > > > > > > > doesn't exist, the file gets created and the file that gets created is > > > > > > > a regular file, so it probably makes sense? Or should the behavior be > > > > > > > that if file doesn't exist, -EINVAL is returned and if file exists it > > > > > > > is opened if regular, otherwise -ENOTREG is returned? > > > > > > > > > > > > > > > > > > > atomic_open() is a combination lookup+open for when the dentry isn't > > > > > > present in the dcache. The normal open codepath that you're patching > > > > > > does not get called in this case when ->atomic_open is set for the > > > > > > filesystem. It's mostly used by network filesystems that need to > > > > > > optimize away the lookup since it's wasted round trip, and is often > > > > > > racy anyway. Your patchset doesn't address those filesystems. They will > > > > > > likely end up ignoring O_REGULAR in that case, which is not what you > > > > > > want. > > > > > > > > > > > > What I was suggesting is that, as an interim step, you find all of the > > > > > > atomic_open operations in the kernel (there are maybe a dozen or so), > > > > > > and just make them return -EINVAL if someone sets O_DIRECTORY. Later, > > > > > > you or someone else can then go back and do a proper implementation of > > > > > > O_REGULAR handling on those filesystems, at least on the ones where > > > > > > it's possible. You will probably also need to similarly patch the > > > > > > open() routines for those filesystems too. Otherwise you'll get > > > > > > inconsistent behavior vs. when the dentry is in the cache. > > > > > > > > > > > > One note: I think NFS probably can support O_DIRECTORY, since its OPEN > > > > > > call only works on files. We'll need to change how we handle errors > > > > > > from the server when it's set though. > > > > > > > > > > So I think you're proposing two separate things or there's a typo: > > > > > > > > > > (1) blocking O_DIRECTORY for ->atomic_open:: > > > > > (2) blocking O_REGULAR for ->atomic_open:: > > > > > > > > > > The (1) point implies that O_DIRECTORY currently doesn't work correctly > > > > > with atomic open for all filesystems. > > > > > > > > > > Ever since 43b450632676 ("open: return EINVAL for O_DIRECTORY | > > > > > O_CREAT") O_DIRECTORY with O_CREAT is blocked. It was accidently allowed > > > > > and completely broken before that. > > > > > > > > > > For O_DIRECTORY without O_CREAT the kernel will pass that down through > > > > > ->atomic_open:: to the filesystem. > > > > > > > > > > The worry that I see is that a network filesystem via ->atomic_open:: > > > > > somehow already called open on the server side on something that wasn't > > > > > a directory. At that point the damage such as side-effects from device > > > > > opening is already done. > > > > > > > > > > > > > > > > > > Exactly. I guess you could send an immediate close, but that's not > > > > without side effects. > > > > > > > > > > > > > > But I suspect that every filesystem implementing ->atomic_open:: just > > > > > does finish_no_open() and punts to the VFS for the actual open. And the > > > > > VFS will catch it in do_open() for it actually opens the file. So the > > > > > only real worry for O_DIRECTORY I see is that there's an fs that handles > > > > > it wrong. > > > > > > > > > > For (2) it is problematic as there surely are filesystems with > > > > > ->atomic_open:: that do handle the ~O_CREAT case and return with > > > > > FMODE_OPENED. So that'll be problematic if the intention is to not > > > > > trigger an actual open on a non-regular file such as a > > > > > device/socket/fifo etc. before the VFS had a chance to validate what's > > > > > going on. > > > > > > > > > > So I'm not excited about having this 70% working and punting on > > > > > ->atomic_open:: waiting for someone to fix this. One option would be to > > > > > bypass ->atomic_open:: for OPENAT2_REGULAR without O_CREAT and fallback > > > > > to racy and pricy lookup + open for now. How problematic would that be? > > > > > If possible I'd prefer this a lot over merging something that works > > > > > half-way. > > > > > > > > > > I guess to make that really work you'd need some protocol extension? > > > > > > > > For NFS, I think we're OK. The OPEN call on NFSv4 only works for > > > > regular files, so it should be able to handle O_REGULAR. We just need > > > > to rejigger the error handling when it's set (just return an error > > > > instead of doing the open of a directory or whatever it is). > > > > > > > > > > Thank you for the details. Do you remember which codepath this is? Is > > > this the inode_operations.atomic_open codepath or file_operations.open > > > codepath? I am a bit confused also about where exactly the error > > > handling that needs to be done. > > > > > > > I was thinking nfs_atomic_open(). > > > > Looking now, I think it might actually work OK without changes. It just > > might not be terribly efficient about it. > > > > If the open_context() call returns -EISDIR or similar, then you really > > don't need to do the call to nfs_lookup() and the like. You can just > > return an immediate error when O_REGULAR is set since you know it's not > > suitable to be opened. > > > > Right. And I guess we don't need to worry about O_REGULAR being an > unknown flag when it gets sent to the server (not only for NFS / but > others as well)? > You shouldn't. We don't send POSIX flags in NFSv4 requests. It has its own set of flags. In the case of NFSv4, O_REGULAR is already implied in an OPEN call on the wire. OPEN only operates on regular files. > > > > The others (at a quick glance): > > > > > > > > cifs: I don't see a way to specify an O_REGULAR equivalent to the > > > > SMB2_CREATE call and it looks like it can create directories. Maybe > > > > SteveF (cc'ed) knows if this is possible? > > > > > > > > ceph: I think CEPH_MDS_OP_OPEN might only work for files, in which case > > > > O_REGULAR can probably be supported similarly to NFS. > > > > > > > > fuse: probably ok? Does finish_no_open() in most cases. May depend on > > > > the userland driver though. > > > > > > > > gfs2: is ok, it just does finish_no_open() in most cases anyway > > > > > > > > vboxsf: does finish_no_open on non-creates, so you could probably just > > > > punt to that if O_REGULAR is set. > > > > > > > > > > These are all inode_operations.atomic_open code paths, right? Because > > > you mentioned finish_no_open and I see finish_no_open in the > > > atomic_open code paths as opposed to file_operations.open code paths. > > > > > > > Note that this was just a cursory look. Someone will need to do a > > deeper dive and test these cases. > > > > I think most will end up working ok, since most fall back to doing a > > finish_no_open(). There may be opportunities to optimize some of these > > cases though (similarly to how I mentioned with NFS). > > I can try to look into these and see if I can implement handling for > O_REGULAR flag for these filesystems in the atomic_open code paths. > Thanks for the details. > > Will I need to modify the corresponding file_operations.open code > paths as well along with atomic_open code paths? > Probably not. The main thing to keep in mind is that ->open is used when we already have a dentry for the target of the open. ->atomic_open is used when we don't have one yet or the one we have has failed revalidation. If you have a valid dentry, then you should be able to satisfy the O_REGULAR check without having to call into ->open at all. -- Jeff Layton <jlayton@kernel.org> ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v3 1/4] open: new O_REGULAR flag support 2026-02-18 19:32 ` Jeff Layton @ 2026-02-18 19:44 ` Dorjoy Chowdhury 0 siblings, 0 replies; 26+ messages in thread From: Dorjoy Chowdhury @ 2026-02-18 19:44 UTC (permalink / raw) To: Jeff Layton Cc: Christian Brauner, linux-fsdevel, linux-kernel, viro, jack, chuck.lever, alex.aring, arnd, adilger, smfrench On Thu, Feb 19, 2026 at 1:32 AM Jeff Layton <jlayton@kernel.org> wrote: > > On Thu, 2026-02-19 at 01:19 +0600, Dorjoy Chowdhury wrote: > > On Thu, Feb 19, 2026 at 1:01 AM Jeff Layton <jlayton@kernel.org> wrote: > > > > > > On Thu, 2026-02-19 at 00:26 +0600, Dorjoy Chowdhury wrote: > > > > On Thu, Jan 29, 2026 at 7:12 PM Jeff Layton <jlayton@kernel.org> wrote: > > > > > > > > > > On Thu, 2026-01-29 at 13:33 +0100, Christian Brauner wrote: > > > > > > On Wed, Jan 28, 2026 at 10:51:07AM -0500, Jeff Layton wrote: > > > > > > > On Wed, 2026-01-28 at 21:36 +0600, Dorjoy Chowdhury wrote: > > > > > > > > On Wed, Jan 28, 2026 at 5:52 AM Jeff Layton <jlayton@kernel.org> wrote: > > > > > > > > > > > > > > > > > > On Tue, 2026-01-27 at 23:58 +0600, Dorjoy Chowdhury wrote: > > > > > > > > > > This flag indicates the path should be opened if it's a regular file. > > > > > > > > > > This is useful to write secure programs that want to avoid being tricked > > > > > > > > > > into opening device nodes with special semantics while thinking they > > > > > > > > > > operate on regular files. > > > > > > > > > > > > > > > > > > > > A corresponding error code ENOTREG has been introduced. For example, if > > > > > > > > > > open is called on path /dev/null with O_REGULAR in the flag param, it > > > > > > > > > > will return -ENOTREG. > > > > > > > > > > > > > > > > > > > > When used in combination with O_CREAT, either the regular file is > > > > > > > > > > created, or if the path already exists, it is opened if it's a regular > > > > > > > > > > file. Otherwise, -ENOTREG is returned. > > > > > > > > > > > > > > > > > > > > -EINVAL is returned when O_REGULAR is combined with O_DIRECTORY (not > > > > > > > > > > part of O_TMPFILE) because it doesn't make sense to open a path that > > > > > > > > > > is both a directory and a regular file. > > > > > > > > > > > > > > > > > > > > Signed-off-by: Dorjoy Chowdhury <dorjoychy111@gmail.com> > > > > > > > > > > --- > > > > > > > > > > arch/alpha/include/uapi/asm/errno.h | 2 ++ > > > > > > > > > > arch/alpha/include/uapi/asm/fcntl.h | 1 + > > > > > > > > > > arch/mips/include/uapi/asm/errno.h | 2 ++ > > > > > > > > > > arch/parisc/include/uapi/asm/errno.h | 2 ++ > > > > > > > > > > arch/parisc/include/uapi/asm/fcntl.h | 1 + > > > > > > > > > > arch/sparc/include/uapi/asm/errno.h | 2 ++ > > > > > > > > > > arch/sparc/include/uapi/asm/fcntl.h | 1 + > > > > > > > > > > fs/fcntl.c | 2 +- > > > > > > > > > > fs/namei.c | 6 ++++++ > > > > > > > > > > fs/open.c | 4 +++- > > > > > > > > > > include/linux/fcntl.h | 2 +- > > > > > > > > > > include/uapi/asm-generic/errno.h | 2 ++ > > > > > > > > > > include/uapi/asm-generic/fcntl.h | 4 ++++ > > > > > > > > > > tools/arch/alpha/include/uapi/asm/errno.h | 2 ++ > > > > > > > > > > tools/arch/mips/include/uapi/asm/errno.h | 2 ++ > > > > > > > > > > tools/arch/parisc/include/uapi/asm/errno.h | 2 ++ > > > > > > > > > > tools/arch/sparc/include/uapi/asm/errno.h | 2 ++ > > > > > > > > > > tools/include/uapi/asm-generic/errno.h | 2 ++ > > > > > > > > > > 18 files changed, 38 insertions(+), 3 deletions(-) > > > > > > > > > > > > > > > > > > > > diff --git a/arch/alpha/include/uapi/asm/errno.h b/arch/alpha/include/uapi/asm/errno.h > > > > > > > > > > index 6791f6508632..8bbcaa9024f9 100644 > > > > > > > > > > --- a/arch/alpha/include/uapi/asm/errno.h > > > > > > > > > > +++ b/arch/alpha/include/uapi/asm/errno.h > > > > > > > > > > @@ -127,4 +127,6 @@ > > > > > > > > > > > > > > > > > > > > #define EHWPOISON 139 /* Memory page has hardware error */ > > > > > > > > > > > > > > > > > > > > +#define ENOTREG 140 /* Not a regular file */ > > > > > > > > > > + > > > > > > > > > > #endif > > > > > > > > > > diff --git a/arch/alpha/include/uapi/asm/fcntl.h b/arch/alpha/include/uapi/asm/fcntl.h > > > > > > > > > > index 50bdc8e8a271..4da5a64c23bd 100644 > > > > > > > > > > --- a/arch/alpha/include/uapi/asm/fcntl.h > > > > > > > > > > +++ b/arch/alpha/include/uapi/asm/fcntl.h > > > > > > > > > > @@ -34,6 +34,7 @@ > > > > > > > > > > > > > > > > > > > > #define O_PATH 040000000 > > > > > > > > > > #define __O_TMPFILE 0100000000 > > > > > > > > > > +#define O_REGULAR 0200000000 > > > > > > > > > > > > > > > > > > > > #define F_GETLK 7 > > > > > > > > > > #define F_SETLK 8 > > > > > > > > > > diff --git a/arch/mips/include/uapi/asm/errno.h b/arch/mips/include/uapi/asm/errno.h > > > > > > > > > > index c01ed91b1ef4..293c78777254 100644 > > > > > > > > > > --- a/arch/mips/include/uapi/asm/errno.h > > > > > > > > > > +++ b/arch/mips/include/uapi/asm/errno.h > > > > > > > > > > @@ -126,6 +126,8 @@ > > > > > > > > > > > > > > > > > > > > #define EHWPOISON 168 /* Memory page has hardware error */ > > > > > > > > > > > > > > > > > > > > +#define ENOTREG 169 /* Not a regular file */ > > > > > > > > > > + > > > > > > > > > > #define EDQUOT 1133 /* Quota exceeded */ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > diff --git a/arch/parisc/include/uapi/asm/errno.h b/arch/parisc/include/uapi/asm/errno.h > > > > > > > > > > index 8cbc07c1903e..442917484f99 100644 > > > > > > > > > > --- a/arch/parisc/include/uapi/asm/errno.h > > > > > > > > > > +++ b/arch/parisc/include/uapi/asm/errno.h > > > > > > > > > > @@ -124,4 +124,6 @@ > > > > > > > > > > > > > > > > > > > > #define EHWPOISON 257 /* Memory page has hardware error */ > > > > > > > > > > > > > > > > > > > > +#define ENOTREG 258 /* Not a regular file */ > > > > > > > > > > + > > > > > > > > > > #endif > > > > > > > > > > diff --git a/arch/parisc/include/uapi/asm/fcntl.h b/arch/parisc/include/uapi/asm/fcntl.h > > > > > > > > > > index 03dee816cb13..0cc3320fe326 100644 > > > > > > > > > > --- a/arch/parisc/include/uapi/asm/fcntl.h > > > > > > > > > > +++ b/arch/parisc/include/uapi/asm/fcntl.h > > > > > > > > > > @@ -19,6 +19,7 @@ > > > > > > > > > > > > > > > > > > > > #define O_PATH 020000000 > > > > > > > > > > #define __O_TMPFILE 040000000 > > > > > > > > > > +#define O_REGULAR 0100000000 > > > > > > > > > > > > > > > > > > > > #define F_GETLK64 8 > > > > > > > > > > #define F_SETLK64 9 > > > > > > > > > > diff --git a/arch/sparc/include/uapi/asm/errno.h b/arch/sparc/include/uapi/asm/errno.h > > > > > > > > > > index 4a41e7835fd5..8dce0bfeab74 100644 > > > > > > > > > > --- a/arch/sparc/include/uapi/asm/errno.h > > > > > > > > > > +++ b/arch/sparc/include/uapi/asm/errno.h > > > > > > > > > > @@ -117,4 +117,6 @@ > > > > > > > > > > > > > > > > > > > > #define EHWPOISON 135 /* Memory page has hardware error */ > > > > > > > > > > > > > > > > > > > > +#define ENOTREG 136 /* Not a regular file */ > > > > > > > > > > + > > > > > > > > > > #endif > > > > > > > > > > diff --git a/arch/sparc/include/uapi/asm/fcntl.h b/arch/sparc/include/uapi/asm/fcntl.h > > > > > > > > > > index 67dae75e5274..a93d18d2c23e 100644 > > > > > > > > > > --- a/arch/sparc/include/uapi/asm/fcntl.h > > > > > > > > > > +++ b/arch/sparc/include/uapi/asm/fcntl.h > > > > > > > > > > @@ -37,6 +37,7 @@ > > > > > > > > > > > > > > > > > > > > #define O_PATH 0x1000000 > > > > > > > > > > #define __O_TMPFILE 0x2000000 > > > > > > > > > > +#define O_REGULAR 0x4000000 > > > > > > > > > > > > > > > > > > > > #define F_GETOWN 5 /* for sockets. */ > > > > > > > > > > #define F_SETOWN 6 /* for sockets. */ > > > > > > > > > > diff --git a/fs/fcntl.c b/fs/fcntl.c > > > > > > > > > > index f93dbca08435..62ab4ad2b6f5 100644 > > > > > > > > > > --- a/fs/fcntl.c > > > > > > > > > > +++ b/fs/fcntl.c > > > > > > > > > > @@ -1169,7 +1169,7 @@ static int __init fcntl_init(void) > > > > > > > > > > * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY > > > > > > > > > > * is defined as O_NONBLOCK on some platforms and not on others. > > > > > > > > > > */ > > > > > > > > > > - BUILD_BUG_ON(20 - 1 /* for O_RDONLY being 0 */ != > > > > > > > > > > + BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ != > > > > > > > > > > HWEIGHT32( > > > > > > > > > > (VALID_OPEN_FLAGS & ~(O_NONBLOCK | O_NDELAY)) | > > > > > > > > > > __FMODE_EXEC)); > > > > > > > > > > diff --git a/fs/namei.c b/fs/namei.c > > > > > > > > > > index b28ecb699f32..f5504ae4b03c 100644 > > > > > > > > > > --- a/fs/namei.c > > > > > > > > > > +++ b/fs/namei.c > > > > > > > > > > @@ -4616,6 +4616,10 @@ static int do_open(struct nameidata *nd, > > > > > > > > > > if (unlikely(error)) > > > > > > > > > > return error; > > > > > > > > > > } > > > > > > > > > > + > > > > > > > > > > + if ((open_flag & O_REGULAR) && !d_is_reg(nd->path.dentry)) > > > > > > > > > > + return -ENOTREG; > > > > > > > > > > + > > > > > > > > > > if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry)) > > > > > > > > > > return -ENOTDIR; > > > > > > > > > > > > > > > > > > > > @@ -4765,6 +4769,8 @@ static int do_o_path(struct nameidata *nd, unsigned flags, struct file *file) > > > > > > > > > > struct path path; > > > > > > > > > > int error = path_lookupat(nd, flags, &path); > > > > > > > > > > if (!error) { > > > > > > > > > > + if ((file->f_flags & O_REGULAR) && !d_is_reg(path.dentry)) > > > > > > > > > > + return -ENOTREG; > > > > > > > > > > audit_inode(nd->name, path.dentry, 0); > > > > > > > > > > error = vfs_open(&path, file); > > > > > > > > > > path_put(&path); > > > > > > > > > > diff --git a/fs/open.c b/fs/open.c > > > > > > > > > > index 74c4c1462b3e..82153e21907e 100644 > > > > > > > > > > --- a/fs/open.c > > > > > > > > > > +++ b/fs/open.c > > > > > > > > > > @@ -1173,7 +1173,7 @@ struct file *kernel_file_open(const struct path *path, int flags, > > > > > > > > > > EXPORT_SYMBOL_GPL(kernel_file_open); > > > > > > > > > > > > > > > > > > > > #define WILL_CREATE(flags) (flags & (O_CREAT | __O_TMPFILE)) > > > > > > > > > > -#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC) > > > > > > > > > > +#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC | O_REGULAR) > > > > > > > > > > > > > > > > > > > > inline struct open_how build_open_how(int flags, umode_t mode) > > > > > > > > > > { > > > > > > > > > > @@ -1250,6 +1250,8 @@ inline int build_open_flags(const struct open_how *how, struct open_flags *op) > > > > > > > > > > return -EINVAL; > > > > > > > > > > if (!(acc_mode & MAY_WRITE)) > > > > > > > > > > return -EINVAL; > > > > > > > > > > + } else if ((flags & O_DIRECTORY) && (flags & O_REGULAR)) { > > > > > > > > > > + return -EINVAL; > > > > > > > > > > } > > > > > > > > > > if (flags & O_PATH) { > > > > > > > > > > /* O_PATH only permits certain other flags to be set. */ > > > > > > > > > > diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h > > > > > > > > > > index a332e79b3207..4fd07b0e0a17 100644 > > > > > > > > > > --- a/include/linux/fcntl.h > > > > > > > > > > +++ b/include/linux/fcntl.h > > > > > > > > > > @@ -10,7 +10,7 @@ > > > > > > > > > > (O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | \ > > > > > > > > > > O_APPEND | O_NDELAY | O_NONBLOCK | __O_SYNC | O_DSYNC | \ > > > > > > > > > > FASYNC | O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | \ > > > > > > > > > > - O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE) > > > > > > > > > > + O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE | O_REGULAR) > > > > > > > > > > > > > > > > > > > > /* List of all valid flags for the how->resolve argument: */ > > > > > > > > > > #define VALID_RESOLVE_FLAGS \ > > > > > > > > > > diff --git a/include/uapi/asm-generic/errno.h b/include/uapi/asm-generic/errno.h > > > > > > > > > > index 92e7ae493ee3..2216ab9aa32e 100644 > > > > > > > > > > --- a/include/uapi/asm-generic/errno.h > > > > > > > > > > +++ b/include/uapi/asm-generic/errno.h > > > > > > > > > > @@ -122,4 +122,6 @@ > > > > > > > > > > > > > > > > > > > > #define EHWPOISON 133 /* Memory page has hardware error */ > > > > > > > > > > > > > > > > > > > > +#define ENOTREG 134 /* Not a regular file */ > > > > > > > > > > + > > > > > > > > > > #endif > > > > > > > > > > diff --git a/include/uapi/asm-generic/fcntl.h b/include/uapi/asm-generic/fcntl.h > > > > > > > > > > index 613475285643..3468b352a575 100644 > > > > > > > > > > --- a/include/uapi/asm-generic/fcntl.h > > > > > > > > > > +++ b/include/uapi/asm-generic/fcntl.h > > > > > > > > > > @@ -88,6 +88,10 @@ > > > > > > > > > > #define __O_TMPFILE 020000000 > > > > > > > > > > #endif > > > > > > > > > > > > > > > > > > > > +#ifndef O_REGULAR > > > > > > > > > > +#define O_REGULAR 040000000 > > > > > > > > > > +#endif > > > > > > > > > > + > > > > > > > > > > /* a horrid kludge trying to make sure that this will fail on old kernels */ > > > > > > > > > > #define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) > > > > > > > > > > > > > > > > > > > > diff --git a/tools/arch/alpha/include/uapi/asm/errno.h b/tools/arch/alpha/include/uapi/asm/errno.h > > > > > > > > > > index 6791f6508632..8bbcaa9024f9 100644 > > > > > > > > > > --- a/tools/arch/alpha/include/uapi/asm/errno.h > > > > > > > > > > +++ b/tools/arch/alpha/include/uapi/asm/errno.h > > > > > > > > > > @@ -127,4 +127,6 @@ > > > > > > > > > > > > > > > > > > > > #define EHWPOISON 139 /* Memory page has hardware error */ > > > > > > > > > > > > > > > > > > > > +#define ENOTREG 140 /* Not a regular file */ > > > > > > > > > > + > > > > > > > > > > #endif > > > > > > > > > > diff --git a/tools/arch/mips/include/uapi/asm/errno.h b/tools/arch/mips/include/uapi/asm/errno.h > > > > > > > > > > index c01ed91b1ef4..293c78777254 100644 > > > > > > > > > > --- a/tools/arch/mips/include/uapi/asm/errno.h > > > > > > > > > > +++ b/tools/arch/mips/include/uapi/asm/errno.h > > > > > > > > > > @@ -126,6 +126,8 @@ > > > > > > > > > > > > > > > > > > > > #define EHWPOISON 168 /* Memory page has hardware error */ > > > > > > > > > > > > > > > > > > > > +#define ENOTREG 169 /* Not a regular file */ > > > > > > > > > > + > > > > > > > > > > #define EDQUOT 1133 /* Quota exceeded */ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > diff --git a/tools/arch/parisc/include/uapi/asm/errno.h b/tools/arch/parisc/include/uapi/asm/errno.h > > > > > > > > > > index 8cbc07c1903e..442917484f99 100644 > > > > > > > > > > --- a/tools/arch/parisc/include/uapi/asm/errno.h > > > > > > > > > > +++ b/tools/arch/parisc/include/uapi/asm/errno.h > > > > > > > > > > @@ -124,4 +124,6 @@ > > > > > > > > > > > > > > > > > > > > #define EHWPOISON 257 /* Memory page has hardware error */ > > > > > > > > > > > > > > > > > > > > +#define ENOTREG 258 /* Not a regular file */ > > > > > > > > > > + > > > > > > > > > > #endif > > > > > > > > > > diff --git a/tools/arch/sparc/include/uapi/asm/errno.h b/tools/arch/sparc/include/uapi/asm/errno.h > > > > > > > > > > index 4a41e7835fd5..8dce0bfeab74 100644 > > > > > > > > > > --- a/tools/arch/sparc/include/uapi/asm/errno.h > > > > > > > > > > +++ b/tools/arch/sparc/include/uapi/asm/errno.h > > > > > > > > > > @@ -117,4 +117,6 @@ > > > > > > > > > > > > > > > > > > > > #define EHWPOISON 135 /* Memory page has hardware error */ > > > > > > > > > > > > > > > > > > > > +#define ENOTREG 136 /* Not a regular file */ > > > > > > > > > > + > > > > > > > > > > #endif > > > > > > > > > > diff --git a/tools/include/uapi/asm-generic/errno.h b/tools/include/uapi/asm-generic/errno.h > > > > > > > > > > index 92e7ae493ee3..2216ab9aa32e 100644 > > > > > > > > > > --- a/tools/include/uapi/asm-generic/errno.h > > > > > > > > > > +++ b/tools/include/uapi/asm-generic/errno.h > > > > > > > > > > @@ -122,4 +122,6 @@ > > > > > > > > > > > > > > > > > > > > #define EHWPOISON 133 /* Memory page has hardware error */ > > > > > > > > > > > > > > > > > > > > +#define ENOTREG 134 /* Not a regular file */ > > > > > > > > > > + > > > > > > > > > > #endif > > > > > > > > > > > > > > > > > > One thing this patch is missing is handling for ->atomic_open(). I > > > > > > > > > imagine most of the filesystems that provide that op can't support > > > > > > > > > O_REGULAR properly (maybe cifs can? idk). What you probably want to do > > > > > > > > > is add in some patches that make all of the atomic_open operations in > > > > > > > > > the kernel return -EINVAL if O_REGULAR is set. > > > > > > > > > > > > > > > > > > Then, once the basic support is in, you or someone else can go back and > > > > > > > > > implement support for O_REGULAR where possible. > > > > > > > > > > > > > > > > Thank you for the feedback. I don't quite understand what I need to > > > > > > > > fix. I thought open system calls always create regular files, so > > > > > > > > atomic_open probably always creates regular files? Can you please give > > > > > > > > me some more details as to where I need to fix this and what the > > > > > > > > actual bug here is that is related to atomic_open? I think I had done > > > > > > > > some normal testing and when using O_CREAT | O_REGULAR, if the file > > > > > > > > doesn't exist, the file gets created and the file that gets created is > > > > > > > > a regular file, so it probably makes sense? Or should the behavior be > > > > > > > > that if file doesn't exist, -EINVAL is returned and if file exists it > > > > > > > > is opened if regular, otherwise -ENOTREG is returned? > > > > > > > > > > > > > > > > > > > > > > atomic_open() is a combination lookup+open for when the dentry isn't > > > > > > > present in the dcache. The normal open codepath that you're patching > > > > > > > does not get called in this case when ->atomic_open is set for the > > > > > > > filesystem. It's mostly used by network filesystems that need to > > > > > > > optimize away the lookup since it's wasted round trip, and is often > > > > > > > racy anyway. Your patchset doesn't address those filesystems. They will > > > > > > > likely end up ignoring O_REGULAR in that case, which is not what you > > > > > > > want. > > > > > > > > > > > > > > What I was suggesting is that, as an interim step, you find all of the > > > > > > > atomic_open operations in the kernel (there are maybe a dozen or so), > > > > > > > and just make them return -EINVAL if someone sets O_DIRECTORY. Later, > > > > > > > you or someone else can then go back and do a proper implementation of > > > > > > > O_REGULAR handling on those filesystems, at least on the ones where > > > > > > > it's possible. You will probably also need to similarly patch the > > > > > > > open() routines for those filesystems too. Otherwise you'll get > > > > > > > inconsistent behavior vs. when the dentry is in the cache. > > > > > > > > > > > > > > One note: I think NFS probably can support O_DIRECTORY, since its OPEN > > > > > > > call only works on files. We'll need to change how we handle errors > > > > > > > from the server when it's set though. > > > > > > > > > > > > So I think you're proposing two separate things or there's a typo: > > > > > > > > > > > > (1) blocking O_DIRECTORY for ->atomic_open:: > > > > > > (2) blocking O_REGULAR for ->atomic_open:: > > > > > > > > > > > > The (1) point implies that O_DIRECTORY currently doesn't work correctly > > > > > > with atomic open for all filesystems. > > > > > > > > > > > > Ever since 43b450632676 ("open: return EINVAL for O_DIRECTORY | > > > > > > O_CREAT") O_DIRECTORY with O_CREAT is blocked. It was accidently allowed > > > > > > and completely broken before that. > > > > > > > > > > > > For O_DIRECTORY without O_CREAT the kernel will pass that down through > > > > > > ->atomic_open:: to the filesystem. > > > > > > > > > > > > The worry that I see is that a network filesystem via ->atomic_open:: > > > > > > somehow already called open on the server side on something that wasn't > > > > > > a directory. At that point the damage such as side-effects from device > > > > > > opening is already done. > > > > > > > > > > > > > > > > > > > > > > Exactly. I guess you could send an immediate close, but that's not > > > > > without side effects. > > > > > > > > > > > > > > > > > But I suspect that every filesystem implementing ->atomic_open:: just > > > > > > does finish_no_open() and punts to the VFS for the actual open. And the > > > > > > VFS will catch it in do_open() for it actually opens the file. So the > > > > > > only real worry for O_DIRECTORY I see is that there's an fs that handles > > > > > > it wrong. > > > > > > > > > > > > For (2) it is problematic as there surely are filesystems with > > > > > > ->atomic_open:: that do handle the ~O_CREAT case and return with > > > > > > FMODE_OPENED. So that'll be problematic if the intention is to not > > > > > > trigger an actual open on a non-regular file such as a > > > > > > device/socket/fifo etc. before the VFS had a chance to validate what's > > > > > > going on. > > > > > > > > > > > > So I'm not excited about having this 70% working and punting on > > > > > > ->atomic_open:: waiting for someone to fix this. One option would be to > > > > > > bypass ->atomic_open:: for OPENAT2_REGULAR without O_CREAT and fallback > > > > > > to racy and pricy lookup + open for now. How problematic would that be? > > > > > > If possible I'd prefer this a lot over merging something that works > > > > > > half-way. > > > > > > > > > > > > I guess to make that really work you'd need some protocol extension? > > > > > > > > > > For NFS, I think we're OK. The OPEN call on NFSv4 only works for > > > > > regular files, so it should be able to handle O_REGULAR. We just need > > > > > to rejigger the error handling when it's set (just return an error > > > > > instead of doing the open of a directory or whatever it is). > > > > > > > > > > > > > Thank you for the details. Do you remember which codepath this is? Is > > > > this the inode_operations.atomic_open codepath or file_operations.open > > > > codepath? I am a bit confused also about where exactly the error > > > > handling that needs to be done. > > > > > > > > > > I was thinking nfs_atomic_open(). > > > > > > Looking now, I think it might actually work OK without changes. It just > > > might not be terribly efficient about it. > > > > > > If the open_context() call returns -EISDIR or similar, then you really > > > don't need to do the call to nfs_lookup() and the like. You can just > > > return an immediate error when O_REGULAR is set since you know it's not > > > suitable to be opened. > > > > > > > Right. And I guess we don't need to worry about O_REGULAR being an > > unknown flag when it gets sent to the server (not only for NFS / but > > others as well)? > > > > You shouldn't. We don't send POSIX flags in NFSv4 requests. It has its > own set of flags. In the case of NFSv4, O_REGULAR is already implied in > an OPEN call on the wire. OPEN only operates on regular files. > Alright. Thanks for the details again! > > > > > The others (at a quick glance): > > > > > > > > > > cifs: I don't see a way to specify an O_REGULAR equivalent to the > > > > > SMB2_CREATE call and it looks like it can create directories. Maybe > > > > > SteveF (cc'ed) knows if this is possible? > > > > > > > > > > ceph: I think CEPH_MDS_OP_OPEN might only work for files, in which case > > > > > O_REGULAR can probably be supported similarly to NFS. > > > > > > > > > > fuse: probably ok? Does finish_no_open() in most cases. May depend on > > > > > the userland driver though. > > > > > > > > > > gfs2: is ok, it just does finish_no_open() in most cases anyway > > > > > > > > > > vboxsf: does finish_no_open on non-creates, so you could probably just > > > > > punt to that if O_REGULAR is set. > > > > > > > > > > > > > These are all inode_operations.atomic_open code paths, right? Because > > > > you mentioned finish_no_open and I see finish_no_open in the > > > > atomic_open code paths as opposed to file_operations.open code paths. > > > > > > > > > > Note that this was just a cursory look. Someone will need to do a > > > deeper dive and test these cases. > > > > > > I think most will end up working ok, since most fall back to doing a > > > finish_no_open(). There may be opportunities to optimize some of these > > > cases though (similarly to how I mentioned with NFS). > > > > I can try to look into these and see if I can implement handling for > > O_REGULAR flag for these filesystems in the atomic_open code paths. > > Thanks for the details. > > > > Will I need to modify the corresponding file_operations.open code > > paths as well along with atomic_open code paths? > > > > Probably not. > > The main thing to keep in mind is that ->open is used when we already > have a dentry for the target of the open. ->atomic_open is used when we > don't have one yet or the one we have has failed revalidation. > > If you have a valid dentry, then you should be able to satisfy the > O_REGULAR check without having to call into ->open at all. Understood. Thanks! Regards, Dorjoy ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v3 1/4] open: new O_REGULAR flag support 2026-01-29 12:33 ` Christian Brauner 2026-01-29 13:12 ` Jeff Layton @ 2026-01-29 14:01 ` Jeff Layton 1 sibling, 0 replies; 26+ messages in thread From: Jeff Layton @ 2026-01-29 14:01 UTC (permalink / raw) To: Christian Brauner Cc: Dorjoy Chowdhury, linux-fsdevel, linux-kernel, viro, jack, chuck.lever, alex.aring, arnd, adilger On Thu, 2026-01-29 at 13:33 +0100, Christian Brauner wrote: > On Wed, Jan 28, 2026 at 10:51:07AM -0500, Jeff Layton wrote: > > On Wed, 2026-01-28 at 21:36 +0600, Dorjoy Chowdhury wrote: > > > On Wed, Jan 28, 2026 at 5:52 AM Jeff Layton <jlayton@kernel.org> wrote: > > > > > > > > On Tue, 2026-01-27 at 23:58 +0600, Dorjoy Chowdhury wrote: > > > > > This flag indicates the path should be opened if it's a regular file. > > > > > This is useful to write secure programs that want to avoid being tricked > > > > > into opening device nodes with special semantics while thinking they > > > > > operate on regular files. > > > > > > > > > > A corresponding error code ENOTREG has been introduced. For example, if > > > > > open is called on path /dev/null with O_REGULAR in the flag param, it > > > > > will return -ENOTREG. > > > > > > > > > > When used in combination with O_CREAT, either the regular file is > > > > > created, or if the path already exists, it is opened if it's a regular > > > > > file. Otherwise, -ENOTREG is returned. > > > > > > > > > > -EINVAL is returned when O_REGULAR is combined with O_DIRECTORY (not > > > > > part of O_TMPFILE) because it doesn't make sense to open a path that > > > > > is both a directory and a regular file. > > > > > > > > > > Signed-off-by: Dorjoy Chowdhury <dorjoychy111@gmail.com> > > > > > --- > > > > > arch/alpha/include/uapi/asm/errno.h | 2 ++ > > > > > arch/alpha/include/uapi/asm/fcntl.h | 1 + > > > > > arch/mips/include/uapi/asm/errno.h | 2 ++ > > > > > arch/parisc/include/uapi/asm/errno.h | 2 ++ > > > > > arch/parisc/include/uapi/asm/fcntl.h | 1 + > > > > > arch/sparc/include/uapi/asm/errno.h | 2 ++ > > > > > arch/sparc/include/uapi/asm/fcntl.h | 1 + > > > > > fs/fcntl.c | 2 +- > > > > > fs/namei.c | 6 ++++++ > > > > > fs/open.c | 4 +++- > > > > > include/linux/fcntl.h | 2 +- > > > > > include/uapi/asm-generic/errno.h | 2 ++ > > > > > include/uapi/asm-generic/fcntl.h | 4 ++++ > > > > > tools/arch/alpha/include/uapi/asm/errno.h | 2 ++ > > > > > tools/arch/mips/include/uapi/asm/errno.h | 2 ++ > > > > > tools/arch/parisc/include/uapi/asm/errno.h | 2 ++ > > > > > tools/arch/sparc/include/uapi/asm/errno.h | 2 ++ > > > > > tools/include/uapi/asm-generic/errno.h | 2 ++ > > > > > 18 files changed, 38 insertions(+), 3 deletions(-) > > > > > > > > > > diff --git a/arch/alpha/include/uapi/asm/errno.h b/arch/alpha/include/uapi/asm/errno.h > > > > > index 6791f6508632..8bbcaa9024f9 100644 > > > > > --- a/arch/alpha/include/uapi/asm/errno.h > > > > > +++ b/arch/alpha/include/uapi/asm/errno.h > > > > > @@ -127,4 +127,6 @@ > > > > > > > > > > #define EHWPOISON 139 /* Memory page has hardware error */ > > > > > > > > > > +#define ENOTREG 140 /* Not a regular file */ > > > > > + > > > > > #endif > > > > > diff --git a/arch/alpha/include/uapi/asm/fcntl.h b/arch/alpha/include/uapi/asm/fcntl.h > > > > > index 50bdc8e8a271..4da5a64c23bd 100644 > > > > > --- a/arch/alpha/include/uapi/asm/fcntl.h > > > > > +++ b/arch/alpha/include/uapi/asm/fcntl.h > > > > > @@ -34,6 +34,7 @@ > > > > > > > > > > #define O_PATH 040000000 > > > > > #define __O_TMPFILE 0100000000 > > > > > +#define O_REGULAR 0200000000 > > > > > > > > > > #define F_GETLK 7 > > > > > #define F_SETLK 8 > > > > > diff --git a/arch/mips/include/uapi/asm/errno.h b/arch/mips/include/uapi/asm/errno.h > > > > > index c01ed91b1ef4..293c78777254 100644 > > > > > --- a/arch/mips/include/uapi/asm/errno.h > > > > > +++ b/arch/mips/include/uapi/asm/errno.h > > > > > @@ -126,6 +126,8 @@ > > > > > > > > > > #define EHWPOISON 168 /* Memory page has hardware error */ > > > > > > > > > > +#define ENOTREG 169 /* Not a regular file */ > > > > > + > > > > > #define EDQUOT 1133 /* Quota exceeded */ > > > > > > > > > > > > > > > diff --git a/arch/parisc/include/uapi/asm/errno.h b/arch/parisc/include/uapi/asm/errno.h > > > > > index 8cbc07c1903e..442917484f99 100644 > > > > > --- a/arch/parisc/include/uapi/asm/errno.h > > > > > +++ b/arch/parisc/include/uapi/asm/errno.h > > > > > @@ -124,4 +124,6 @@ > > > > > > > > > > #define EHWPOISON 257 /* Memory page has hardware error */ > > > > > > > > > > +#define ENOTREG 258 /* Not a regular file */ > > > > > + > > > > > #endif > > > > > diff --git a/arch/parisc/include/uapi/asm/fcntl.h b/arch/parisc/include/uapi/asm/fcntl.h > > > > > index 03dee816cb13..0cc3320fe326 100644 > > > > > --- a/arch/parisc/include/uapi/asm/fcntl.h > > > > > +++ b/arch/parisc/include/uapi/asm/fcntl.h > > > > > @@ -19,6 +19,7 @@ > > > > > > > > > > #define O_PATH 020000000 > > > > > #define __O_TMPFILE 040000000 > > > > > +#define O_REGULAR 0100000000 > > > > > > > > > > #define F_GETLK64 8 > > > > > #define F_SETLK64 9 > > > > > diff --git a/arch/sparc/include/uapi/asm/errno.h b/arch/sparc/include/uapi/asm/errno.h > > > > > index 4a41e7835fd5..8dce0bfeab74 100644 > > > > > --- a/arch/sparc/include/uapi/asm/errno.h > > > > > +++ b/arch/sparc/include/uapi/asm/errno.h > > > > > @@ -117,4 +117,6 @@ > > > > > > > > > > #define EHWPOISON 135 /* Memory page has hardware error */ > > > > > > > > > > +#define ENOTREG 136 /* Not a regular file */ > > > > > + > > > > > #endif > > > > > diff --git a/arch/sparc/include/uapi/asm/fcntl.h b/arch/sparc/include/uapi/asm/fcntl.h > > > > > index 67dae75e5274..a93d18d2c23e 100644 > > > > > --- a/arch/sparc/include/uapi/asm/fcntl.h > > > > > +++ b/arch/sparc/include/uapi/asm/fcntl.h > > > > > @@ -37,6 +37,7 @@ > > > > > > > > > > #define O_PATH 0x1000000 > > > > > #define __O_TMPFILE 0x2000000 > > > > > +#define O_REGULAR 0x4000000 > > > > > > > > > > #define F_GETOWN 5 /* for sockets. */ > > > > > #define F_SETOWN 6 /* for sockets. */ > > > > > diff --git a/fs/fcntl.c b/fs/fcntl.c > > > > > index f93dbca08435..62ab4ad2b6f5 100644 > > > > > --- a/fs/fcntl.c > > > > > +++ b/fs/fcntl.c > > > > > @@ -1169,7 +1169,7 @@ static int __init fcntl_init(void) > > > > > * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY > > > > > * is defined as O_NONBLOCK on some platforms and not on others. > > > > > */ > > > > > - BUILD_BUG_ON(20 - 1 /* for O_RDONLY being 0 */ != > > > > > + BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ != > > > > > HWEIGHT32( > > > > > (VALID_OPEN_FLAGS & ~(O_NONBLOCK | O_NDELAY)) | > > > > > __FMODE_EXEC)); > > > > > diff --git a/fs/namei.c b/fs/namei.c > > > > > index b28ecb699f32..f5504ae4b03c 100644 > > > > > --- a/fs/namei.c > > > > > +++ b/fs/namei.c > > > > > @@ -4616,6 +4616,10 @@ static int do_open(struct nameidata *nd, > > > > > if (unlikely(error)) > > > > > return error; > > > > > } > > > > > + > > > > > + if ((open_flag & O_REGULAR) && !d_is_reg(nd->path.dentry)) > > > > > + return -ENOTREG; > > > > > + > > > > > if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry)) > > > > > return -ENOTDIR; > > > > > > > > > > @@ -4765,6 +4769,8 @@ static int do_o_path(struct nameidata *nd, unsigned flags, struct file *file) > > > > > struct path path; > > > > > int error = path_lookupat(nd, flags, &path); > > > > > if (!error) { > > > > > + if ((file->f_flags & O_REGULAR) && !d_is_reg(path.dentry)) > > > > > + return -ENOTREG; > > > > > audit_inode(nd->name, path.dentry, 0); > > > > > error = vfs_open(&path, file); > > > > > path_put(&path); > > > > > diff --git a/fs/open.c b/fs/open.c > > > > > index 74c4c1462b3e..82153e21907e 100644 > > > > > --- a/fs/open.c > > > > > +++ b/fs/open.c > > > > > @@ -1173,7 +1173,7 @@ struct file *kernel_file_open(const struct path *path, int flags, > > > > > EXPORT_SYMBOL_GPL(kernel_file_open); > > > > > > > > > > #define WILL_CREATE(flags) (flags & (O_CREAT | __O_TMPFILE)) > > > > > -#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC) > > > > > +#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC | O_REGULAR) > > > > > > > > > > inline struct open_how build_open_how(int flags, umode_t mode) > > > > > { > > > > > @@ -1250,6 +1250,8 @@ inline int build_open_flags(const struct open_how *how, struct open_flags *op) > > > > > return -EINVAL; > > > > > if (!(acc_mode & MAY_WRITE)) > > > > > return -EINVAL; > > > > > + } else if ((flags & O_DIRECTORY) && (flags & O_REGULAR)) { > > > > > + return -EINVAL; > > > > > } > > > > > if (flags & O_PATH) { > > > > > /* O_PATH only permits certain other flags to be set. */ > > > > > diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h > > > > > index a332e79b3207..4fd07b0e0a17 100644 > > > > > --- a/include/linux/fcntl.h > > > > > +++ b/include/linux/fcntl.h > > > > > @@ -10,7 +10,7 @@ > > > > > (O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | \ > > > > > O_APPEND | O_NDELAY | O_NONBLOCK | __O_SYNC | O_DSYNC | \ > > > > > FASYNC | O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | \ > > > > > - O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE) > > > > > + O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE | O_REGULAR) > > > > > > > > > > /* List of all valid flags for the how->resolve argument: */ > > > > > #define VALID_RESOLVE_FLAGS \ > > > > > diff --git a/include/uapi/asm-generic/errno.h b/include/uapi/asm-generic/errno.h > > > > > index 92e7ae493ee3..2216ab9aa32e 100644 > > > > > --- a/include/uapi/asm-generic/errno.h > > > > > +++ b/include/uapi/asm-generic/errno.h > > > > > @@ -122,4 +122,6 @@ > > > > > > > > > > #define EHWPOISON 133 /* Memory page has hardware error */ > > > > > > > > > > +#define ENOTREG 134 /* Not a regular file */ > > > > > + > > > > > #endif > > > > > diff --git a/include/uapi/asm-generic/fcntl.h b/include/uapi/asm-generic/fcntl.h > > > > > index 613475285643..3468b352a575 100644 > > > > > --- a/include/uapi/asm-generic/fcntl.h > > > > > +++ b/include/uapi/asm-generic/fcntl.h > > > > > @@ -88,6 +88,10 @@ > > > > > #define __O_TMPFILE 020000000 > > > > > #endif > > > > > > > > > > +#ifndef O_REGULAR > > > > > +#define O_REGULAR 040000000 > > > > > +#endif > > > > > + > > > > > /* a horrid kludge trying to make sure that this will fail on old kernels */ > > > > > #define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) > > > > > > > > > > diff --git a/tools/arch/alpha/include/uapi/asm/errno.h b/tools/arch/alpha/include/uapi/asm/errno.h > > > > > index 6791f6508632..8bbcaa9024f9 100644 > > > > > --- a/tools/arch/alpha/include/uapi/asm/errno.h > > > > > +++ b/tools/arch/alpha/include/uapi/asm/errno.h > > > > > @@ -127,4 +127,6 @@ > > > > > > > > > > #define EHWPOISON 139 /* Memory page has hardware error */ > > > > > > > > > > +#define ENOTREG 140 /* Not a regular file */ > > > > > + > > > > > #endif > > > > > diff --git a/tools/arch/mips/include/uapi/asm/errno.h b/tools/arch/mips/include/uapi/asm/errno.h > > > > > index c01ed91b1ef4..293c78777254 100644 > > > > > --- a/tools/arch/mips/include/uapi/asm/errno.h > > > > > +++ b/tools/arch/mips/include/uapi/asm/errno.h > > > > > @@ -126,6 +126,8 @@ > > > > > > > > > > #define EHWPOISON 168 /* Memory page has hardware error */ > > > > > > > > > > +#define ENOTREG 169 /* Not a regular file */ > > > > > + > > > > > #define EDQUOT 1133 /* Quota exceeded */ > > > > > > > > > > > > > > > diff --git a/tools/arch/parisc/include/uapi/asm/errno.h b/tools/arch/parisc/include/uapi/asm/errno.h > > > > > index 8cbc07c1903e..442917484f99 100644 > > > > > --- a/tools/arch/parisc/include/uapi/asm/errno.h > > > > > +++ b/tools/arch/parisc/include/uapi/asm/errno.h > > > > > @@ -124,4 +124,6 @@ > > > > > > > > > > #define EHWPOISON 257 /* Memory page has hardware error */ > > > > > > > > > > +#define ENOTREG 258 /* Not a regular file */ > > > > > + > > > > > #endif > > > > > diff --git a/tools/arch/sparc/include/uapi/asm/errno.h b/tools/arch/sparc/include/uapi/asm/errno.h > > > > > index 4a41e7835fd5..8dce0bfeab74 100644 > > > > > --- a/tools/arch/sparc/include/uapi/asm/errno.h > > > > > +++ b/tools/arch/sparc/include/uapi/asm/errno.h > > > > > @@ -117,4 +117,6 @@ > > > > > > > > > > #define EHWPOISON 135 /* Memory page has hardware error */ > > > > > > > > > > +#define ENOTREG 136 /* Not a regular file */ > > > > > + > > > > > #endif > > > > > diff --git a/tools/include/uapi/asm-generic/errno.h b/tools/include/uapi/asm-generic/errno.h > > > > > index 92e7ae493ee3..2216ab9aa32e 100644 > > > > > --- a/tools/include/uapi/asm-generic/errno.h > > > > > +++ b/tools/include/uapi/asm-generic/errno.h > > > > > @@ -122,4 +122,6 @@ > > > > > > > > > > #define EHWPOISON 133 /* Memory page has hardware error */ > > > > > > > > > > +#define ENOTREG 134 /* Not a regular file */ > > > > > + > > > > > #endif > > > > > > > > One thing this patch is missing is handling for ->atomic_open(). I > > > > imagine most of the filesystems that provide that op can't support > > > > O_REGULAR properly (maybe cifs can? idk). What you probably want to do > > > > is add in some patches that make all of the atomic_open operations in > > > > the kernel return -EINVAL if O_REGULAR is set. > > > > > > > > Then, once the basic support is in, you or someone else can go back and > > > > implement support for O_REGULAR where possible. > > > > > > Thank you for the feedback. I don't quite understand what I need to > > > fix. I thought open system calls always create regular files, so > > > atomic_open probably always creates regular files? Can you please give > > > me some more details as to where I need to fix this and what the > > > actual bug here is that is related to atomic_open? I think I had done > > > some normal testing and when using O_CREAT | O_REGULAR, if the file > > > doesn't exist, the file gets created and the file that gets created is > > > a regular file, so it probably makes sense? Or should the behavior be > > > that if file doesn't exist, -EINVAL is returned and if file exists it > > > is opened if regular, otherwise -ENOTREG is returned? > > > > > > > atomic_open() is a combination lookup+open for when the dentry isn't > > present in the dcache. The normal open codepath that you're patching > > does not get called in this case when ->atomic_open is set for the > > filesystem. It's mostly used by network filesystems that need to > > optimize away the lookup since it's wasted round trip, and is often > > racy anyway. Your patchset doesn't address those filesystems. They will > > likely end up ignoring O_REGULAR in that case, which is not what you > > want. > > > > What I was suggesting is that, as an interim step, you find all of the > > atomic_open operations in the kernel (there are maybe a dozen or so), > > and just make them return -EINVAL if someone sets O_DIRECTORY. Later, > > you or someone else can then go back and do a proper implementation of > > O_REGULAR handling on those filesystems, at least on the ones where > > it's possible. You will probably also need to similarly patch the > > open() routines for those filesystems too. Otherwise you'll get > > inconsistent behavior vs. when the dentry is in the cache. > > > > One note: I think NFS probably can support O_DIRECTORY, since its OPEN > > call only works on files. We'll need to change how we handle errors > > from the server when it's set though. > > So I think you're proposing two separate things or there's a typo: > Oops, that was a typo. > (1) blocking O_DIRECTORY for ->atomic_open:: > (2) blocking O_REGULAR for ->atomic_open:: > > The (1) point implies that O_DIRECTORY currently doesn't work correctly > with atomic open for all filesystems. > It looks like NFS at least handles O_DIRECTORY properly. I don't have any reason to believe that O_DIRECTORY handling is broken on the others. > Ever since 43b450632676 ("open: return EINVAL for O_DIRECTORY | > O_CREAT") O_DIRECTORY with O_CREAT is blocked. It was accidently allowed > and completely broken before that. > > For O_DIRECTORY without O_CREAT the kernel will pass that down through > ->atomic_open:: to the filesystem. > > The worry that I see is that a network filesystem via ->atomic_open:: > somehow already called open on the server side on something that wasn't > a directory. At that point the damage such as side-effects from device > opening is already done. > > But I suspect that every filesystem implementing ->atomic_open:: just > does finish_no_open() and punts to the VFS for the actual open. And the > VFS will catch it in do_open() for it actually opens the file. So the > only real worry for O_DIRECTORY I see is that there's an fs that handles > it wrong. > > For (2) it is problematic as there surely are filesystems with > ->atomic_open:: that do handle the ~O_CREAT case and return with > FMODE_OPENED. So that'll be problematic if the intention is to not > trigger an actual open on a non-regular file such as a > device/socket/fifo etc. before the VFS had a chance to validate what's > going on. > > So I'm not excited about having this 70% working and punting on > ->atomic_open:: waiting for someone to fix this. One option would be to > bypass ->atomic_open:: for OPENAT2_REGULAR without O_CREAT and fallback > to racy and pricy lookup + open for now. How problematic would that be? > If possible I'd prefer this a lot over merging something that works > half-way. > > I guess to make that really work you'd need some protocol extension? -- Jeff Layton <jlayton@kernel.org> ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v3 1/4] open: new O_REGULAR flag support 2026-01-27 17:58 ` [PATCH v3 1/4] open: new O_REGULAR flag support Dorjoy Chowdhury 2026-01-27 23:23 ` Aleksa Sarai 2026-01-27 23:52 ` Jeff Layton @ 2026-01-29 10:49 ` Christian Brauner 2026-01-29 16:55 ` Dorjoy Chowdhury 2026-01-29 17:03 ` Aleksa Sarai 2 siblings, 2 replies; 26+ messages in thread From: Christian Brauner @ 2026-01-29 10:49 UTC (permalink / raw) To: Dorjoy Chowdhury Cc: linux-fsdevel, linux-kernel, viro, jack, jlayton, chuck.lever, alex.aring, arnd, adilger On Tue, Jan 27, 2026 at 11:58:17PM +0600, Dorjoy Chowdhury wrote: > This flag indicates the path should be opened if it's a regular file. > This is useful to write secure programs that want to avoid being tricked > into opening device nodes with special semantics while thinking they > operate on regular files. > > A corresponding error code ENOTREG has been introduced. For example, if > open is called on path /dev/null with O_REGULAR in the flag param, it > will return -ENOTREG. > > When used in combination with O_CREAT, either the regular file is > created, or if the path already exists, it is opened if it's a regular > file. Otherwise, -ENOTREG is returned. > > -EINVAL is returned when O_REGULAR is combined with O_DIRECTORY (not > part of O_TMPFILE) because it doesn't make sense to open a path that > is both a directory and a regular file. > > Signed-off-by: Dorjoy Chowdhury <dorjoychy111@gmail.com> > --- Yeah, we shouldn't add support for this outside of openat2(). We also shouldn't call this OEXT_* or O2_*. Let's just follow the pattern where we prefix the flag space with the name of the system call OPENAT2_REGULAR. There's also no real need to make O_DIRECTORY exclusive with OPENAT2_REGULAR. Callers could legimitately want to open a directory or regular file but not anything else. If someone wants to operate on a whole filesystem tree but only wants to interact with regular files and directories and ignore devices, sockets, fifos etc it's very handy to just be able to set both in flags. Frankly, this shouldn't be a flag at all but we already have O_DIRECTORY in there so no need to move this into a new field. Add EFTYPE as the errno code. Some of the bsds including macos already have that. ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v3 1/4] open: new O_REGULAR flag support 2026-01-29 10:49 ` Christian Brauner @ 2026-01-29 16:55 ` Dorjoy Chowdhury 2026-01-29 17:03 ` Aleksa Sarai 1 sibling, 0 replies; 26+ messages in thread From: Dorjoy Chowdhury @ 2026-01-29 16:55 UTC (permalink / raw) To: Christian Brauner Cc: linux-fsdevel, linux-kernel, viro, jack, jlayton, chuck.lever, alex.aring, arnd, adilger On Thu, Jan 29, 2026 at 4:49 PM Christian Brauner <brauner@kernel.org> wrote: > > On Tue, Jan 27, 2026 at 11:58:17PM +0600, Dorjoy Chowdhury wrote: > > This flag indicates the path should be opened if it's a regular file. > > This is useful to write secure programs that want to avoid being tricked > > into opening device nodes with special semantics while thinking they > > operate on regular files. > > > > A corresponding error code ENOTREG has been introduced. For example, if > > open is called on path /dev/null with O_REGULAR in the flag param, it > > will return -ENOTREG. > > > > When used in combination with O_CREAT, either the regular file is > > created, or if the path already exists, it is opened if it's a regular > > file. Otherwise, -ENOTREG is returned. > > > > -EINVAL is returned when O_REGULAR is combined with O_DIRECTORY (not > > part of O_TMPFILE) because it doesn't make sense to open a path that > > is both a directory and a regular file. > > > > Signed-off-by: Dorjoy Chowdhury <dorjoychy111@gmail.com> > > --- > > Yeah, we shouldn't add support for this outside of openat2(). We also > shouldn't call this OEXT_* or O2_*. Let's just follow the pattern where > we prefix the flag space with the name of the system call > OPENAT2_REGULAR. > Thanks for the feedback. I agree that OPENAT2_REGULAR is better than the other OEXT_*/O2_* options. Right now in the patch, the O_REGULAR took the next slot in all the fcntl files. Should OPENAT2_REGULAR be a bit outside of the 32bits? That way it won't take any of the regular O_* bits and we would only need to define it in include/uapi/asm-generic/fcntl.h file and not need it in arch/*/fcntl.h files. What do you think? > There's also no real need to make O_DIRECTORY exclusive with > OPENAT2_REGULAR. Callers could legimitately want to open a directory or > regular file but not anything else. If someone wants to operate on a > whole filesystem tree but only wants to interact with regular files and > directories and ignore devices, sockets, fifos etc it's very handy to > just be able to set both in flags. > > Frankly, this shouldn't be a flag at all but we already have O_DIRECTORY > in there so no need to move this into a new field. > > Add EFTYPE as the errno code. Some of the bsds including macos already > have that. Great suggestion. Will fixup in v4 submission. Regards, Dorjoy ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v3 1/4] open: new O_REGULAR flag support 2026-01-29 10:49 ` Christian Brauner 2026-01-29 16:55 ` Dorjoy Chowdhury @ 2026-01-29 17:03 ` Aleksa Sarai 2026-01-29 17:41 ` Dorjoy Chowdhury 1 sibling, 1 reply; 26+ messages in thread From: Aleksa Sarai @ 2026-01-29 17:03 UTC (permalink / raw) To: Christian Brauner Cc: Dorjoy Chowdhury, linux-fsdevel, linux-kernel, viro, jack, jlayton, chuck.lever, alex.aring, arnd, adilger [-- Attachment #1: Type: text/plain, Size: 2266 bytes --] On 2026-01-29, Christian Brauner <brauner@kernel.org> wrote: > On Tue, Jan 27, 2026 at 11:58:17PM +0600, Dorjoy Chowdhury wrote: > > This flag indicates the path should be opened if it's a regular file. > > This is useful to write secure programs that want to avoid being tricked > > into opening device nodes with special semantics while thinking they > > operate on regular files. > > > > A corresponding error code ENOTREG has been introduced. For example, if > > open is called on path /dev/null with O_REGULAR in the flag param, it > > will return -ENOTREG. > > > > When used in combination with O_CREAT, either the regular file is > > created, or if the path already exists, it is opened if it's a regular > > file. Otherwise, -ENOTREG is returned. > > > > -EINVAL is returned when O_REGULAR is combined with O_DIRECTORY (not > > part of O_TMPFILE) because it doesn't make sense to open a path that > > is both a directory and a regular file. > > > > Signed-off-by: Dorjoy Chowdhury <dorjoychy111@gmail.com> > > --- > > Yeah, we shouldn't add support for this outside of openat2(). We also > shouldn't call this OEXT_* or O2_*. Let's just follow the pattern where > we prefix the flag space with the name of the system call > OPENAT2_REGULAR. > > There's also no real need to make O_DIRECTORY exclusive with > OPENAT2_REGULAR. Callers could legimitately want to open a directory or > regular file but not anything else. If someone wants to operate on a > whole filesystem tree but only wants to interact with regular files and > directories and ignore devices, sockets, fifos etc it's very handy to > just be able to set both in flags. > > Frankly, this shouldn't be a flag at all but we already have O_DIRECTORY > in there so no need to move this into a new field. You could even say O_NOFOLLOW is kinda like that too. In my other mail I proposed a bitmask of S_IFMT to reject opening (which would let you allow FIFOs and regular files but block devices, etc). Unfortunately I forgot that S_IFBLK is S_IFCHR|S_IFDIR. This isn't fatal to the idea but it kinda sucks. Grr. > Add EFTYPE as the errno code. Some of the bsds including macos already > have that. -- Aleksa Sarai https://www.cyphar.com/ [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 265 bytes --] ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v3 1/4] open: new O_REGULAR flag support 2026-01-29 17:03 ` Aleksa Sarai @ 2026-01-29 17:41 ` Dorjoy Chowdhury 0 siblings, 0 replies; 26+ messages in thread From: Dorjoy Chowdhury @ 2026-01-29 17:41 UTC (permalink / raw) To: Aleksa Sarai Cc: Christian Brauner, linux-fsdevel, linux-kernel, viro, jack, jlayton, chuck.lever, alex.aring, arnd, adilger On Thu, Jan 29, 2026 at 11:03 PM Aleksa Sarai <cyphar@cyphar.com> wrote: > > On 2026-01-29, Christian Brauner <brauner@kernel.org> wrote: > > On Tue, Jan 27, 2026 at 11:58:17PM +0600, Dorjoy Chowdhury wrote: > > > This flag indicates the path should be opened if it's a regular file. > > > This is useful to write secure programs that want to avoid being tricked > > > into opening device nodes with special semantics while thinking they > > > operate on regular files. > > > > > > A corresponding error code ENOTREG has been introduced. For example, if > > > open is called on path /dev/null with O_REGULAR in the flag param, it > > > will return -ENOTREG. > > > > > > When used in combination with O_CREAT, either the regular file is > > > created, or if the path already exists, it is opened if it's a regular > > > file. Otherwise, -ENOTREG is returned. > > > > > > -EINVAL is returned when O_REGULAR is combined with O_DIRECTORY (not > > > part of O_TMPFILE) because it doesn't make sense to open a path that > > > is both a directory and a regular file. > > > > > > Signed-off-by: Dorjoy Chowdhury <dorjoychy111@gmail.com> > > > --- > > > > Yeah, we shouldn't add support for this outside of openat2(). We also > > shouldn't call this OEXT_* or O2_*. Let's just follow the pattern where > > we prefix the flag space with the name of the system call > > OPENAT2_REGULAR. > > > > There's also no real need to make O_DIRECTORY exclusive with > > OPENAT2_REGULAR. Callers could legimitately want to open a directory or > > regular file but not anything else. If someone wants to operate on a > > whole filesystem tree but only wants to interact with regular files and > > directories and ignore devices, sockets, fifos etc it's very handy to > > just be able to set both in flags. > > > > Frankly, this shouldn't be a flag at all but we already have O_DIRECTORY > > in there so no need to move this into a new field. > > You could even say O_NOFOLLOW is kinda like that too. > > In my other mail I proposed a bitmask of S_IFMT to reject opening (which > would let you allow FIFOs and regular files but block devices, etc). > Unfortunately I forgot that S_IFBLK is S_IFCHR|S_IFDIR. This isn't fatal > to the idea but it kinda sucks. Grr. > It is a good suggestion. I guess we can still introduce a new how->sfmt_allow field and have new bits (instead of keeping in sync with S_IF* ones) that allow types and just start with regular file allow bit for now, right? But I guess it would be cumbersome for users as an api to use different bits? Regards, Dorjoy ^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v3 2/4] kselftest/openat2: test for O_REGULAR flag 2026-01-27 17:58 [PATCH v3 0/4] O_REGULAR flag support for open Dorjoy Chowdhury 2026-01-27 17:58 ` [PATCH v3 1/4] open: new O_REGULAR flag support Dorjoy Chowdhury @ 2026-01-27 17:58 ` Dorjoy Chowdhury 2026-01-27 17:58 ` [PATCH v3 3/4] sparc/fcntl.h: convert O_* flag macros from hex to octal Dorjoy Chowdhury 2026-01-27 17:58 ` [PATCH v3 4/4] mips/fcntl.h: " Dorjoy Chowdhury 3 siblings, 0 replies; 26+ messages in thread From: Dorjoy Chowdhury @ 2026-01-27 17:58 UTC (permalink / raw) To: linux-fsdevel Cc: linux-kernel, viro, brauner, jack, jlayton, chuck.lever, alex.aring, arnd, adilger Just a happy path test. Signed-off-by: Dorjoy Chowdhury <dorjoychy111@gmail.com> --- .../testing/selftests/openat2/openat2_test.c | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/openat2/openat2_test.c b/tools/testing/selftests/openat2/openat2_test.c index 0e161ef9e9e4..011ebc9af4e5 100644 --- a/tools/testing/selftests/openat2/openat2_test.c +++ b/tools/testing/selftests/openat2/openat2_test.c @@ -320,8 +320,42 @@ void test_openat2_flags(void) } } +#ifndef O_REGULAR +#define O_REGULAR 040000000 +#endif + +#ifndef ENOTREG +#define ENOTREG 134 +#endif + +void test_openat2_o_regular_flag(void) +{ + if (!openat2_supported) { + ksft_test_result_skip("Skipping %s as openat2 is not supported\n", __func__); + return; + } + + struct open_how how = { + .flags = O_REGULAR | O_RDONLY + }; + + int fd = sys_openat2(AT_FDCWD, "/dev/null", &how); + + if (fd == ENOENT) { + ksft_test_result_skip("Skipping %s as there is no /dev/null\n", __func__); + return; + } + + if (fd != -ENOTREG) { + ksft_test_result_fail("openat2 should return ENOTREG\n"); + return; + } + + ksft_test_result_pass("%s succeeded\n", __func__); +} + #define NUM_TESTS (NUM_OPENAT2_STRUCT_VARIATIONS * NUM_OPENAT2_STRUCT_TESTS + \ - NUM_OPENAT2_FLAG_TESTS) + NUM_OPENAT2_FLAG_TESTS + 1) int main(int argc, char **argv) { @@ -330,6 +364,7 @@ int main(int argc, char **argv) test_openat2_struct(); test_openat2_flags(); + test_openat2_o_regular_flag(); if (ksft_get_fail_cnt() + ksft_get_error_cnt() > 0) ksft_exit_fail(); -- 2.52.0 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 3/4] sparc/fcntl.h: convert O_* flag macros from hex to octal 2026-01-27 17:58 [PATCH v3 0/4] O_REGULAR flag support for open Dorjoy Chowdhury 2026-01-27 17:58 ` [PATCH v3 1/4] open: new O_REGULAR flag support Dorjoy Chowdhury 2026-01-27 17:58 ` [PATCH v3 2/4] kselftest/openat2: test for O_REGULAR flag Dorjoy Chowdhury @ 2026-01-27 17:58 ` Dorjoy Chowdhury 2026-01-27 17:58 ` [PATCH v3 4/4] mips/fcntl.h: " Dorjoy Chowdhury 3 siblings, 0 replies; 26+ messages in thread From: Dorjoy Chowdhury @ 2026-01-27 17:58 UTC (permalink / raw) To: linux-fsdevel Cc: linux-kernel, viro, brauner, jack, jlayton, chuck.lever, alex.aring, arnd, adilger Following the convention in include/uapi/asm-generic/fcntl.h and other architecture specific arch/*/include/uapi/asm/fcntl.h files. Signed-off-by: Dorjoy Chowdhury <dorjoychy111@gmail.com> --- arch/sparc/include/uapi/asm/fcntl.h | 36 ++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/arch/sparc/include/uapi/asm/fcntl.h b/arch/sparc/include/uapi/asm/fcntl.h index a93d18d2c23e..3c16f1a66a6a 100644 --- a/arch/sparc/include/uapi/asm/fcntl.h +++ b/arch/sparc/include/uapi/asm/fcntl.h @@ -2,23 +2,23 @@ #ifndef _SPARC_FCNTL_H #define _SPARC_FCNTL_H -#define O_APPEND 0x0008 -#define FASYNC 0x0040 /* fcntl, for BSD compatibility */ -#define O_CREAT 0x0200 /* not fcntl */ -#define O_TRUNC 0x0400 /* not fcntl */ -#define O_EXCL 0x0800 /* not fcntl */ -#define O_DSYNC 0x2000 /* used to be O_SYNC, see below */ -#define O_NONBLOCK 0x4000 +#define O_APPEND 0000000010 +#define FASYNC 0000000100 /* fcntl, for BSD compatibility */ +#define O_CREAT 0000001000 /* not fcntl */ +#define O_TRUNC 0000002000 /* not fcntl */ +#define O_EXCL 0000004000 /* not fcntl */ +#define O_DSYNC 0000020000 /* used to be O_SYNC, see below */ +#define O_NONBLOCK 0000040000 #if defined(__sparc__) && defined(__arch64__) -#define O_NDELAY 0x0004 +#define O_NDELAY 0000000004 #else -#define O_NDELAY (0x0004 | O_NONBLOCK) +#define O_NDELAY (0000000004 | O_NONBLOCK) #endif -#define O_NOCTTY 0x8000 /* not fcntl */ -#define O_LARGEFILE 0x40000 -#define O_DIRECT 0x100000 /* direct disk access hint */ -#define O_NOATIME 0x200000 -#define O_CLOEXEC 0x400000 +#define O_NOCTTY 0000100000 /* not fcntl */ +#define O_LARGEFILE 0001000000 +#define O_DIRECT 0004000000 /* direct disk access hint */ +#define O_NOATIME 0010000000 +#define O_CLOEXEC 0020000000 /* * Before Linux 2.6.33 only O_DSYNC semantics were implemented, but using * the O_SYNC flag. We continue to use the existing numerical value @@ -32,12 +32,12 @@ * * Note: __O_SYNC must never be used directly. */ -#define __O_SYNC 0x800000 +#define __O_SYNC 0040000000 #define O_SYNC (__O_SYNC|O_DSYNC) -#define O_PATH 0x1000000 -#define __O_TMPFILE 0x2000000 -#define O_REGULAR 0x4000000 +#define O_PATH 0100000000 +#define __O_TMPFILE 0200000000 +#define O_REGULAR 0400000000 #define F_GETOWN 5 /* for sockets. */ #define F_SETOWN 6 /* for sockets. */ -- 2.52.0 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v3 4/4] mips/fcntl.h: convert O_* flag macros from hex to octal 2026-01-27 17:58 [PATCH v3 0/4] O_REGULAR flag support for open Dorjoy Chowdhury ` (2 preceding siblings ...) 2026-01-27 17:58 ` [PATCH v3 3/4] sparc/fcntl.h: convert O_* flag macros from hex to octal Dorjoy Chowdhury @ 2026-01-27 17:58 ` Dorjoy Chowdhury 3 siblings, 0 replies; 26+ messages in thread From: Dorjoy Chowdhury @ 2026-01-27 17:58 UTC (permalink / raw) To: linux-fsdevel Cc: linux-kernel, viro, brauner, jack, jlayton, chuck.lever, alex.aring, arnd, adilger Following the convention in include/uapi/asm-generic/fcntl.h and other architecture specific arch/*/include/uapi/asm/fcntl.h files. Signed-off-by: Dorjoy Chowdhury <dorjoychy111@gmail.com> --- arch/mips/include/uapi/asm/fcntl.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/arch/mips/include/uapi/asm/fcntl.h b/arch/mips/include/uapi/asm/fcntl.h index 0369a38e3d4f..6aa3f49df17e 100644 --- a/arch/mips/include/uapi/asm/fcntl.h +++ b/arch/mips/include/uapi/asm/fcntl.h @@ -11,15 +11,15 @@ #include <asm/sgidefs.h> -#define O_APPEND 0x0008 -#define O_DSYNC 0x0010 /* used to be O_SYNC, see below */ -#define O_NONBLOCK 0x0080 -#define O_CREAT 0x0100 /* not fcntl */ -#define O_TRUNC 0x0200 /* not fcntl */ -#define O_EXCL 0x0400 /* not fcntl */ -#define O_NOCTTY 0x0800 /* not fcntl */ -#define FASYNC 0x1000 /* fcntl, for BSD compatibility */ -#define O_LARGEFILE 0x2000 /* allow large file opens */ +#define O_APPEND 0000010 +#define O_DSYNC 0000020 /* used to be O_SYNC, see below */ +#define O_NONBLOCK 0000200 +#define O_CREAT 0000400 /* not fcntl */ +#define O_TRUNC 0001000 /* not fcntl */ +#define O_EXCL 0002000 /* not fcntl */ +#define O_NOCTTY 0004000 /* not fcntl */ +#define FASYNC 0010000 /* fcntl, for BSD compatibility */ +#define O_LARGEFILE 0020000 /* allow large file opens */ /* * Before Linux 2.6.33 only O_DSYNC semantics were implemented, but using * the O_SYNC flag. We continue to use the existing numerical value @@ -33,9 +33,9 @@ * * Note: __O_SYNC must never be used directly. */ -#define __O_SYNC 0x4000 +#define __O_SYNC 0040000 #define O_SYNC (__O_SYNC|O_DSYNC) -#define O_DIRECT 0x8000 /* direct disk access hint */ +#define O_DIRECT 0100000 /* direct disk access hint */ #define F_GETLK 14 #define F_SETLK 6 -- 2.52.0 ^ permalink raw reply related [flat|nested] 26+ messages in thread
end of thread, other threads:[~2026-02-18 19:44 UTC | newest] Thread overview: 26+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-01-27 17:58 [PATCH v3 0/4] O_REGULAR flag support for open Dorjoy Chowdhury 2026-01-27 17:58 ` [PATCH v3 1/4] open: new O_REGULAR flag support Dorjoy Chowdhury 2026-01-27 23:23 ` Aleksa Sarai 2026-01-28 7:12 ` Mateusz Guzik 2026-01-28 16:57 ` Dorjoy Chowdhury 2026-01-28 19:26 ` Aleksa Sarai 2026-01-27 23:52 ` Jeff Layton 2026-01-28 15:36 ` Dorjoy Chowdhury 2026-01-28 15:51 ` Jeff Layton 2026-01-28 16:29 ` Dorjoy Chowdhury 2026-01-29 12:33 ` Christian Brauner 2026-01-29 13:12 ` Jeff Layton 2026-01-29 13:42 ` Jeff Layton 2026-02-18 18:26 ` Dorjoy Chowdhury 2026-02-18 19:01 ` Jeff Layton 2026-02-18 19:19 ` Dorjoy Chowdhury 2026-02-18 19:32 ` Jeff Layton 2026-02-18 19:44 ` Dorjoy Chowdhury 2026-01-29 14:01 ` Jeff Layton 2026-01-29 10:49 ` Christian Brauner 2026-01-29 16:55 ` Dorjoy Chowdhury 2026-01-29 17:03 ` Aleksa Sarai 2026-01-29 17:41 ` Dorjoy Chowdhury 2026-01-27 17:58 ` [PATCH v3 2/4] kselftest/openat2: test for O_REGULAR flag Dorjoy Chowdhury 2026-01-27 17:58 ` [PATCH v3 3/4] sparc/fcntl.h: convert O_* flag macros from hex to octal Dorjoy Chowdhury 2026-01-27 17:58 ` [PATCH v3 4/4] mips/fcntl.h: " Dorjoy Chowdhury
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox