Commit 16b5f54e authored by Atte Heikkilä's avatar Atte Heikkilä Committed by Steve French
Browse files

ksmbd: casefold utf-8 share names and fix ascii lowercase conversion



strtolower() corrupts all UTF-8 share names that have a byte in the C0
(À ISO8859-1) to DE (Þ ISO8859-1) range, since the non-ASCII part of
ISO8859-1 is incompatible with UTF-8. Prevent this by checking that a
byte is in the ASCII range with isascii(), before the conversion to
lowercase with tolower(). Properly handle case-insensitivity of UTF-8
share names by casefolding them, but fallback to ASCII lowercase
conversion on failure or if CONFIG_UNICODE is not set. Refactor to move
the share name casefolding immediately after the share name extraction.
Also, make the associated constness corrections.

Signed-off-by: default avatarAtte Heikkilä <atteh.mailbox@gmail.com>
Acked-by: default avatarNamjae Jeon <linkinjeon@kernel.org>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 276a3f7c
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -60,6 +60,12 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
	conn->local_nls = load_nls("utf8");
	if (!conn->local_nls)
		conn->local_nls = load_nls_default();
	if (IS_ENABLED(CONFIG_UNICODE))
		conn->um = utf8_load(UNICODE_AGE(12, 1, 0));
	else
		conn->um = ERR_PTR(-EOPNOTSUPP);
	if (IS_ERR(conn->um))
		conn->um = NULL;
	atomic_set(&conn->req_running, 0);
	atomic_set(&conn->r_count, 0);
	conn->total_credits = 1;
@@ -350,6 +356,8 @@ int ksmbd_conn_handler_loop(void *p)
	wait_event(conn->r_count_q, atomic_read(&conn->r_count) == 0);


	if (IS_ENABLED(CONFIG_UNICODE))
		utf8_unload(conn->um);
	unload_nls(conn->local_nls);
	if (default_conn_ops.terminate_fn)
		default_conn_ops.terminate_fn(conn);
+1 −0
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ struct ksmbd_conn {
	char				*request_buf;
	struct ksmbd_transport		*transport;
	struct nls_table		*local_nls;
	struct unicode_map		*um;
	struct list_head		conns_list;
	/* smb session 1 per user */
	struct xarray			sessions;
+4 −14
Original line number Diff line number Diff line
@@ -26,7 +26,7 @@ struct ksmbd_veto_pattern {
	struct list_head	list;
};

static unsigned int share_name_hash(char *name)
static unsigned int share_name_hash(const char *name)
{
	return jhash(name, strlen(name), 0);
}
@@ -72,7 +72,7 @@ __get_share_config(struct ksmbd_share_config *share)
	return share;
}

static struct ksmbd_share_config *__share_lookup(char *name)
static struct ksmbd_share_config *__share_lookup(const char *name)
{
	struct ksmbd_share_config *share;
	unsigned int key = share_name_hash(name);
@@ -119,7 +119,7 @@ static int parse_veto_list(struct ksmbd_share_config *share,
	return 0;
}

static struct ksmbd_share_config *share_config_request(char *name)
static struct ksmbd_share_config *share_config_request(const char *name)
{
	struct ksmbd_share_config_response *resp;
	struct ksmbd_share_config *share = NULL;
@@ -190,20 +190,10 @@ static struct ksmbd_share_config *share_config_request(char *name)
	return share;
}

static void strtolower(char *share_name)
{
	while (*share_name) {
		*share_name = tolower(*share_name);
		share_name++;
	}
}

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

	strtolower(name);

	down_read(&shares_table_lock);
	share = __share_lookup(name);
	if (share)
+1 −1
Original line number Diff line number Diff line
@@ -74,7 +74,7 @@ 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(char *name);
struct ksmbd_share_config *ksmbd_share_config_get(const char *name);
bool ksmbd_share_veto_filename(struct ksmbd_share_config *share,
			       const char *filename);
#endif /* __SHARE_CONFIG_MANAGEMENT_H__ */
+1 −1
Original line number Diff line number Diff line
@@ -17,7 +17,7 @@

struct ksmbd_tree_conn_status
ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess,
			char *share_name)
			const char *share_name)
{
	struct ksmbd_tree_conn_status status = {-ENOENT, NULL};
	struct ksmbd_tree_connect_response *resp = NULL;
Loading