FAILED: patch "[PATCH] ovl: Use ovl mounter's fsuid and fsgid in ovl_link()" failed to apply to 4.14-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 4.14-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
Possible dependencies:
5b0db51215e8 ("ovl: Use ovl mounter's fsuid and fsgid in ovl_link()") 471ec5dcf4e7 ("ovl: struct cattr cleanups")6cf00764b008 ("ovl: strip debug argument from ovl_do_ helpers") e7dd0e71348c ("ovl: whiteout index when union nlink drops to zero") 016b720f5558 ("ovl: index directories on copy up for NFS export") fbd2d2074bde ("ovl: index all non-dir on copy up for NFS export") 24b33ee104ec ("ovl: create ovl_need_index() helper")
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 5b0db51215e895a361bc63132caa7cca36a53d6a Mon Sep 17 00:00:00 2001
From: Zhang Tianci <[email protected]>
Date: Thu, 1 Sep 2022 16:29:29 +0800
Subject: [PATCH] ovl: Use ovl mounter's fsuid and fsgid in ovl_link()
There is a wrong case of link() on overlay:
$ mkdir /lower /fuse /merge
$ mount -t fuse /fuse
$ mkdir /fuse/upper /fuse/work
$ mount -t overlay /merge -o lowerdir=/lower,upperdir=/fuse/upper,\
workdir=work
$ touch /merge/file
$ chown bin.bin /merge/file // the file's caller becomes "bin"
$ ln /merge/file /merge/lnkfileThen we will get an error(EACCES) because fuse daemon checks the link()'s caller is "bin", it denied this request.
In the changing history of ovl_link(), there are two key commits:
The first is commit bb0d2b8ad296 ("ovl: fix sgid on directory") which overrides the cred's fsuid/fsgid using the new inode. The new inode's owner is initialized by inode_init_owner(), and inode->fsuid is assigned to the current user. So the override fsuid becomes the current user. We know link() is actually modifying the directory, so the caller must have the MAY_WRITE permission on the directory. The current caller may should have this permission. This is acceptable to use the caller's fsuid.
The second is commit 51f7e52dc943 ("ovl: share inode for hard link") which removed the inode creation in ovl_link(). This commit move inode_init_owner() into ovl_create_object(), so the ovl_link() just give the old inode to ovl_create_or_link(). Then the override fsuid becomes the old inode's fsuid, neither the caller nor the overlay's mounter! So this is incorrect.
Fix this bug by using ovl mounter's fsuid/fsgid to do underlying fs's link().
fs/overlayfs/dir.c +30 -16
@@ -592,28 +592,42 @@ static int ovl_create_or_link(struct dentry *dentry, struct inode *inode, goto out_revert_creds; } - err = -ENOMEM ; - override_cred =prepare_creds (); -if (override_cred) { +if (!attr->hardlink) { + err = -ENOMEM ; + override_cred =prepare_creds (); +if (!override_cred) + goto out_revert_creds; +/* +* In the creation cases(create, mkdir, mknod, symlink), +* ovl should transfer current's fs{u,g}id to underlying +* fs. Because underlying fs want to initialize its new +* inode owner using current's fs{u,g}id. And in this +* case, the @inode is a new inode that is initialized +* in inode_init_owner() to current's fs{u,g}id. So use +* the inode's i_{u,g}id to override the cred's fs{u,g}id. +* +* But in the other hardlink case, ovl_link() does not +* create a new inode, so just use the ovl mounter's +* fs{u,g}id. +*/ override_cred->fsuid = inode->i_uid; override_cred->fsgid = inode->i_gid; -if (!attr->hardlink) { - err =security_dentry_create_files_as (dentry, - attr->mode, &dentry->d_name, old_cred, - override_cred); -if (err) { -put_cred (override_cred); - goto out_revert_creds; - } + err =security_dentry_create_files_as (dentry, + attr->mode, &dentry->d_name, old_cred, + override_cred); +if (err) { +put_cred (override_cred); + goto out_revert_creds; }put_cred (override_creds (override_cred));put_cred (override_cred); - -if (!ovl_dentry_is_whiteout (dentry)) - err =ovl_create_upper (dentry, inode, attr); -else - err =ovl_create_over_whiteout (dentry, inode, attr); } + +if (!ovl_dentry_is_whiteout (dentry)) + err =ovl_create_upper (dentry, inode, attr); +else + err =ovl_create_over_whiteout (dentry, inode, attr); + out_revert_creds:revert_creds (old_cred);return err;