diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index b6cd3fbd7837..2860ab3ccc6b 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -300,7 +300,7 @@ static int ovl_set_size(struct ovl_fs *ofs, .ia_size = stat->size, }; - return notify_change(&init_user_ns, upperdentry, &attr, NULL); + return ovl_do_notify_change(ofs, upperdentry, &attr); } static int ovl_set_timestamps(struct ovl_fs *ofs, struct dentry *upperdentry, @@ -313,7 +313,7 @@ static int ovl_set_timestamps(struct ovl_fs *ofs, struct dentry *upperdentry, .ia_mtime = stat->mtime, }; - return notify_change(&init_user_ns, upperdentry, &attr, NULL); + return ovl_do_notify_change(ofs, upperdentry, &attr); } int ovl_set_attr(struct ovl_fs *ofs, struct dentry *upperdentry, @@ -326,7 +326,7 @@ int ovl_set_attr(struct ovl_fs *ofs, struct dentry *upperdentry, .ia_valid = ATTR_MODE, .ia_mode = stat->mode, }; - err = notify_change(&init_user_ns, upperdentry, &attr, NULL); + err = ovl_do_notify_change(ofs, upperdentry, &attr); } if (!err) { struct iattr attr = { @@ -334,7 +334,7 @@ int ovl_set_attr(struct ovl_fs *ofs, struct dentry *upperdentry, .ia_uid = stat->uid, .ia_gid = stat->gid, }; - err = notify_change(&init_user_ns, upperdentry, &attr, NULL); + err = ovl_do_notify_change(ofs, upperdentry, &attr); } if (!err) ovl_set_timestamps(ofs, upperdentry, stat); diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index 3a870bc8366c..8f7917474ee2 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -514,7 +514,7 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode, .ia_mode = cattr->mode, }; inode_lock(newdentry->d_inode); - err = notify_change(&init_user_ns, newdentry, &attr, NULL); + err = ovl_do_notify_change(ofs, newdentry, &attr); inode_unlock(newdentry->d_inode); if (err) goto out_cleanup; diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index 40210d6d451d..4527bb8d52ea 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -21,6 +21,7 @@ int ovl_setattr(struct user_namespace *mnt_userns, struct dentry *dentry, struct iattr *attr) { int err; + struct ovl_fs *ofs = OVL_FS(dentry->d_sb); bool full_copy_up = false; struct dentry *upperdentry; const struct cred *old_cred; @@ -77,7 +78,7 @@ int ovl_setattr(struct user_namespace *mnt_userns, struct dentry *dentry, inode_lock(upperdentry->d_inode); old_cred = ovl_override_creds(dentry->d_sb); - err = notify_change(&init_user_ns, upperdentry, attr, NULL); + err = ovl_do_notify_change(ofs, upperdentry, attr); revert_creds(old_cred); if (!err) ovl_copyattr(upperdentry->d_inode, dentry->d_inode); diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index d6405c2046ed..bc81f279b170 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -122,6 +122,35 @@ static inline const char *ovl_xattr(struct ovl_fs *ofs, enum ovl_xattr ox) return ovl_xattr_table[ox][ofs->config.userxattr]; } +/* + * When changing ownership of an upper object map the intended ownership + * according to the upper layer's idmapping. When an upper mount idmaps files + * that are stored on-disk as owned by id 1001 to id 1000 this means stat on + * this object will report it as being owned by id 1000 when calling stat via + * the upper mount. + * In order to change ownership of an object so stat reports id 1000 when + * called on an idmapped upper mount the value written to disk - i.e., the + * value stored in ia_*id - must 1001. The mount mapping helper will thus take + * care to map 1000 to 1001. + * The mnt idmapping helpers are nops if the upper layer isn't idmapped. + */ +static inline int ovl_do_notify_change(struct ovl_fs *ofs, + struct dentry *upperdentry, + struct iattr *attr) +{ + struct user_namespace *upper_mnt_userns = ovl_upper_mnt_userns(ofs); + struct user_namespace *fs_userns = i_user_ns(d_inode(upperdentry)); + + if (attr->ia_valid & ATTR_UID) + attr->ia_uid = mapped_kuid_user(upper_mnt_userns, + fs_userns, attr->ia_uid); + if (attr->ia_valid & ATTR_GID) + attr->ia_gid = mapped_kgid_user(upper_mnt_userns, + fs_userns, attr->ia_gid); + + return notify_change(upper_mnt_userns, upperdentry, attr, NULL); +} + static inline int ovl_do_rmdir(struct ovl_fs *ofs, struct inode *dir, struct dentry *dentry) { diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 307a36af7b4f..432ef060d2ab 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -821,7 +821,7 @@ retry: /* Clear any inherited mode bits */ inode_lock(work->d_inode); - err = notify_change(&init_user_ns, work, &attr, NULL); + err = ovl_do_notify_change(ofs, work, &attr); inode_unlock(work->d_inode); if (err) goto out_dput;