diff options
author | Hyunchul Lee <hyc.lee@gmail.com> | 2021-09-25 00:06:16 +0900 |
---|---|---|
committer | Steve French <stfrench@microsoft.com> | 2021-09-24 21:25:23 -0500 |
commit | 265fd1991c1db85fbabaad4946ca0e63e2ae688d (patch) | |
tree | f243e175b7a357f16b0b8494268c2b1e82996d21 /fs/ksmbd/misc.c | |
parent | 4ea477988c423a57241ea4840b12832de6fabdfd (diff) |
ksmbd: use LOOKUP_BENEATH to prevent the out of share access
instead of removing '..' in a given path, call
kern_path with LOOKUP_BENEATH flag to prevent
the out of share access.
ran various test on this:
smb2-cat-async smb://127.0.0.1/homes/../out_of_share
smb2-cat-async smb://127.0.0.1/homes/foo/../../out_of_share
smbclient //127.0.0.1/homes -c "mkdir ../foo2"
smbclient //127.0.0.1/homes -c "rename bar ../bar"
Cc: Ronnie Sahlberg <ronniesahlberg@gmail.com>
Cc: Ralph Boehme <slow@samba.org>
Tested-by: Steve French <smfrench@gmail.com>
Tested-by: Namjae Jeon <linkinjeon@kernel.org>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Diffstat (limited to 'fs/ksmbd/misc.c')
-rw-r--r-- | fs/ksmbd/misc.c | 100 |
1 files changed, 19 insertions, 81 deletions
diff --git a/fs/ksmbd/misc.c b/fs/ksmbd/misc.c index 3eac3c01749f..6a19f4bc692d 100644 --- a/fs/ksmbd/misc.c +++ b/fs/ksmbd/misc.c @@ -158,25 +158,21 @@ out: * Return : windows path string or error */ -char *convert_to_nt_pathname(char *filename, char *sharepath) +char *convert_to_nt_pathname(char *filename) { char *ab_pathname; - int len, name_len; - name_len = strlen(filename); - ab_pathname = kmalloc(name_len, GFP_KERNEL); - if (!ab_pathname) - return NULL; - - ab_pathname[0] = '\\'; - ab_pathname[1] = '\0'; + if (strlen(filename) == 0) { + ab_pathname = kmalloc(2, GFP_KERNEL); + ab_pathname[0] = '\\'; + ab_pathname[1] = '\0'; + } else { + ab_pathname = kstrdup(filename, GFP_KERNEL); + if (!ab_pathname) + return NULL; - len = strlen(sharepath); - if (!strncmp(filename, sharepath, len) && name_len != len) { - strscpy(ab_pathname, &filename[len], name_len); ksmbd_conv_path_to_windows(ab_pathname); } - return ab_pathname; } @@ -191,77 +187,19 @@ int get_nlink(struct kstat *st) return nlink; } -char *ksmbd_conv_path_to_unix(char *path) +void ksmbd_conv_path_to_unix(char *path) { - size_t path_len, remain_path_len, out_path_len; - char *out_path, *out_next; - int i, pre_dotdot_cnt = 0, slash_cnt = 0; - bool is_last; - strreplace(path, '\\', '/'); - path_len = strlen(path); - remain_path_len = path_len; - if (path_len == 0) - return ERR_PTR(-EINVAL); - - out_path = kzalloc(path_len + 2, GFP_KERNEL); - if (!out_path) - return ERR_PTR(-ENOMEM); - out_path_len = 0; - out_next = out_path; - - do { - char *name = path + path_len - remain_path_len; - char *next = strchrnul(name, '/'); - size_t name_len = next - name; - - is_last = !next[0]; - if (name_len == 2 && name[0] == '.' && name[1] == '.') { - pre_dotdot_cnt++; - /* handle the case that path ends with "/.." */ - if (is_last) - goto follow_dotdot; - } else { - if (pre_dotdot_cnt) { -follow_dotdot: - slash_cnt = 0; - for (i = out_path_len - 1; i >= 0; i--) { - if (out_path[i] == '/' && - ++slash_cnt == pre_dotdot_cnt + 1) - break; - } - - if (i < 0 && - slash_cnt != pre_dotdot_cnt) { - kfree(out_path); - return ERR_PTR(-EINVAL); - } - - out_next = &out_path[i+1]; - *out_next = '\0'; - out_path_len = i + 1; - - } - - if (name_len != 0 && - !(name_len == 1 && name[0] == '.') && - !(name_len == 2 && name[0] == '.' && name[1] == '.')) { - next[0] = '\0'; - sprintf(out_next, "%s/", name); - out_next += name_len + 1; - out_path_len += name_len + 1; - next[0] = '/'; - } - pre_dotdot_cnt = 0; - } +} - remain_path_len -= name_len + 1; - } while (!is_last); +void ksmbd_strip_last_slash(char *path) +{ + int len = strlen(path); - if (out_path_len > 0) - out_path[out_path_len-1] = '\0'; - path[path_len] = '\0'; - return out_path; + while (len && path[len - 1] == '/') { + path[len - 1] = '\0'; + len--; + } } void ksmbd_conv_path_to_windows(char *path) @@ -298,7 +236,7 @@ char *ksmbd_extract_sharename(char *treename) * * Return: converted name on success, otherwise NULL */ -char *convert_to_unix_name(struct ksmbd_share_config *share, char *name) +char *convert_to_unix_name(struct ksmbd_share_config *share, const char *name) { int no_slash = 0, name_len, path_len; char *new_name; |