mirror of
https://github.com/torvalds/linux.git
synced 2026-07-29 10:41:49 +02:00
ksmbd: fix path resolution in ksmbd_vfs_kern_path_create
The SMB2 open lookup is rooted at the share with LOOKUP_BENEATH, but the
create/mkdir/hardlink sink is not: ksmbd_vfs_kern_path_create() builds an
absolute path with convert_to_unix_name() and resolves it from AT_FDCWD
via start_creating_path(), so a ".." component is walked from the real
filesystem root and escapes the export.
An authenticated client races a missing path component so the rooted open
lookup returns -ENOENT (taking the create branch) while the same component
is present (a directory) when the create walk runs; the create then
resolves ".." out of the share.
Root the create walk at the share like the lookup and rename paths already
are: resolve the parent with vfs_path_parent_lookup(..., LOOKUP_BENEATH,
&share_conf->vfs_path) and create the final component with
start_creating_noperm(). convert_to_unix_name() then has no callers and is
removed.
Fixes: 265fd1991c ("ksmbd: use LOOKUP_BENEATH to prevent the out of share access")
Cc: stable@vger.kernel.org
Signed-off-by: Davide Ornaghi <d.ornaghi97@gmail.com>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
c6394bcaf2
commit
1c8951963d
|
|
@ -283,39 +283,6 @@ char *ksmbd_extract_sharename(struct unicode_map *um, const char *treename)
|
|||
return ksmbd_casefold_sharename(um, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* convert_to_unix_name() - convert windows name to unix format
|
||||
* @share: ksmbd_share_config pointer
|
||||
* @name: file name that is relative to share
|
||||
*
|
||||
* Return: converted name on success, otherwise NULL
|
||||
*/
|
||||
char *convert_to_unix_name(struct ksmbd_share_config *share, const char *name)
|
||||
{
|
||||
int no_slash = 0, name_len, path_len;
|
||||
char *new_name;
|
||||
|
||||
if (name[0] == '/')
|
||||
name++;
|
||||
|
||||
path_len = share->path_sz;
|
||||
name_len = strlen(name);
|
||||
new_name = kmalloc(path_len + name_len + 2, KSMBD_DEFAULT_GFP);
|
||||
if (!new_name)
|
||||
return new_name;
|
||||
|
||||
memcpy(new_name, share->path, path_len);
|
||||
if (new_name[path_len - 1] != '/') {
|
||||
new_name[path_len] = '/';
|
||||
no_slash = 1;
|
||||
}
|
||||
|
||||
memcpy(new_name + path_len + no_slash, name, name_len);
|
||||
path_len += name_len + no_slash;
|
||||
new_name[path_len] = 0x00;
|
||||
return new_name;
|
||||
}
|
||||
|
||||
char *ksmbd_convert_dir_info_name(struct ksmbd_dir_info *d_info,
|
||||
const struct nls_table *local_nls,
|
||||
int *conv_len)
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ void ksmbd_strip_last_slash(char *path);
|
|||
void ksmbd_conv_path_to_windows(char *path);
|
||||
char *ksmbd_casefold_sharename(struct unicode_map *um, const char *name);
|
||||
char *ksmbd_extract_sharename(struct unicode_map *um, const char *treename);
|
||||
char *convert_to_unix_name(struct ksmbd_share_config *share, const char *name);
|
||||
|
||||
#define KSMBD_DIR_INFO_ALIGNMENT 8
|
||||
struct ksmbd_dir_info;
|
||||
|
|
|
|||
|
|
@ -1259,15 +1259,30 @@ struct dentry *ksmbd_vfs_kern_path_create(struct ksmbd_work *work,
|
|||
unsigned int flags,
|
||||
struct path *path)
|
||||
{
|
||||
char *abs_name;
|
||||
struct ksmbd_share_config *share_conf = work->tcon->share_conf;
|
||||
struct qstr last;
|
||||
struct dentry *dent;
|
||||
int err;
|
||||
|
||||
abs_name = convert_to_unix_name(work->tcon->share_conf, name);
|
||||
if (!abs_name)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
/* resolve the name beneath the share root so ".." cannot escape */
|
||||
CLASS(filename_kernel, filename)(name);
|
||||
|
||||
dent = start_creating_path(AT_FDCWD, abs_name, path, flags);
|
||||
kfree(abs_name);
|
||||
err = vfs_path_parent_lookup(filename, flags | LOOKUP_BENEATH,
|
||||
path, &last, &share_conf->vfs_path);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
err = mnt_want_write(path->mnt);
|
||||
if (err) {
|
||||
path_put(path);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
dent = start_creating_noperm(path->dentry, &last);
|
||||
if (IS_ERR(dent)) {
|
||||
mnt_drop_write(path->mnt);
|
||||
path_put(path);
|
||||
}
|
||||
return dent;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user