Commit 707a63e9 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag '5.15-rc1-ksmbd' of git://git.samba.org/ksmbd

Pull ksmbd server fixes from Steve French:
 "Three ksmbd fixes, including an important security fix for path
  processing, and a buffer overflow check, and a trivial fix for
  incorrect header inclusion"

* tag '5.15-rc1-ksmbd' of git://git.samba.org/ksmbd:
  ksmbd: add validation for FILE_FULL_EA_INFORMATION of smb2_get_info
  ksmbd: prevent out of share access
  ksmbd: transport_rdma: Don't include rwlock.h directly
parents fdf50784 6d56262c
...@@ -191,19 +191,77 @@ int get_nlink(struct kstat *st) ...@@ -191,19 +191,77 @@ int get_nlink(struct kstat *st)
return nlink; return nlink;
} }
void ksmbd_conv_path_to_unix(char *path) char *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, '\\', '/'); strreplace(path, '\\', '/');
} path_len = strlen(path);
remain_path_len = path_len;
if (path_len == 0)
return ERR_PTR(-EINVAL);
void ksmbd_strip_last_slash(char *path) out_path = kzalloc(path_len + 2, GFP_KERNEL);
{ if (!out_path)
int len = strlen(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;
while (len && path[len - 1] == '/') { }
path[len - 1] = '\0';
len--; 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);
if (out_path_len > 0)
out_path[out_path_len-1] = '\0';
path[path_len] = '\0';
return out_path;
} }
void ksmbd_conv_path_to_windows(char *path) void ksmbd_conv_path_to_windows(char *path)
......
...@@ -16,8 +16,7 @@ int ksmbd_validate_filename(char *filename); ...@@ -16,8 +16,7 @@ int ksmbd_validate_filename(char *filename);
int parse_stream_name(char *filename, char **stream_name, int *s_type); int parse_stream_name(char *filename, char **stream_name, int *s_type);
char *convert_to_nt_pathname(char *filename, char *sharepath); char *convert_to_nt_pathname(char *filename, char *sharepath);
int get_nlink(struct kstat *st); int get_nlink(struct kstat *st);
void ksmbd_conv_path_to_unix(char *path); char *ksmbd_conv_path_to_unix(char *path);
void ksmbd_strip_last_slash(char *path);
void ksmbd_conv_path_to_windows(char *path); void ksmbd_conv_path_to_windows(char *path);
char *ksmbd_extract_sharename(char *treename); char *ksmbd_extract_sharename(char *treename);
char *convert_to_unix_name(struct ksmbd_share_config *share, char *name); char *convert_to_unix_name(struct ksmbd_share_config *share, char *name);
......
...@@ -634,7 +634,7 @@ static char * ...@@ -634,7 +634,7 @@ static char *
smb2_get_name(struct ksmbd_share_config *share, const char *src, smb2_get_name(struct ksmbd_share_config *share, const char *src,
const int maxlen, struct nls_table *local_nls) const int maxlen, struct nls_table *local_nls)
{ {
char *name, *unixname; char *name, *norm_name, *unixname;
name = smb_strndup_from_utf16(src, maxlen, 1, local_nls); name = smb_strndup_from_utf16(src, maxlen, 1, local_nls);
if (IS_ERR(name)) { if (IS_ERR(name)) {
...@@ -643,11 +643,15 @@ smb2_get_name(struct ksmbd_share_config *share, const char *src, ...@@ -643,11 +643,15 @@ smb2_get_name(struct ksmbd_share_config *share, const char *src,
} }
/* change it to absolute unix name */ /* change it to absolute unix name */
ksmbd_conv_path_to_unix(name); norm_name = ksmbd_conv_path_to_unix(name);
ksmbd_strip_last_slash(name); if (IS_ERR(norm_name)) {
kfree(name);
unixname = convert_to_unix_name(share, name); return norm_name;
}
kfree(name); kfree(name);
unixname = convert_to_unix_name(share, norm_name);
kfree(norm_name);
if (!unixname) { if (!unixname) {
pr_err("can not convert absolute name\n"); pr_err("can not convert absolute name\n");
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -4041,6 +4045,10 @@ static int smb2_get_ea(struct ksmbd_work *work, struct ksmbd_file *fp, ...@@ -4041,6 +4045,10 @@ static int smb2_get_ea(struct ksmbd_work *work, struct ksmbd_file *fp,
path = &fp->filp->f_path; path = &fp->filp->f_path;
/* single EA entry is requested with given user.* name */ /* single EA entry is requested with given user.* name */
if (req->InputBufferLength) { if (req->InputBufferLength) {
if (le32_to_cpu(req->InputBufferLength) <
sizeof(struct smb2_ea_info_req))
return -EINVAL;
ea_req = (struct smb2_ea_info_req *)req->Buffer; ea_req = (struct smb2_ea_info_req *)req->Buffer;
} else { } else {
/* need to send all EAs, if no specific EA is requested*/ /* need to send all EAs, if no specific EA is requested*/
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#define SUBMOD_NAME "smb_direct" #define SUBMOD_NAME "smb_direct"
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/rwlock.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/mempool.h> #include <linux/mempool.h>
#include <linux/highmem.h> #include <linux/highmem.h>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment