From: Al Viro viro@zeniv.linux.org.uk
[ Upstream commit fe91e078b60d1beabf5cef4a37c848457a6d2dfb ]
... allowing any ->lookup() return value to be passed to it.
Reviewed-by: NeilBrown neil@brown.name Signed-off-by: Al Viro viro@zeniv.linux.org.uk Signed-off-by: Sasha Levin sashal@kernel.org ---
LLM Generated explanations, may be completely bogus:
YES – this commit closes a real VFS bug that lets `finish_no_open()` report success after being handed an `ERR_PTR`, so it needs to go to stable.
- `fs/open.c:1072-1077` now returns `PTR_ERR(dentry)` when `dentry` encodes an error, instead of stashing that poison pointer in `file->__f_path` and reporting success. This is the core fix. - Without it, any filesystem that forwards a `->lookup()` result straight into `finish_no_open()`—for example FUSE (`fs/fuse/dir.c:746-753`), CIFS/SMB (`fs/smb/client/dir.c:488-496`), NFS (`fs/nfs/dir.c:2174-2201`), 9p, Ceph, vboxsf—will propagate negative dentries as if they were successes. `atomic_open()` then dereferences the bogus pointer in its success path (`fs/namei.c:3668-3673`), leading to immediate crashes on routine errors like `-EACCES`, `-EIO`, or allocation failures. - The documentation update in `fs/open.c:1061-1070` captures the intended ABI: `finish_no_open()` must accept every `->lookup()` return value (valid, `NULL`, or `ERR_PTR`). The previous implementation violated that contract, so this is a bugfix, not a feature change. - Risk is minimal: the change is self-contained, touches no callers, and simply short-circuits on the already-known error condition. Backporting does not require the later “simplify …atomic_open” cleanups; it just hardens the exported helper so existing stable code can’t corrupt `file->f_path`.
Natural follow-up: run the usual filesystem open/lookup regression tests (especially on FUSE/CIFS/NFS) after picking the patch.
fs/open.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/fs/open.c b/fs/open.c index 9655158c38853..4890b13461c7b 100644 --- a/fs/open.c +++ b/fs/open.c @@ -1059,18 +1059,20 @@ EXPORT_SYMBOL(finish_open); * finish_no_open - finish ->atomic_open() without opening the file * * @file: file pointer - * @dentry: dentry or NULL (as returned from ->lookup()) + * @dentry: dentry, ERR_PTR(-E...) or NULL (as returned from ->lookup()) * - * This can be used to set the result of a successful lookup in ->atomic_open(). + * This can be used to set the result of a lookup in ->atomic_open(). * * NB: unlike finish_open() this function does consume the dentry reference and * the caller need not dput() it. * - * Returns "0" which must be the return value of ->atomic_open() after having - * called this function. + * Returns 0 or -E..., which must be the return value of ->atomic_open() after + * having called this function. */ int finish_no_open(struct file *file, struct dentry *dentry) { + if (IS_ERR(dentry)) + return PTR_ERR(dentry); file->f_path.dentry = dentry; return 0; }