Skip to content

Commit

Permalink
ksmbd: validate share name from share config response
Browse files Browse the repository at this point in the history
Share config response may contain the share name without casefolding as
it is known to the user space daemon. When it is present, casefold and
compare it to the share name the share config request was made with. If
they differ, we have a share config which is incompatible with the way
share config caching is done. This is the case when CONFIG_UNICODE is
not set, the share name contains non-ASCII characters, and those non-
ASCII characters do not match those in the share name known to user
space. In other words, when CONFIG_UNICODE is not set, UTF-8 share
names now work but are only case-insensitive in the ASCII range.

Signed-off-by: Atte Heikkilä <[email protected]>
Acked-by: Tom Talpey <[email protected]>
Signed-off-by: Namjae Jeon <[email protected]>
  • Loading branch information
atheik authored and namjaejeon committed Oct 4, 2022
1 parent 0db6a06 commit 63759f7
Show file tree
Hide file tree
Showing 6 changed files with 29 additions and 9 deletions.
3 changes: 2 additions & 1 deletion ksmbd_netlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ struct ksmbd_share_config_response {
__u16 force_directory_mode;
__u16 force_uid;
__u16 force_gid;
__u32 reserved[128]; /* Reserved room */
__s8 share_name[KSMBD_REQ_MAX_SHARE_NAME];
__u32 reserved[112]; /* Reserved room */
__u32 veto_list_sz;
__s8 ____payload[];
};
Expand Down
22 changes: 19 additions & 3 deletions mgmt/share_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "user_config.h"
#include "user_session.h"
#include "../transport_ipc.h"
#include "../misc.h"

#define SHARE_HASH_BITS 3
static DEFINE_HASHTABLE(shares_table, SHARE_HASH_BITS);
Expand Down Expand Up @@ -119,7 +120,8 @@ static int parse_veto_list(struct ksmbd_share_config *share,
return 0;
}

static struct ksmbd_share_config *share_config_request(const char *name)
static struct ksmbd_share_config *share_config_request(struct unicode_map *um,
const char *name)
{
struct ksmbd_share_config_response *resp;
struct ksmbd_share_config *share = NULL;
Expand All @@ -133,6 +135,19 @@ static struct ksmbd_share_config *share_config_request(const char *name)
if (resp->flags == KSMBD_SHARE_FLAG_INVALID)
goto out;

if (*resp->share_name) {
char *cf_resp_name;
bool equal;

cf_resp_name = ksmbd_casefold_sharename(um, resp->share_name);
if (IS_ERR(cf_resp_name))
goto out;
equal = !strcmp(cf_resp_name, name);
kfree(cf_resp_name);
if (!equal)
goto out;
}

share = kzalloc(sizeof(struct ksmbd_share_config), GFP_KERNEL);
if (!share)
goto out;
Expand Down Expand Up @@ -190,7 +205,8 @@ static struct ksmbd_share_config *share_config_request(const char *name)
return share;
}

struct ksmbd_share_config *ksmbd_share_config_get(const char *name)
struct ksmbd_share_config *ksmbd_share_config_get(struct unicode_map *um,
const char *name)
{
struct ksmbd_share_config *share;

Expand All @@ -202,7 +218,7 @@ struct ksmbd_share_config *ksmbd_share_config_get(const char *name)

if (share)
return share;
return share_config_request(name);
return share_config_request(um, name);
}

bool ksmbd_share_veto_filename(struct ksmbd_share_config *share,
Expand Down
4 changes: 3 additions & 1 deletion mgmt/share_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <linux/workqueue.h>
#include <linux/hashtable.h>
#include <linux/path.h>
#include <linux/unicode.h>

struct ksmbd_share_config {
char *name;
Expand Down Expand Up @@ -74,7 +75,8 @@ static inline void ksmbd_share_config_put(struct ksmbd_share_config *share)
__ksmbd_share_config_put(share);
}

struct ksmbd_share_config *ksmbd_share_config_get(const char *name);
struct ksmbd_share_config *ksmbd_share_config_get(struct unicode_map *um,
const char *name);
bool ksmbd_share_veto_filename(struct ksmbd_share_config *share,
const char *filename);
#endif /* __SHARE_CONFIG_MANAGEMENT_H__ */
4 changes: 2 additions & 2 deletions mgmt/tree_connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess,
struct sockaddr *peer_addr;
int ret;

sc = ksmbd_share_config_get(share_name);
sc = ksmbd_share_config_get(conn->um, share_name);
if (!sc) {
pr_err("Failed to get share config\n");
return status;
Expand Down Expand Up @@ -69,7 +69,7 @@ ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess,
struct ksmbd_share_config *new_sc;

ksmbd_share_config_del(sc);
new_sc = ksmbd_share_config_get(share_name);
new_sc = ksmbd_share_config_get(conn->um, share_name);
if (!new_sc) {
pr_err("Failed to update stale share config\n");
status.ret = -ESTALE;
Expand Down
4 changes: 2 additions & 2 deletions misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ void ksmbd_conv_path_to_windows(char *path)
strreplace(path, '/', '\\');
}

static char *casefold_sharename(struct unicode_map *um, const char *name)
char *ksmbd_casefold_sharename(struct unicode_map *um, const char *name)
{
char *cf_name;
int cf_len;
Expand Down Expand Up @@ -290,7 +290,7 @@ char *ksmbd_extract_sharename(struct unicode_map *um, const char *treename)
name = (pos + 1);

/* caller has to free the memory */
return casefold_sharename(um, name);
return ksmbd_casefold_sharename(um, name);
}

/**
Expand Down
1 change: 1 addition & 0 deletions misc.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ int get_nlink(struct kstat *st);
void ksmbd_conv_path_to_unix(char *path);
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);

Expand Down

0 comments on commit 63759f7

Please sign in to comment.