Skip to content

Commit da1e7ad

Browse files
Christian Braunersmfrench
authored andcommitted
ksmbd: fix lookup on idmapped mounts
It's great that the new in-kernel ksmbd server will support idmapped mounts out of the box! However, lookup is currently broken. Lookup helpers such as lookup_one_len() call inode_permission() internally to ensure that the caller is privileged over the inode of the base dentry they are trying to lookup under. So the permission checking here is currently wrong. Linux v5.15 will gain a new lookup helper lookup_one() that does take idmappings into account. I've added it as part of my patch series to make btrfs support idmapped mounts. The new helper is in linux-next as part of David's (Sterba) btrfs for-next branch as commit c972214 ("namei: add mapping aware lookup helper"). I've said it before during one of my first reviews: I would very much recommend adding fstests to [1]. It already seems to have very rudimentary cifs support. There is a completely generic idmapped mount testsuite that supports idmapped mounts. [1]: https://git.kernel.org/pub/scm/fs/xfs/xfsprogs-dev.git/ Cc: Colin Ian King <[email protected]> Cc: Steve French <[email protected]> Cc: Christoph Hellwig <[email protected]> Cc: Namjae Jeon <[email protected]> Cc: Hyunchul Lee <[email protected]> Cc: Sergey Senozhatsky <[email protected]> Cc: David Sterba <[email protected]> Cc: [email protected] Signed-off-by: Christian Brauner <[email protected]> Signed-off-by: Namjae Jeon <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent 9c849ce commit da1e7ad

File tree

3 files changed

+37
-27
lines changed

3 files changed

+37
-27
lines changed

fs/ksmbd/smb2pdu.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3543,9 +3543,9 @@ static int process_query_dir_entries(struct smb2_query_dir_private *priv)
35433543
return -EINVAL;
35443544

35453545
lock_dir(priv->dir_fp);
3546-
dent = lookup_one_len(priv->d_info->name,
3547-
priv->dir_fp->filp->f_path.dentry,
3548-
priv->d_info->name_len);
3546+
dent = lookup_one(user_ns, priv->d_info->name,
3547+
priv->dir_fp->filp->f_path.dentry,
3548+
priv->d_info->name_len);
35493549
unlock_dir(priv->dir_fp);
35503550

35513551
if (IS_ERR(dent)) {
@@ -5246,7 +5246,9 @@ int smb2_echo(struct ksmbd_work *work)
52465246
return 0;
52475247
}
52485248

5249-
static int smb2_rename(struct ksmbd_work *work, struct ksmbd_file *fp,
5249+
static int smb2_rename(struct ksmbd_work *work,
5250+
struct ksmbd_file *fp,
5251+
struct user_namespace *user_ns,
52505252
struct smb2_file_rename_info *file_info,
52515253
struct nls_table *local_nls)
52525254
{
@@ -5310,7 +5312,7 @@ static int smb2_rename(struct ksmbd_work *work, struct ksmbd_file *fp,
53105312
if (rc)
53115313
goto out;
53125314

5313-
rc = ksmbd_vfs_setxattr(file_mnt_user_ns(fp->filp),
5315+
rc = ksmbd_vfs_setxattr(user_ns,
53145316
fp->filp->f_path.dentry,
53155317
xattr_stream_name,
53165318
NULL, 0, 0);
@@ -5624,6 +5626,7 @@ static int set_end_of_file_info(struct ksmbd_work *work, struct ksmbd_file *fp,
56245626
static int set_rename_info(struct ksmbd_work *work, struct ksmbd_file *fp,
56255627
char *buf)
56265628
{
5629+
struct user_namespace *user_ns;
56275630
struct ksmbd_file *parent_fp;
56285631
struct dentry *parent;
56295632
struct dentry *dentry = fp->filp->f_path.dentry;
@@ -5634,11 +5637,12 @@ static int set_rename_info(struct ksmbd_work *work, struct ksmbd_file *fp,
56345637
return -EACCES;
56355638
}
56365639

5640+
user_ns = file_mnt_user_ns(fp->filp);
56375641
if (ksmbd_stream_fd(fp))
56385642
goto next;
56395643

56405644
parent = dget_parent(dentry);
5641-
ret = ksmbd_vfs_lock_parent(parent, dentry);
5645+
ret = ksmbd_vfs_lock_parent(user_ns, parent, dentry);
56425646
if (ret) {
56435647
dput(parent);
56445648
return ret;
@@ -5655,7 +5659,7 @@ static int set_rename_info(struct ksmbd_work *work, struct ksmbd_file *fp,
56555659
}
56565660
}
56575661
next:
5658-
return smb2_rename(work, fp,
5662+
return smb2_rename(work, fp, user_ns,
56595663
(struct smb2_file_rename_info *)buf,
56605664
work->sess->conn->local_nls);
56615665
}

fs/ksmbd/vfs.c

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -69,14 +69,15 @@ static void ksmbd_vfs_inherit_owner(struct ksmbd_work *work,
6969
*
7070
* the reference count of @parent isn't incremented.
7171
*/
72-
int ksmbd_vfs_lock_parent(struct dentry *parent, struct dentry *child)
72+
int ksmbd_vfs_lock_parent(struct user_namespace *user_ns, struct dentry *parent,
73+
struct dentry *child)
7374
{
7475
struct dentry *dentry;
7576
int ret = 0;
7677

7778
inode_lock_nested(d_inode(parent), I_MUTEX_PARENT);
78-
dentry = lookup_one_len(child->d_name.name, parent,
79-
child->d_name.len);
79+
dentry = lookup_one(user_ns, child->d_name.name, parent,
80+
child->d_name.len);
8081
if (IS_ERR(dentry)) {
8182
ret = PTR_ERR(dentry);
8283
goto out_err;
@@ -102,7 +103,7 @@ int ksmbd_vfs_may_delete(struct user_namespace *user_ns,
102103
int ret;
103104

104105
parent = dget_parent(dentry);
105-
ret = ksmbd_vfs_lock_parent(parent, dentry);
106+
ret = ksmbd_vfs_lock_parent(user_ns, parent, dentry);
106107
if (ret) {
107108
dput(parent);
108109
return ret;
@@ -137,7 +138,7 @@ int ksmbd_vfs_query_maximal_access(struct user_namespace *user_ns,
137138
*daccess |= FILE_EXECUTE_LE;
138139

139140
parent = dget_parent(dentry);
140-
ret = ksmbd_vfs_lock_parent(parent, dentry);
141+
ret = ksmbd_vfs_lock_parent(user_ns, parent, dentry);
141142
if (ret) {
142143
dput(parent);
143144
return ret;
@@ -197,6 +198,7 @@ int ksmbd_vfs_create(struct ksmbd_work *work, const char *name, umode_t mode)
197198
*/
198199
int ksmbd_vfs_mkdir(struct ksmbd_work *work, const char *name, umode_t mode)
199200
{
201+
struct user_namespace *user_ns;
200202
struct path path;
201203
struct dentry *dentry;
202204
int err;
@@ -210,16 +212,16 @@ int ksmbd_vfs_mkdir(struct ksmbd_work *work, const char *name, umode_t mode)
210212
return err;
211213
}
212214

215+
user_ns = mnt_user_ns(path.mnt);
213216
mode |= S_IFDIR;
214-
err = vfs_mkdir(mnt_user_ns(path.mnt), d_inode(path.dentry),
215-
dentry, mode);
217+
err = vfs_mkdir(user_ns, d_inode(path.dentry), dentry, mode);
216218
if (err) {
217219
goto out;
218220
} else if (d_unhashed(dentry)) {
219221
struct dentry *d;
220222

221-
d = lookup_one_len(dentry->d_name.name, dentry->d_parent,
222-
dentry->d_name.len);
223+
d = lookup_one(user_ns, dentry->d_name.name, dentry->d_parent,
224+
dentry->d_name.len);
223225
if (IS_ERR(d)) {
224226
err = PTR_ERR(d);
225227
goto out;
@@ -582,6 +584,7 @@ int ksmbd_vfs_fsync(struct ksmbd_work *work, u64 fid, u64 p_id)
582584
*/
583585
int ksmbd_vfs_remove_file(struct ksmbd_work *work, char *name)
584586
{
587+
struct user_namespace *user_ns;
585588
struct path path;
586589
struct dentry *parent;
587590
int err;
@@ -601,8 +604,9 @@ int ksmbd_vfs_remove_file(struct ksmbd_work *work, char *name)
601604
return err;
602605
}
603606

607+
user_ns = mnt_user_ns(path.mnt);
604608
parent = dget_parent(path.dentry);
605-
err = ksmbd_vfs_lock_parent(parent, path.dentry);
609+
err = ksmbd_vfs_lock_parent(user_ns, parent, path.dentry);
606610
if (err) {
607611
dput(parent);
608612
path_put(&path);
@@ -616,14 +620,12 @@ int ksmbd_vfs_remove_file(struct ksmbd_work *work, char *name)
616620
}
617621

618622
if (S_ISDIR(d_inode(path.dentry)->i_mode)) {
619-
err = vfs_rmdir(mnt_user_ns(path.mnt), d_inode(parent),
620-
path.dentry);
623+
err = vfs_rmdir(user_ns, d_inode(parent), path.dentry);
621624
if (err && err != -ENOTEMPTY)
622625
ksmbd_debug(VFS, "%s: rmdir failed, err %d\n", name,
623626
err);
624627
} else {
625-
err = vfs_unlink(mnt_user_ns(path.mnt), d_inode(parent),
626-
path.dentry, NULL);
628+
err = vfs_unlink(user_ns, d_inode(parent), path.dentry, NULL);
627629
if (err)
628630
ksmbd_debug(VFS, "%s: unlink failed, err %d\n", name,
629631
err);
@@ -748,7 +750,8 @@ static int __ksmbd_vfs_rename(struct ksmbd_work *work,
748750
if (ksmbd_override_fsids(work))
749751
return -ENOMEM;
750752

751-
dst_dent = lookup_one_len(dst_name, dst_dent_parent, strlen(dst_name));
753+
dst_dent = lookup_one(dst_user_ns, dst_name, dst_dent_parent,
754+
strlen(dst_name));
752755
err = PTR_ERR(dst_dent);
753756
if (IS_ERR(dst_dent)) {
754757
pr_err("lookup failed %s [%d]\n", dst_name, err);
@@ -779,6 +782,7 @@ static int __ksmbd_vfs_rename(struct ksmbd_work *work,
779782
int ksmbd_vfs_fp_rename(struct ksmbd_work *work, struct ksmbd_file *fp,
780783
char *newname)
781784
{
785+
struct user_namespace *user_ns;
782786
struct path dst_path;
783787
struct dentry *src_dent_parent, *dst_dent_parent;
784788
struct dentry *src_dent, *trap_dent, *src_child;
@@ -808,8 +812,9 @@ int ksmbd_vfs_fp_rename(struct ksmbd_work *work, struct ksmbd_file *fp,
808812
trap_dent = lock_rename(src_dent_parent, dst_dent_parent);
809813
dget(src_dent);
810814
dget(dst_dent_parent);
811-
src_child = lookup_one_len(src_dent->d_name.name, src_dent_parent,
812-
src_dent->d_name.len);
815+
user_ns = file_mnt_user_ns(fp->filp);
816+
src_child = lookup_one(user_ns, src_dent->d_name.name, src_dent_parent,
817+
src_dent->d_name.len);
813818
if (IS_ERR(src_child)) {
814819
err = PTR_ERR(src_child);
815820
goto out_lock;
@@ -823,7 +828,7 @@ int ksmbd_vfs_fp_rename(struct ksmbd_work *work, struct ksmbd_file *fp,
823828
dput(src_child);
824829

825830
err = __ksmbd_vfs_rename(work,
826-
file_mnt_user_ns(fp->filp),
831+
user_ns,
827832
src_dent_parent,
828833
src_dent,
829834
mnt_user_ns(dst_path.mnt),
@@ -1109,7 +1114,7 @@ int ksmbd_vfs_unlink(struct user_namespace *user_ns,
11091114
{
11101115
int err = 0;
11111116

1112-
err = ksmbd_vfs_lock_parent(dir, dentry);
1117+
err = ksmbd_vfs_lock_parent(user_ns, dir, dentry);
11131118
if (err)
11141119
return err;
11151120
dget(dentry);

fs/ksmbd/vfs.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@ struct ksmbd_kstat {
107107
__le32 file_attributes;
108108
};
109109

110-
int ksmbd_vfs_lock_parent(struct dentry *parent, struct dentry *child);
110+
int ksmbd_vfs_lock_parent(struct user_namespace *user_ns, struct dentry *parent,
111+
struct dentry *child);
111112
int ksmbd_vfs_may_delete(struct user_namespace *user_ns, struct dentry *dentry);
112113
int ksmbd_vfs_query_maximal_access(struct user_namespace *user_ns,
113114
struct dentry *dentry, __le32 *daccess);

0 commit comments

Comments
 (0)