]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ksmbd: make utf-8 file name comparison work in __caseless_lookup()
authorAtte Heikkilä <atteh.mailbox@gmail.com>
Mon, 18 Dec 2023 15:33:21 +0000 (00:33 +0900)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 23 Dec 2023 09:41:53 +0000 (10:41 +0100)
[ Upstream commit dbab80e2071ad8c702e50dab43326608a127d27b ]

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ä <atteh.mailbox@gmail.com>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/ksmbd/connection.h
fs/ksmbd/vfs.c
fs/ksmbd/vfs.h

index 8c99fdbd701f059d0253850c17c9e6e00a80a2a1..0e3a848defaf3214ed752deed6c51854890a4194 100644 (file)
@@ -14,6 +14,7 @@
 #include <net/request_sock.h>
 #include <linux/kthread.h>
 #include <linux/nls.h>
+#include <linux/unicode.h>
 
 #include "smb_common.h"
 #include "ksmbd_work.h"
index 284aa87f3e5cd600521691fe5ee54f41549028cf..d7814397764c478aef2a34f46248bf35ca0eb1c9 100644 (file)
@@ -1144,12 +1144,23 @@ static int __caseless_lookup(struct dir_context *ctx, const char *name,
                             unsigned int d_type)
 {
        struct ksmbd_readdir_data *buf;
+       int cmp = -EINVAL;
 
        buf = container_of(ctx, struct ksmbd_readdir_data, ctx);
 
        if (buf->used != namlen)
                return 0;
-       if (!strncasecmp((char *)buf->private, name, namlen)) {
+       if (IS_ENABLED(CONFIG_UNICODE) && buf->um) {
+               const struct qstr q_buf = {.name = buf->private,
+                                          .len = buf->used};
+               const struct qstr q_name = {.name = name,
+                                           .len = namlen};
+
+               cmp = utf8_strncasecmp(buf->um, &q_buf, &q_name);
+       }
+       if (cmp < 0)
+               cmp = strncasecmp((char *)buf->private, name, namlen);
+       if (!cmp) {
                memcpy((char *)buf->private, name, namlen);
                buf->dirent_count = 1;
                return -EEXIST;
@@ -1165,7 +1176,8 @@ static int __caseless_lookup(struct dir_context *ctx, const char *name,
  *
  * Return:     0 on success, otherwise error
  */
-static int ksmbd_vfs_lookup_in_dir(const struct path *dir, char *name, size_t namelen)
+static int ksmbd_vfs_lookup_in_dir(const struct path *dir, char *name,
+                                  size_t namelen, struct unicode_map *um)
 {
        int ret;
        struct file *dfilp;
@@ -1175,6 +1187,7 @@ static int ksmbd_vfs_lookup_in_dir(const struct path *dir, char *name, size_t na
                .private        = name,
                .used           = namelen,
                .dirent_count   = 0,
+               .um             = um,
        };
 
        dfilp = dentry_open(dir, flags, current_cred());
@@ -1237,7 +1250,8 @@ int ksmbd_vfs_kern_path(struct ksmbd_work *work, char *name,
                                break;
 
                        err = ksmbd_vfs_lookup_in_dir(&parent, filename,
-                                                     filename_len);
+                                                     filename_len,
+                                                     work->conn->um);
                        path_put(&parent);
                        if (err)
                                goto out;
index 7dd054f868506dd527a228fff7cd7c0648045b5e..1f0cbd520f129374431ee7e6c558f047ff711087 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/namei.h>
 #include <uapi/linux/xattr.h>
 #include <linux/posix_acl.h>
+#include <linux/unicode.h>
 
 #include "smbacl.h"
 #include "xattr.h"
@@ -99,6 +100,7 @@ struct ksmbd_readdir_data {
        unsigned int            used;
        unsigned int            dirent_count;
        unsigned int            file_attr;
+       struct unicode_map      *um;
 };
 
 /* ksmbd kstat wrapper to get valid create time when reading dir entry */