Skip to content

Commit dbab80e

Browse files
atheiksmfrench
authored andcommitted
ksmbd: make utf-8 file name comparison work in __caseless_lookup()
Case-insensitive file name lookups with __caseless_lookup() use strncasecmp() for file name comparison. strncasecmp() assumes an ISO8859-1-compatible encoding, which is not the case here as UTF-8 is always used. As such, use of strncasecmp() here produces correct results only if both strings use characters in the ASCII range only. Fix this by using utf8_strncasecmp() if CONFIG_UNICODE is set. On failure or if CONFIG_UNICODE is not set, fallback to strncasecmp(). Also, as we are adding an include for `linux/unicode.h', include it in `fs/ksmbd/connection.h' as well since it should be explicit there. Signed-off-by: Atte Heikkilä <[email protected]> Acked-by: Namjae Jeon <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent 7c88c1e commit dbab80e

File tree

3 files changed

+20
-3
lines changed

3 files changed

+20
-3
lines changed

fs/ksmbd/connection.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <net/request_sock.h>
1515
#include <linux/kthread.h>
1616
#include <linux/nls.h>
17+
#include <linux/unicode.h>
1718

1819
#include "smb_common.h"
1920
#include "ksmbd_work.h"

fs/ksmbd/vfs.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,12 +1145,23 @@ static int __caseless_lookup(struct dir_context *ctx, const char *name,
11451145
unsigned int d_type)
11461146
{
11471147
struct ksmbd_readdir_data *buf;
1148+
int cmp = -EINVAL;
11481149

11491150
buf = container_of(ctx, struct ksmbd_readdir_data, ctx);
11501151

11511152
if (buf->used != namlen)
11521153
return 0;
1153-
if (!strncasecmp((char *)buf->private, name, namlen)) {
1154+
if (IS_ENABLED(CONFIG_UNICODE) && buf->um) {
1155+
const struct qstr q_buf = {.name = buf->private,
1156+
.len = buf->used};
1157+
const struct qstr q_name = {.name = name,
1158+
.len = namlen};
1159+
1160+
cmp = utf8_strncasecmp(buf->um, &q_buf, &q_name);
1161+
}
1162+
if (cmp < 0)
1163+
cmp = strncasecmp((char *)buf->private, name, namlen);
1164+
if (!cmp) {
11541165
memcpy((char *)buf->private, name, namlen);
11551166
buf->dirent_count = 1;
11561167
return -EEXIST;
@@ -1166,7 +1177,8 @@ static int __caseless_lookup(struct dir_context *ctx, const char *name,
11661177
*
11671178
* Return: 0 on success, otherwise error
11681179
*/
1169-
static int ksmbd_vfs_lookup_in_dir(const struct path *dir, char *name, size_t namelen)
1180+
static int ksmbd_vfs_lookup_in_dir(const struct path *dir, char *name,
1181+
size_t namelen, struct unicode_map *um)
11701182
{
11711183
int ret;
11721184
struct file *dfilp;
@@ -1176,6 +1188,7 @@ static int ksmbd_vfs_lookup_in_dir(const struct path *dir, char *name, size_t na
11761188
.private = name,
11771189
.used = namelen,
11781190
.dirent_count = 0,
1191+
.um = um,
11791192
};
11801193

11811194
dfilp = dentry_open(dir, flags, current_cred());
@@ -1238,7 +1251,8 @@ int ksmbd_vfs_kern_path(struct ksmbd_work *work, char *name,
12381251
break;
12391252

12401253
err = ksmbd_vfs_lookup_in_dir(&parent, filename,
1241-
filename_len);
1254+
filename_len,
1255+
work->conn->um);
12421256
path_put(&parent);
12431257
if (err)
12441258
goto out;

fs/ksmbd/vfs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <linux/namei.h>
1313
#include <uapi/linux/xattr.h>
1414
#include <linux/posix_acl.h>
15+
#include <linux/unicode.h>
1516

1617
#include "smbacl.h"
1718
#include "xattr.h"
@@ -60,6 +61,7 @@ struct ksmbd_readdir_data {
6061
unsigned int used;
6162
unsigned int dirent_count;
6263
unsigned int file_attr;
64+
struct unicode_map *um;
6365
};
6466

6567
/* ksmbd kstat wrapper to get valid create time when reading dir entry */

0 commit comments

Comments
 (0)