diff options
author | Steve French <smfrench@gmail.com> | 2021-07-02 09:58:21 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-07-02 09:58:21 -0500 |
commit | ae9d84d6f1b1012a7829c03b9a318f499dc7719d (patch) | |
tree | 0db387e95eb0372e4e6ebb6304671603d0c9690a | |
parent | be8bcf8baaec8e063da56797dda48075bb8198d2 (diff) | |
parent | af34983e831587472333e47c86a350a2360c6093 (diff) |
Merge pull request #56 from namjaejeon/cifsd-for-next
ksmbd-fixes
-rw-r--r-- | Documentation/filesystems/cifs/index.rst | 2 | ||||
-rw-r--r-- | Documentation/filesystems/cifs/ksmbd.rst (renamed from Documentation/filesystems/cifs/cifsd.rst) | 10 | ||||
-rw-r--r-- | MAINTAINERS | 19 | ||||
-rw-r--r-- | fs/Kconfig | 2 | ||||
-rw-r--r-- | fs/Makefile | 2 | ||||
-rw-r--r-- | fs/cifsd/buffer_pool.c | 265 | ||||
-rw-r--r-- | fs/cifsd/buffer_pool.h | 17 | ||||
-rw-r--r-- | fs/ksmbd/Kconfig (renamed from fs/cifsd/Kconfig) | 15 | ||||
-rw-r--r-- | fs/ksmbd/Makefile (renamed from fs/cifsd/Makefile) | 4 | ||||
-rw-r--r-- | fs/ksmbd/asn1.c (renamed from fs/cifsd/asn1.c) | 3 | ||||
-rw-r--r-- | fs/ksmbd/asn1.h (renamed from fs/cifsd/asn1.h) | 0 | ||||
-rw-r--r-- | fs/ksmbd/auth.c (renamed from fs/cifsd/auth.c) | 49 | ||||
-rw-r--r-- | fs/ksmbd/auth.h (renamed from fs/cifsd/auth.h) | 6 | ||||
-rw-r--r-- | fs/ksmbd/connection.c (renamed from fs/cifsd/connection.c) | 16 | ||||
-rw-r--r-- | fs/ksmbd/connection.h (renamed from fs/cifsd/connection.h) | 1 | ||||
-rw-r--r-- | fs/ksmbd/crypto_ctx.c (renamed from fs/cifsd/crypto_ctx.c) | 5 | ||||
-rw-r--r-- | fs/ksmbd/crypto_ctx.h (renamed from fs/cifsd/crypto_ctx.h) | 0 | ||||
-rw-r--r-- | fs/ksmbd/glob.h (renamed from fs/cifsd/glob.h) | 29 | ||||
-rw-r--r-- | fs/ksmbd/ksmbd_netlink.h (renamed from fs/cifsd/ksmbd_server.h) | 236 | ||||
-rw-r--r-- | fs/ksmbd/ksmbd_spnego_negtokeninit.asn1 (renamed from fs/cifsd/ksmbd_spnego_negtokeninit.asn1) | 0 | ||||
-rw-r--r-- | fs/ksmbd/ksmbd_spnego_negtokentarg.asn1 (renamed from fs/cifsd/ksmbd_spnego_negtokentarg.asn1) | 0 | ||||
-rw-r--r-- | fs/ksmbd/ksmbd_work.c (renamed from fs/cifsd/ksmbd_work.c) | 17 | ||||
-rw-r--r-- | fs/ksmbd/ksmbd_work.h (renamed from fs/cifsd/ksmbd_work.h) | 27 | ||||
-rw-r--r-- | fs/ksmbd/mgmt/ksmbd_ida.c (renamed from fs/cifsd/mgmt/ksmbd_ida.c) | 0 | ||||
-rw-r--r-- | fs/ksmbd/mgmt/ksmbd_ida.h (renamed from fs/cifsd/mgmt/ksmbd_ida.h) | 0 | ||||
-rw-r--r-- | fs/ksmbd/mgmt/share_config.c (renamed from fs/cifsd/mgmt/share_config.c) | 3 | ||||
-rw-r--r-- | fs/ksmbd/mgmt/share_config.h (renamed from fs/cifsd/mgmt/share_config.h) | 0 | ||||
-rw-r--r-- | fs/ksmbd/mgmt/tree_connect.c (renamed from fs/cifsd/mgmt/tree_connect.c) | 1 | ||||
-rw-r--r-- | fs/ksmbd/mgmt/tree_connect.h (renamed from fs/cifsd/mgmt/tree_connect.h) | 2 | ||||
-rw-r--r-- | fs/ksmbd/mgmt/user_config.c (renamed from fs/cifsd/mgmt/user_config.c) | 1 | ||||
-rw-r--r-- | fs/ksmbd/mgmt/user_config.h (renamed from fs/cifsd/mgmt/user_config.h) | 0 | ||||
-rw-r--r-- | fs/ksmbd/mgmt/user_session.c (renamed from fs/cifsd/mgmt/user_session.c) | 77 | ||||
-rw-r--r-- | fs/ksmbd/mgmt/user_session.h (renamed from fs/cifsd/mgmt/user_session.h) | 11 | ||||
-rw-r--r-- | fs/ksmbd/misc.c (renamed from fs/cifsd/misc.c) | 2 | ||||
-rw-r--r-- | fs/ksmbd/misc.h (renamed from fs/cifsd/misc.h) | 0 | ||||
-rw-r--r-- | fs/ksmbd/ndr.c (renamed from fs/cifsd/ndr.c) | 72 | ||||
-rw-r--r-- | fs/ksmbd/ndr.h (renamed from fs/cifsd/ndr.h) | 4 | ||||
-rw-r--r-- | fs/ksmbd/nterr.h (renamed from fs/cifsd/nterr.h) | 0 | ||||
-rw-r--r-- | fs/ksmbd/ntlmssp.h (renamed from fs/cifsd/ntlmssp.h) | 0 | ||||
-rw-r--r-- | fs/ksmbd/oplock.c (renamed from fs/cifsd/oplock.c) | 39 | ||||
-rw-r--r-- | fs/ksmbd/oplock.h (renamed from fs/cifsd/oplock.h) | 6 | ||||
-rw-r--r-- | fs/ksmbd/server.c (renamed from fs/cifsd/server.c) | 24 | ||||
-rw-r--r-- | fs/ksmbd/server.h (renamed from fs/cifsd/server.h) | 26 | ||||
-rw-r--r-- | fs/ksmbd/smb2misc.c (renamed from fs/cifsd/smb2misc.c) | 14 | ||||
-rw-r--r-- | fs/ksmbd/smb2ops.c (renamed from fs/cifsd/smb2ops.c) | 10 | ||||
-rw-r--r-- | fs/ksmbd/smb2pdu.c (renamed from fs/cifsd/smb2pdu.c) | 754 | ||||
-rw-r--r-- | fs/ksmbd/smb2pdu.h (renamed from fs/cifsd/smb2pdu.h) | 3 | ||||
-rw-r--r-- | fs/ksmbd/smb_common.c (renamed from fs/cifsd/smb_common.c) | 13 | ||||
-rw-r--r-- | fs/ksmbd/smb_common.h (renamed from fs/cifsd/smb_common.h) | 15 | ||||
-rw-r--r-- | fs/ksmbd/smbacl.c (renamed from fs/cifsd/smbacl.c) | 147 | ||||
-rw-r--r-- | fs/ksmbd/smbacl.h (renamed from fs/cifsd/smbacl.h) | 50 | ||||
-rw-r--r-- | fs/ksmbd/smbfsctl.h (renamed from fs/cifsd/smbfsctl.h) | 0 | ||||
-rw-r--r-- | fs/ksmbd/smbstatus.h (renamed from fs/cifsd/smbstatus.h) | 0 | ||||
-rw-r--r-- | fs/ksmbd/transport_ipc.c (renamed from fs/cifsd/transport_ipc.c) | 66 | ||||
-rw-r--r-- | fs/ksmbd/transport_ipc.h (renamed from fs/cifsd/transport_ipc.h) | 0 | ||||
-rw-r--r-- | fs/ksmbd/transport_rdma.c (renamed from fs/cifsd/transport_rdma.c) | 141 | ||||
-rw-r--r-- | fs/ksmbd/transport_rdma.h (renamed from fs/cifsd/transport_rdma.h) | 0 | ||||
-rw-r--r-- | fs/ksmbd/transport_tcp.c (renamed from fs/cifsd/transport_tcp.c) | 21 | ||||
-rw-r--r-- | fs/ksmbd/transport_tcp.h (renamed from fs/cifsd/transport_tcp.h) | 0 | ||||
-rw-r--r-- | fs/ksmbd/unicode.c (renamed from fs/cifsd/unicode.c) | 0 | ||||
-rw-r--r-- | fs/ksmbd/unicode.h (renamed from fs/cifsd/unicode.h) | 0 | ||||
-rw-r--r-- | fs/ksmbd/uniupr.h (renamed from fs/cifsd/uniupr.h) | 0 | ||||
-rw-r--r-- | fs/ksmbd/vfs.c (renamed from fs/cifsd/vfs.c) | 620 | ||||
-rw-r--r-- | fs/ksmbd/vfs.h (renamed from fs/cifsd/vfs.h) | 162 | ||||
-rw-r--r-- | fs/ksmbd/vfs_cache.c (renamed from fs/cifsd/vfs_cache.c) | 70 | ||||
-rw-r--r-- | fs/ksmbd/vfs_cache.h (renamed from fs/cifsd/vfs_cache.h) | 11 | ||||
-rw-r--r-- | fs/ksmbd/xattr.h | 122 |
67 files changed, 1580 insertions, 1632 deletions
diff --git a/Documentation/filesystems/cifs/index.rst b/Documentation/filesystems/cifs/index.rst index e762586b5dc7..1c8597a679ab 100644 --- a/Documentation/filesystems/cifs/index.rst +++ b/Documentation/filesystems/cifs/index.rst @@ -6,5 +6,5 @@ CIFS .. toctree:: :maxdepth: 1 - cifsd + ksmbd cifsroot diff --git a/Documentation/filesystems/cifs/cifsd.rst b/Documentation/filesystems/cifs/ksmbd.rst index 01a0be272ce6..1e111efecd45 100644 --- a/Documentation/filesystems/cifs/cifsd.rst +++ b/Documentation/filesystems/cifs/ksmbd.rst @@ -1,13 +1,13 @@ .. SPDX-License-Identifier: GPL-2.0 ========================== -CIFSD - SMB3 Kernel Server +KSMBD - SMB3 Kernel Server ========================== -CIFSD is a linux kernel server which implements SMB3 protocol in kernel space +KSMBD is a linux kernel server which implements SMB3 protocol in kernel space for sharing files over network. -CIFSD architecture +KSMBD architecture ================== The subset of performance related operations belong in kernelspace and @@ -60,7 +60,7 @@ NetServerGetInfo. Complete DCE/RPC response is prepared from the user space and passed over to the associated kernel thread for the client. -CIFSD Feature Status +KSMBD Feature Status ==================== ============================== ================================================= @@ -138,7 +138,7 @@ How to run 6. Access share from Windows or Linux using CIFS -Shutdown CIFSD +Shutdown KSMBD ============== 1. kill user and kernel space daemon diff --git a/MAINTAINERS b/MAINTAINERS index f23bb5cbfd70..6691ac75fce5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4540,16 +4540,6 @@ T: git git://git.samba.org/sfrench/cifs-2.6.git F: Documentation/admin-guide/cifs/ F: fs/cifs/ -COMMON INTERNET FILE SYSTEM SERVER (CIFSD) -M: Namjae Jeon <namjae.jeon@samsung.com> -M: Sergey Senozhatsky <sergey.senozhatsky@gmail.com> -M: Steve French <sfrench@samba.org> -M: Hyunchul Lee <hyc.lee@gmail.com> -L: linux-cifs@vger.kernel.org -L: linux-cifsd-devel@lists.sourceforge.net -S: Maintained -F: fs/cifsd/ - COMPACTPCI HOTPLUG CORE M: Scott Murray <scott@spiteful.org> L: linux-pci@vger.kernel.org @@ -9948,6 +9938,15 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git F: Documentation/dev-tools/kselftest* F: tools/testing/selftests/ +KERNEL SMB3 SERVER (KSMBD) +M: Namjae Jeon <namjae.jeon@samsung.com> +M: Sergey Senozhatsky <senozhatsky@chromium.org> +M: Steve French <sfrench@samba.org> +M: Hyunchul Lee <hyc.lee@gmail.com> +L: linux-cifs@vger.kernel.org +S: Maintained +F: fs/ksmbd/ + KERNEL UNIT TESTING FRAMEWORK (KUnit) M: Brendan Higgins <brendanhiggins@google.com> L: linux-kselftest@vger.kernel.org diff --git a/fs/Kconfig b/fs/Kconfig index 7462761ebd2f..720c38f484c6 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -344,7 +344,7 @@ config NFS_V4_2_SSC_HELPER source "net/sunrpc/Kconfig" source "fs/ceph/Kconfig" source "fs/cifs/Kconfig" -source "fs/cifsd/Kconfig" +source "fs/ksmbd/Kconfig" source "fs/coda/Kconfig" source "fs/afs/Kconfig" source "fs/9p/Kconfig" diff --git a/fs/Makefile b/fs/Makefile index 542a77374d12..e03a048b2cd8 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -98,7 +98,7 @@ obj-$(CONFIG_NLS) += nls/ obj-$(CONFIG_UNICODE) += unicode/ obj-$(CONFIG_SYSV_FS) += sysv/ obj-$(CONFIG_CIFS) += cifs/ -obj-$(CONFIG_SMB_SERVER) += cifsd/ +obj-$(CONFIG_SMB_SERVER) += ksmbd/ obj-$(CONFIG_HPFS_FS) += hpfs/ obj-$(CONFIG_NTFS_FS) += ntfs/ obj-$(CONFIG_UFS_FS) += ufs/ diff --git a/fs/cifsd/buffer_pool.c b/fs/cifsd/buffer_pool.c deleted file mode 100644 index ea7d2d1a056a..000000000000 --- a/fs/cifsd/buffer_pool.c +++ /dev/null @@ -1,265 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#include <linux/kernel.h> -#include <linux/wait.h> -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/vmalloc.h> -#include <linux/rwlock.h> - -#include "glob.h" -#include "buffer_pool.h" -#include "connection.h" -#include "mgmt/ksmbd_ida.h" - -static struct kmem_cache *filp_cache; - -struct wm { - struct list_head list; - unsigned int sz; - char buffer[0]; -}; - -struct wm_list { - struct list_head list; - unsigned int sz; - - spinlock_t wm_lock; - int avail_wm; - struct list_head idle_wm; - wait_queue_head_t wm_wait; -}; - -static LIST_HEAD(wm_lists); -static DEFINE_RWLOCK(wm_lists_lock); - -static struct wm *wm_alloc(size_t sz, gfp_t flags) -{ - struct wm *wm; - size_t alloc_sz = sz + sizeof(struct wm); - - if (sz > SIZE_MAX - sizeof(struct wm)) - return NULL; - - wm = kvmalloc(alloc_sz, flags); - if (!wm) - return NULL; - wm->sz = sz; - return wm; -} - -static int register_wm_size_class(size_t sz) -{ - struct wm_list *l, *nl; - - nl = kmalloc(sizeof(struct wm_list), GFP_KERNEL); - if (!nl) - return -ENOMEM; - - nl->sz = sz; - spin_lock_init(&nl->wm_lock); - INIT_LIST_HEAD(&nl->idle_wm); - INIT_LIST_HEAD(&nl->list); - init_waitqueue_head(&nl->wm_wait); - nl->avail_wm = 0; - - write_lock(&wm_lists_lock); - list_for_each_entry(l, &wm_lists, list) { - if (l->sz == sz) { - write_unlock(&wm_lists_lock); - kfree(nl); - return 0; - } - } - - list_add(&nl->list, &wm_lists); - write_unlock(&wm_lists_lock); - return 0; -} - -static struct wm_list *match_wm_list(size_t size) -{ - struct wm_list *l, *rl = NULL; - - read_lock(&wm_lists_lock); - list_for_each_entry(l, &wm_lists, list) { - if (l->sz == size) { - rl = l; - break; - } - } - read_unlock(&wm_lists_lock); - return rl; -} - -static struct wm *find_wm(size_t size) -{ - struct wm_list *wm_list; - struct wm *wm; - - wm_list = match_wm_list(size); - if (!wm_list) { - if (register_wm_size_class(size)) - return NULL; - wm_list = match_wm_list(size); - } - - if (!wm_list) - return NULL; - - while (1) { - spin_lock(&wm_list->wm_lock); - if (!list_empty(&wm_list->idle_wm)) { - wm = list_entry(wm_list->idle_wm.next, - struct wm, - list); - list_del(&wm->list); - spin_unlock(&wm_list->wm_lock); - return wm; - } - - if (wm_list->avail_wm > num_online_cpus()) { - spin_unlock(&wm_list->wm_lock); - wait_event(wm_list->wm_wait, - !list_empty(&wm_list->idle_wm)); - continue; - } - - wm_list->avail_wm++; - spin_unlock(&wm_list->wm_lock); - - wm = wm_alloc(size, GFP_KERNEL); - if (!wm) { - spin_lock(&wm_list->wm_lock); - wm_list->avail_wm--; - spin_unlock(&wm_list->wm_lock); - wait_event(wm_list->wm_wait, - !list_empty(&wm_list->idle_wm)); - continue; - } - break; - } - - return wm; -} - -static void release_wm(struct wm *wm, struct wm_list *wm_list) -{ - if (!wm) - return; - - spin_lock(&wm_list->wm_lock); - if (wm_list->avail_wm <= num_online_cpus()) { - list_add(&wm->list, &wm_list->idle_wm); - spin_unlock(&wm_list->wm_lock); - wake_up(&wm_list->wm_wait); - return; - } - - wm_list->avail_wm--; - spin_unlock(&wm_list->wm_lock); - kvfree(wm); -} - -static void wm_list_free(struct wm_list *l) -{ - struct wm *wm; - - while (!list_empty(&l->idle_wm)) { - wm = list_entry(l->idle_wm.next, struct wm, list); - list_del(&wm->list); - kvfree(wm); - } - kfree(l); -} - -static void wm_lists_destroy(void) -{ - struct wm_list *l; - - while (!list_empty(&wm_lists)) { - l = list_entry(wm_lists.next, struct wm_list, list); - list_del(&l->list); - wm_list_free(l); - } -} - -void *ksmbd_find_buffer(size_t size) -{ - struct wm *wm; - - wm = find_wm(size); - - WARN_ON(!wm); - if (wm) - return wm->buffer; - return NULL; -} - -void ksmbd_release_buffer(void *buffer) -{ - struct wm_list *wm_list; - struct wm *wm; - - if (!buffer) - return; - - wm = container_of(buffer, struct wm, buffer); - wm_list = match_wm_list(wm->sz); - WARN_ON(!wm_list); - if (wm_list) - release_wm(wm, wm_list); -} - -void *ksmbd_realloc_response(void *ptr, size_t old_sz, size_t new_sz) -{ - size_t sz = min(old_sz, new_sz); - void *nptr; - - nptr = kvmalloc(new_sz, GFP_KERNEL | __GFP_ZERO); - if (!nptr) - return ptr; - memcpy(nptr, ptr, sz); - kvfree(ptr); - return nptr; -} - -void ksmbd_free_file_struct(void *filp) -{ - kmem_cache_free(filp_cache, filp); -} - -void *ksmbd_alloc_file_struct(void) -{ - return kmem_cache_zalloc(filp_cache, GFP_KERNEL); -} - -void ksmbd_destroy_buffer_pools(void) -{ - wm_lists_destroy(); - ksmbd_work_pool_destroy(); - kmem_cache_destroy(filp_cache); -} - -int ksmbd_init_buffer_pools(void) -{ - if (ksmbd_work_pool_init()) - goto out; - - filp_cache = kmem_cache_create("ksmbd_file_cache", - sizeof(struct ksmbd_file), 0, - SLAB_HWCACHE_ALIGN, NULL); - if (!filp_cache) - goto out; - - return 0; - -out: - ksmbd_err("failed to allocate memory\n"); - ksmbd_destroy_buffer_pools(); - return -ENOMEM; -} diff --git a/fs/cifsd/buffer_pool.h b/fs/cifsd/buffer_pool.h deleted file mode 100644 index 088aa07ba09b..000000000000 --- a/fs/cifsd/buffer_pool.h +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2018 Samsung Electronics Co., Ltd. - */ - -#ifndef __KSMBD_BUFFER_POOL_H__ -#define __KSMBD_BUFFER_POOL_H__ - -void *ksmbd_find_buffer(size_t size); -void ksmbd_release_buffer(void *buffer); -void *ksmbd_realloc_response(void *ptr, size_t old_sz, size_t new_sz); -void ksmbd_free_file_struct(void *filp); -void *ksmbd_alloc_file_struct(void); -void ksmbd_destroy_buffer_pools(void); -int ksmbd_init_buffer_pools(void); - -#endif /* __KSMBD_BUFFER_POOL_H__ */ diff --git a/fs/cifsd/Kconfig b/fs/ksmbd/Kconfig index e6448b04f46e..e9a5ac01b6e0 100644 --- a/fs/cifsd/Kconfig +++ b/fs/ksmbd/Kconfig @@ -1,5 +1,5 @@ config SMB_SERVER - tristate "SMB server support (EXPERIMENTAL)" + tristate "SMB3 server support (EXPERIMENTAL)" depends on INET depends on MULTIUSER depends on FILE_LOCKING @@ -19,6 +19,7 @@ config SMB_SERVER select CRYPTO_GCM select ASN1 select OID_REGISTRY + select FS_POSIX_ACL default n help Choose Y here if you want to allow SMB3 compliant clients @@ -30,13 +31,13 @@ config SMB_SERVER case you can choose N here. You also need to install user space programs which can be found - in cifsd-tools, available from - https://github.com/cifsd-team/cifsd-tools. - More detail about how to run the cifsd kernel server is + in ksmbd-tools, available from + https://github.com/cifsd-team/ksmbd-tools. + More detail about how to run the ksmbd kernel server is available via README file - (https://github.com/cifsd-team/cifsd-tools/blob/master/README). + (https://github.com/cifsd-team/ksmbd-tools/blob/master/README). - cifsd kernel server includes support for auto-negotiation, + ksmbd kernel server includes support for auto-negotiation, Secure negotiate, Pre-authentication integrity, oplock/lease, compound requests, multi-credit, packet signing, RDMA(smbdirect), smb3 encryption, copy-offload, secure per-user session @@ -60,7 +61,7 @@ config SMB_SERVER_CHECK_CAP_NET_ADMIN default y help - Prevent unprivileged processes to start the cifsd kernel server. + Prevent unprivileged processes to start the ksmbd kernel server. config SMB_SERVER_KERBEROS5 bool "Support for Kerberos 5" diff --git a/fs/cifsd/Makefile b/fs/ksmbd/Makefile index 30f64b87cf61..7d6337a7dee4 100644 --- a/fs/cifsd/Makefile +++ b/fs/ksmbd/Makefile @@ -4,13 +4,13 @@ # obj-$(CONFIG_SMB_SERVER) += ksmbd.o -ksmbd-y := unicode.o auth.o vfs.o vfs_cache.o server.o buffer_pool.o \ +ksmbd-y := unicode.o auth.o vfs.o vfs_cache.o server.o ndr.o \ misc.o oplock.o connection.o ksmbd_work.o crypto_ctx.o \ mgmt/ksmbd_ida.o mgmt/user_config.o mgmt/share_config.o \ mgmt/tree_connect.o mgmt/user_session.o smb_common.o \ transport_tcp.o transport_ipc.o smbacl.o smb2pdu.o \ smb2ops.o smb2misc.o ksmbd_spnego_negtokeninit.asn1.o \ - ksmbd_spnego_negtokentarg.asn1.o asn1.o ndr.o + ksmbd_spnego_negtokentarg.asn1.o asn1.o $(obj)/asn1.o: $(obj)/ksmbd_spnego_negtokeninit.asn1.h $(obj)/ksmbd_spnego_negtokentarg.asn1.h diff --git a/fs/cifsd/asn1.c b/fs/ksmbd/asn1.c index 2c63a3e5618b..b014f4638610 100644 --- a/fs/cifsd/asn1.c +++ b/fs/ksmbd/asn1.c @@ -66,7 +66,7 @@ static bool asn1_oid_decode(const unsigned char *value, size_t vlen, vlen += 1; if (vlen < 2 || vlen > UINT_MAX / sizeof(unsigned long)) - return false; + goto fail_nullify; *oid = kmalloc(vlen * sizeof(unsigned long), GFP_KERNEL); if (!*oid) @@ -102,6 +102,7 @@ static bool asn1_oid_decode(const unsigned char *value, size_t vlen, fail: kfree(*oid); +fail_nullify: *oid = NULL; return false; } diff --git a/fs/cifsd/asn1.h b/fs/ksmbd/asn1.h index ce105f4ce305..ce105f4ce305 100644 --- a/fs/cifsd/asn1.h +++ b/fs/ksmbd/asn1.h diff --git a/fs/cifsd/auth.c b/fs/ksmbd/auth.c index 5f47de49c05d..de36f12070bf 100644 --- a/fs/cifsd/auth.c +++ b/fs/ksmbd/auth.c @@ -29,7 +29,6 @@ #include "mgmt/user_config.h" #include "crypto_ctx.h" #include "transport_ipc.h" -#include "buffer_pool.h" /* * Fixed format data defining GSS header and fixed string @@ -343,7 +342,7 @@ int ksmbd_auth_ntlm(struct ksmbd_session *sess, char *pw_buf) memcpy(p21, user_passkey(sess->user), CIFS_NTHASH_SIZE); rc = ksmbd_enc_p24(p21, sess->ntlmssp.cryptkey, key); if (rc) { - ksmbd_err("password processing failed\n"); + pr_err("password processing failed\n"); return rc; } @@ -462,7 +461,7 @@ static int __ksmbd_auth_ntlmv2(struct ksmbd_session *sess, char *client_nonce, client_nonce, (char *)sess->ntlmssp.cryptkey, 8); if (rc) { - ksmbd_err("password processing failed\n"); + pr_err("password processing failed\n"); goto out; } @@ -470,7 +469,7 @@ static int __ksmbd_auth_ntlmv2(struct ksmbd_session *sess, char *client_nonce, memcpy(p21, user_passkey(sess->user), CIFS_NTHASH_SIZE); rc = ksmbd_enc_p24(p21, sess_key, key); if (rc) { - ksmbd_err("password processing failed\n"); + pr_err("password processing failed\n"); goto out; } @@ -921,13 +920,14 @@ smb3signkey_ret: } static int generate_smb3signingkey(struct ksmbd_session *sess, + struct ksmbd_conn *conn, const struct derivation *signing) { int rc; struct channel *chann; char *key; - chann = lookup_chann_list(sess); + chann = lookup_chann_list(sess, conn); if (!chann) return 0; @@ -953,7 +953,8 @@ static int generate_smb3signingkey(struct ksmbd_session *sess, return 0; } -int ksmbd_gen_smb30_signingkey(struct ksmbd_session *sess) +int ksmbd_gen_smb30_signingkey(struct ksmbd_session *sess, + struct ksmbd_conn *conn) { struct derivation d; @@ -961,22 +962,32 @@ int ksmbd_gen_smb30_signingkey(struct ksmbd_session *sess) d.label.iov_len = 12; d.context.iov_base = "SmbSign"; d.context.iov_len = 8; - d.binding = false; + d.binding = conn->binding; - return generate_smb3signingkey(sess, &d); + return generate_smb3signingkey(sess, conn, &d); } -int ksmbd_gen_smb311_signingkey(struct ksmbd_session *sess) +int ksmbd_gen_smb311_signingkey(struct ksmbd_session *sess, + struct ksmbd_conn *conn) { struct derivation d; d.label.iov_base = "SMBSigningKey"; d.label.iov_len = 14; - d.context.iov_base = sess->Preauth_HashValue; + if (conn->binding) { + struct preauth_session *preauth_sess; + + preauth_sess = ksmbd_preauth_session_lookup(conn, sess->id); + if (!preauth_sess) + return -ENOENT; + d.context.iov_base = preauth_sess->Preauth_HashValue; + } else { + d.context.iov_base = sess->Preauth_HashValue; + } d.context.iov_len = 64; - d.binding = false; + d.binding = conn->binding; - return generate_smb3signingkey(sess, &d); + return generate_smb3signingkey(sess, conn, &d); } struct derivation_twin { @@ -1148,7 +1159,7 @@ static int ksmbd_get_encryption_key(struct ksmbd_conn *conn, __u64 ses_id, struct ksmbd_session *sess; u8 *ses_enc_key; - sess = ksmbd_session_lookup(conn, ses_id); + sess = ksmbd_session_lookup_all(conn, ses_id); if (!sess) return -EINVAL; @@ -1258,7 +1269,7 @@ int ksmbd_crypt_message(struct ksmbd_conn *conn, struct kvec *iov, enc, key); if (rc) { - ksmbd_err("Could not get %scryption key\n", enc ? "en" : "de"); + pr_err("Could not get %scryption key\n", enc ? "en" : "de"); return rc; } @@ -1268,7 +1279,7 @@ int ksmbd_crypt_message(struct ksmbd_conn *conn, struct kvec *iov, else ctx = ksmbd_crypto_ctx_find_ccm(); if (!ctx) { - ksmbd_err("crypto alloc failed\n"); + pr_err("crypto alloc failed\n"); return -ENOMEM; } @@ -1284,19 +1295,18 @@ int ksmbd_crypt_message(struct ksmbd_conn *conn, struct kvec *iov, else rc = crypto_aead_setkey(tfm, key, SMB3_GCM128_CRYPTKEY_SIZE); if (rc) { - ksmbd_err("Failed to set aead key %d\n", rc); + pr_err("Failed to set aead key %d\n", rc); goto free_ctx; } rc = crypto_aead_setauthsize(tfm, SMB2_SIGNATURE_SIZE); if (rc) { - ksmbd_err("Failed to set authsize %d\n", rc); + pr_err("Failed to set authsize %d\n", rc); goto free_ctx; } req = aead_request_alloc(tfm, GFP_KERNEL); if (!req) { - ksmbd_err("Failed to alloc aead request\n"); rc = -ENOMEM; goto free_ctx; } @@ -1308,7 +1318,7 @@ int ksmbd_crypt_message(struct ksmbd_conn *conn, struct kvec *iov, sg = ksmbd_init_sg(iov, nvec, sign); if (!sg) { - ksmbd_err("Failed to init sg\n"); + pr_err("Failed to init sg\n"); rc = -ENOMEM; goto free_req; } @@ -1316,7 +1326,6 @@ int ksmbd_crypt_message(struct ksmbd_conn *conn, struct kvec *iov, iv_len = crypto_aead_ivsize(tfm); iv = kzalloc(iv_len, GFP_KERNEL); if (!iv) { - ksmbd_err("Failed to alloc IV\n"); rc = -ENOMEM; goto free_sg; } diff --git a/fs/cifsd/auth.h b/fs/ksmbd/auth.h index 650bd7dd6750..9c2d4badd05d 100644 --- a/fs/cifsd/auth.h +++ b/fs/ksmbd/auth.h @@ -54,8 +54,10 @@ int ksmbd_sign_smb2_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov, int n_vec, char *sig); int ksmbd_sign_smb3_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov, int n_vec, char *sig); -int ksmbd_gen_smb30_signingkey(struct ksmbd_session *sess); -int ksmbd_gen_smb311_signingkey(struct ksmbd_session *sess); +int ksmbd_gen_smb30_signingkey(struct ksmbd_session *sess, + struct ksmbd_conn *conn); +int ksmbd_gen_smb311_signingkey(struct ksmbd_session *sess, + struct ksmbd_conn *conn); int ksmbd_gen_smb30_encryptionkey(struct ksmbd_session *sess); int ksmbd_gen_smb311_encryptionkey(struct ksmbd_session *sess); int ksmbd_gen_preauth_integrity_hash(struct ksmbd_conn *conn, char *buf, diff --git a/fs/cifsd/connection.c b/fs/ksmbd/connection.c index 06c42309be72..928e22e19def 100644 --- a/fs/cifsd/connection.c +++ b/fs/ksmbd/connection.c @@ -9,7 +9,6 @@ #include <linux/module.h> #include "server.h" -#include "buffer_pool.h" #include "smb_common.h" #include "mgmt/ksmbd_ida.h" #include "connection.h" @@ -161,7 +160,7 @@ int ksmbd_conn_write(struct ksmbd_work *work) ksmbd_conn_try_dequeue_request(work); if (!rsp_hdr) { - ksmbd_err("NULL response header\n"); + pr_err("NULL response header\n"); return -EINVAL; } @@ -193,7 +192,7 @@ int ksmbd_conn_write(struct ksmbd_work *work) ksmbd_conn_unlock(conn); if (sent < 0) { - ksmbd_err("Failed to send message: %d\n", sent); + pr_err("Failed to send message: %d\n", sent); return sent; } @@ -316,24 +315,23 @@ int ksmbd_conn_handler_loop(void *p) */ size = t->ops->read(t, conn->request_buf + 4, pdu_size); if (size < 0) { - ksmbd_err("sock_read failed: %d\n", size); + pr_err("sock_read failed: %d\n", size); break; } if (size != pdu_size) { - ksmbd_err("PDU error. Read: %d, Expected: %d\n", - size, - pdu_size); + pr_err("PDU error. Read: %d, Expected: %d\n", + size, pdu_size); continue; } if (!default_conn_ops.process_fn) { - ksmbd_err("No connection request callback\n"); + pr_err("No connection request callback\n"); break; } if (default_conn_ops.process_fn(conn)) { - ksmbd_err("Cannot handle request\n"); + pr_err("Cannot handle request\n"); break; } } diff --git a/fs/cifsd/connection.h b/fs/ksmbd/connection.h index 1658442b27b0..98108b41f739 100644 --- a/fs/cifsd/connection.h +++ b/fs/ksmbd/connection.h @@ -106,6 +106,7 @@ struct ksmbd_conn { __le16 cipher_type; __le16 compress_algorithm; bool posix_ext_supported; + bool binding; }; struct ksmbd_conn_ops { diff --git a/fs/cifsd/crypto_ctx.c b/fs/ksmbd/crypto_ctx.c index cfea4c4db30f..5f4b1008d17e 100644 --- a/fs/cifsd/crypto_ctx.c +++ b/fs/ksmbd/crypto_ctx.c @@ -12,7 +12,6 @@ #include "glob.h" #include "crypto_ctx.h" -#include "buffer_pool.h" struct crypto_ctx_list { spinlock_t ctx_lock; @@ -49,12 +48,12 @@ static struct crypto_aead *alloc_aead(int id) tfm = crypto_alloc_aead("ccm(aes)", 0, 0); break; default: - ksmbd_err("Does not support encrypt ahead(id : %d)\n", id); + pr_err("Does not support encrypt ahead(id : %d)\n", id); return NULL; } if (IS_ERR(tfm)) { - ksmbd_err("Failed to alloc encrypt aead : %ld\n", PTR_ERR(tfm)); + pr_err("Failed to alloc encrypt aead : %ld\n", PTR_ERR(tfm)); return NULL; } diff --git a/fs/cifsd/crypto_ctx.h b/fs/ksmbd/crypto_ctx.h index ef11154b43df..ef11154b43df 100644 --- a/fs/cifsd/crypto_ctx.h +++ b/fs/ksmbd/crypto_ctx.h diff --git a/fs/cifsd/glob.h b/fs/ksmbd/glob.h index ffeaf8aa5595..49a5a3afa118 100644 --- a/fs/cifsd/glob.h +++ b/fs/ksmbd/glob.h @@ -14,13 +14,8 @@ #define KSMBD_VERSION "3.1.9" -/* @FIXME clean up this code */ - extern int ksmbd_debug_types; -#define DATA_STREAM 1 -#define DIR_STREAM 2 - #define KSMBD_DEBUG_SMB BIT(0) #define KSMBD_DEBUG_AUTH BIT(1) #define KSMBD_DEBUG_VFS BIT(2) @@ -33,32 +28,22 @@ extern int ksmbd_debug_types; KSMBD_DEBUG_IPC | KSMBD_DEBUG_CONN | \ KSMBD_DEBUG_RDMA) -#ifndef ksmbd_pr_fmt +#ifdef pr_fmt +#undef pr_fmt +#endif + #ifdef SUBMOD_NAME -#define ksmbd_pr_fmt(fmt) "ksmbd: " SUBMOD_NAME ": " fmt +#define pr_fmt(fmt) "ksmbd: " SUBMOD_NAME ": " fmt #else -#define ksmbd_pr_fmt(fmt) "ksmbd: " fmt -#endif +#define pr_fmt(fmt) "ksmbd: " fmt #endif #define ksmbd_debug(type, fmt, ...) \ do { \ if (ksmbd_debug_types & KSMBD_DEBUG_##type) \ - pr_info(ksmbd_pr_fmt("%s:%d: " fmt), \ - __func__, \ - __LINE__, \ - ##__VA_ARGS__); \ + pr_info(fmt, ##__VA_ARGS__); \ } while (0) -#define ksmbd_info(fmt, ...) \ - pr_info(ksmbd_pr_fmt(fmt), ##__VA_ARGS__) - -#define ksmbd_err(fmt, ...) \ - pr_err(ksmbd_pr_fmt("%s:%d: " fmt), \ - __func__, \ - __LINE__, \ - ##__VA_ARGS__) - #define UNICODE_LEN(x) ((x) * 2) #endif /* __KSMBD_GLOB_H */ diff --git a/fs/cifsd/ksmbd_server.h b/fs/ksmbd/ksmbd_netlink.h index 442077a1e77b..2fbe2bc1e093 100644 --- a/fs/cifsd/ksmbd_server.h +++ b/fs/ksmbd/ksmbd_netlink.h @@ -10,17 +10,59 @@ #include <linux/types.h> +/* + * This is a userspace ABI to communicate data between ksmbd and user IPC + * daemon using netlink. This is added to track and cache user account DB + * and share configuration info from userspace. + * + * - KSMBD_EVENT_HEARTBEAT_REQUEST(ksmbd_heartbeat) + * This event is to check whether user IPC daemon is alive. If user IPC + * daemon is dead, ksmbd keep existing connection till disconnecting and + * new connection will be denied. + * + * - KSMBD_EVENT_STARTING_UP(ksmbd_startup_request) + * This event is to receive the information that initializes the ksmbd + * server from the user IPC daemon and to start the server. The global + * section parameters are given from smb.conf as initialization + * information. + * + * - KSMBD_EVENT_SHUTTING_DOWN(ksmbd_shutdown_request) + * This event is to shutdown ksmbd server. + * + * - KSMBD_EVENT_LOGIN_REQUEST/RESPONSE(ksmbd_login_request/response) + * This event is to get user account info to user IPC daemon. + * + * - KSMBD_EVENT_SHARE_CONFIG_REQUEST/RESPONSE(ksmbd_share_config_request/response) + * This event is to get net share configuration info. + * + * - KSMBD_EVENT_TREE_CONNECT_REQUEST/RESPONSE(ksmbd_tree_connect_request/response) + * This event is to get session and tree connect info. + * + * - KSMBD_EVENT_TREE_DISCONNECT_REQUEST(ksmbd_tree_disconnect_request) + * This event is to send tree disconnect info to user IPC daemon. + * + * - KSMBD_EVENT_LOGOUT_REQUEST(ksmbd_logout_request) + * This event is to send logout request to user IPC daemon. + * + * - KSMBD_EVENT_RPC_REQUEST/RESPONSE(ksmbd_rpc_command) + * This event is to make DCE/RPC request like srvsvc, wkssvc, lsarpc, + * samr to be processed in userspace. + * + * - KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST/RESPONSE(ksmbd_spnego_authen_request/response) + * This event is to make kerberos authentication to be processed in + * userspace. + */ + #define KSMBD_GENL_NAME "SMBD_GENL" #define KSMBD_GENL_VERSION 0x01 -#ifndef ____ksmbd_align -#define ____ksmbd_align __aligned(4) -#endif - #define KSMBD_REQ_MAX_ACCOUNT_NAME_SZ 48 #define KSMBD_REQ_MAX_HASH_SZ 18 #define KSMBD_REQ_MAX_SHARE_NAME 64 +/* + * IPC heartbeat frame to check whether user IPC daemon is alive. + */ struct ksmbd_heartbeat { __u32 handle; }; @@ -30,57 +72,82 @@ struct ksmbd_heartbeat { */ #define KSMBD_GLOBAL_FLAG_INVALID (0) #define KSMBD_GLOBAL_FLAG_SMB2_LEASES BIT(0) -#define KSMBD_GLOBAL_FLAG_CACHE_TBUF BIT(1) -#define KSMBD_GLOBAL_FLAG_CACHE_RBUF BIT(2) -#define KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION BIT(3) +#define KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION BIT(1) +#define KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL BIT(2) +/* + * IPC request for ksmbd server startup + */ struct ksmbd_startup_request { - __u32 flags; - __s32 signing; - __s8 min_prot[16]; - __s8 max_prot[16]; + __u32 flags; /* Flags for global config */ + __s32 signing; /* Signing enabled */ + __s8 min_prot[16]; /* The minimum SMB protocol version */ + __s8 max_prot[16]; /* The maximum SMB protocol version */ __s8 netbios_name[16]; - __s8 work_group[64]; - __s8 server_string[64]; - __u16 tcp_port; - __u16 ipc_timeout; - __u32 deadtime; - __u32 file_max; - __u32 smb2_max_write; - __u32 smb2_max_read; - __u32 smb2_max_trans; - __u32 share_fake_fscaps; - __u32 sub_auth[3]; - __u32 ifc_list_sz; - __s8 ____payload[0]; -} ____ksmbd_align; + __s8 work_group[64]; /* Workgroup */ + __s8 server_string[64]; /* Server string */ + __u16 tcp_port; /* tcp port */ + __u16 ipc_timeout; /* + * specifies the number of seconds + * server will wait for the userspace to + * reply to heartbeat frames. + */ + __u32 deadtime; /* Number of minutes of inactivity */ + __u32 file_max; /* Limits the maximum number of open files */ + __u32 smb2_max_write; /* MAX write size */ + __u32 smb2_max_read; /* MAX read size */ + __u32 smb2_max_trans; /* MAX trans size */ + __u32 share_fake_fscaps; /* + * Support some special application that + * makes QFSINFO calls to check whether + * we set the SPARSE_FILES bit (0x40). + */ + __u32 sub_auth[3]; /* Subauth value for Security ID */ + __u32 ifc_list_sz; /* interfaces list size */ + __s8 ____payload[]; +}; #define KSMBD_STARTUP_CONFIG_INTERFACES(s) ((s)->____payload) +/* + * IPC request to shutdown ksmbd server. + */ struct ksmbd_shutdown_request { __s32 reserved; -} ____ksmbd_align; +}; +/* + * IPC user login request. + */ struct ksmbd_login_request { __u32 handle; - __s8 account[KSMBD_REQ_MAX_ACCOUNT_NAME_SZ]; -} ____ksmbd_align; + __s8 account[KSMBD_REQ_MAX_ACCOUNT_NAME_SZ]; /* user account name */ +}; +/* + * IPC user login response. + */ struct ksmbd_login_response { __u32 handle; - __u32 gid; - __u32 uid; - __s8 account[KSMBD_REQ_MAX_ACCOUNT_NAME_SZ]; + __u32 gid; /* group id */ + __u32 uid; /* user id */ + __s8 account[KSMBD_REQ_MAX_ACCOUNT_NAME_SZ]; /* user account name */ __u16 status; - __u16 hash_sz; - __s8 hash[KSMBD_REQ_MAX_HASH_SZ]; -} ____ksmbd_align; + __u16 hash_sz; /* hash size */ + __s8 hash[KSMBD_REQ_MAX_HASH_SZ]; /* password hash */ +}; +/* + * IPC request to fetch net share config. + */ struct ksmbd_share_config_request { __u32 handle; - __s8 share_name[KSMBD_REQ_MAX_SHARE_NAME]; -} ____ksmbd_align; + __s8 share_name[KSMBD_REQ_MAX_SHARE_NAME]; /* share name */ +}; +/* + * IPC response to the net share config request. + */ struct ksmbd_share_config_response { __u32 handle; __u32 flags; @@ -91,18 +158,26 @@ struct ksmbd_share_config_response { __u16 force_uid; __u16 force_gid; __u32 veto_list_sz; - __s8 ____payload[0]; -} ____ksmbd_align; + __s8 ____payload[]; +}; #define KSMBD_SHARE_CONFIG_VETO_LIST(s) ((s)->____payload) -#define KSMBD_SHARE_CONFIG_PATH(s) \ - ({ \ - char *p = (s)->____payload; \ - if ((s)->veto_list_sz) \ - p += (s)->veto_list_sz + 1; \ - p; \ - }) +static inline char * +ksmbd_share_config_path(struct ksmbd_share_config_response *sc) +{ + char *p = sc->____payload; + + if (sc->veto_list_sz) + p += sc->veto_list_sz + 1; + + return p; +} + +/* + * IPC request for tree connection. This request include session and tree + * connect info from client. + */ struct ksmbd_tree_connect_request { __u32 handle; __u16 account_flags; @@ -112,43 +187,74 @@ struct ksmbd_tree_connect_request { __s8 account[KSMBD_REQ_MAX_ACCOUNT_NAME_SZ]; __s8 share[KSMBD_REQ_MAX_SHARE_NAME]; __s8 peer_addr[64]; -} ____ksmbd_align; +}; +/* + * IPC Response structure for tree connection. + */ struct ksmbd_tree_connect_response { __u32 handle; __u16 status; __u16 connection_flags; -} ____ksmbd_align; +}; +/* + * IPC Request struture to disconnect tree connection. + */ struct ksmbd_tree_disconnect_request { - __u64 session_id; - __u64 connect_id; -} ____ksmbd_align; + __u64 session_id; /* session id */ + __u64 connect_id; /* tree connection id */ +}; +/* + * IPC Response structure to logout user account. + */ struct ksmbd_logout_request { - __s8 account[KSMBD_REQ_MAX_ACCOUNT_NAME_SZ]; -} ____ksmbd_align; + __s8 account[KSMBD_REQ_MAX_ACCOUNT_NAME_SZ]; /* user account name */ +}; +/* + * RPC command structure to send rpc request like srvsvc or wkssvc to + * IPC user daemon. + */ struct ksmbd_rpc_command { __u32 handle; __u32 flags; __u32 payload_sz; - __u8 payload[0]; -} ____ksmbd_align; + __u8 payload[]; +}; +/* + * IPC Request Kerberos authentication + */ struct ksmbd_spnego_authen_request { __u32 handle; - __u16 spnego_blob_len; - __u8 spnego_blob[0]; -} ____ksmbd_align; + __u16 spnego_blob_len; /* the length of spnego_blob */ + __u8 spnego_blob[0]; /* + * the GSS token from SecurityBuffer of + * SMB2 SESSION SETUP request + */ +}; +/* + * Response data which includes the GSS token and the session key generated by + * user daemon. + */ struct ksmbd_spnego_authen_response { __u32 handle; - struct ksmbd_login_response login_response; - __u16 session_key_len; - __u16 spnego_blob_len; - __u8 payload[0]; /* session key + AP_REP */ -} ____ksmbd_align; + struct ksmbd_login_response login_response; /* + * the login response with + * a user identified by the + * GSS token from a client + */ + __u16 session_key_len; /* the length of the session key */ + __u16 spnego_blob_len; /* + * the length of the GSS token which will be + * stored in SecurityBuffer of SMB2 SESSION + * SETUP response + */ + __u8 payload[]; /* session key + AP_REP */ +}; /* * This also used as NETLINK attribute type value. @@ -186,6 +292,9 @@ enum ksmbd_event { KSMBD_EVENT_MAX }; +/* + * Enumeration for IPC tree connect status. + */ enum KSMBD_TREE_CONN_STATUS { KSMBD_TREE_CONN_STATUS_OK = 0, KSMBD_TREE_CONN_STATUS_NOMEM, @@ -263,6 +372,9 @@ enum KSMBD_TREE_CONN_STATUS { #define KSMBD_RPC_LSARPC_METHOD_INVOKE BIT(11) #define KSMBD_RPC_LSARPC_METHOD_RETURN (KSMBD_RPC_LSARPC_METHOD_INVOKE | KSMBD_RPC_METHOD_RETURN) +/* + * RPC status definitions. + */ #define KSMBD_RPC_OK 0 #define KSMBD_RPC_EBAD_FUNC 0x00000001 #define KSMBD_RPC_EACCESS_DENIED 0x00000005 diff --git a/fs/cifsd/ksmbd_spnego_negtokeninit.asn1 b/fs/ksmbd/ksmbd_spnego_negtokeninit.asn1 index 0065f191b54b..0065f191b54b 100644 --- a/fs/cifsd/ksmbd_spnego_negtokeninit.asn1 +++ b/fs/ksmbd/ksmbd_spnego_negtokeninit.asn1 diff --git a/fs/cifsd/ksmbd_spnego_negtokentarg.asn1 b/fs/ksmbd/ksmbd_spnego_negtokentarg.asn1 index 1151933e7b9c..1151933e7b9c 100644 --- a/fs/cifsd/ksmbd_spnego_negtokentarg.asn1 +++ b/fs/ksmbd/ksmbd_spnego_negtokentarg.asn1 diff --git a/fs/cifsd/ksmbd_work.c b/fs/ksmbd/ksmbd_work.c index f284a2a803d6..fd58eb4809f6 100644 --- a/fs/cifsd/ksmbd_work.c +++ b/fs/ksmbd/ksmbd_work.c @@ -11,12 +11,8 @@ #include "server.h" #include "connection.h" #include "ksmbd_work.h" -#include "buffer_pool.h" #include "mgmt/ksmbd_ida.h" -/* @FIXME */ -#include "ksmbd_server.h" - static struct kmem_cache *work_cache; static struct workqueue_struct *ksmbd_wq; @@ -38,18 +34,9 @@ struct ksmbd_work *ksmbd_alloc_work_struct(void) void ksmbd_free_work_struct(struct ksmbd_work *work) { WARN_ON(work->saved_cred != NULL); - if (server_conf.flags & KSMBD_GLOBAL_FLAG_CACHE_TBUF && - work->set_trans_buf) - ksmbd_release_buffer(work->response_buf); - else - kvfree(work->response_buf); - - if (server_conf.flags & KSMBD_GLOBAL_FLAG_CACHE_RBUF && - work->set_read_buf) - ksmbd_release_buffer(work->aux_payload_buf); - else - kvfree(work->aux_payload_buf); + kvfree(work->response_buf); + kvfree(work->aux_payload_buf); kfree(work->tr_buf); kvfree(work->request_buf); if (work->async_id) diff --git a/fs/cifsd/ksmbd_work.h b/fs/ksmbd/ksmbd_work.h index 28a1692ed37f..c655bf371ce5 100644 --- a/fs/cifsd/ksmbd_work.h +++ b/fs/ksmbd/ksmbd_work.h @@ -70,8 +70,6 @@ struct ksmbd_work { /* Is this SYNC or ASYNC ksmbd_work */ bool syncronous:1; bool need_invalidate_rkey:1; - bool set_trans_buf:1; - bool set_read_buf:1; unsigned int remote_key; /* cancel works */ @@ -88,14 +86,23 @@ struct ksmbd_work { struct list_head interim_entry; }; -#define WORK_CANCELLED(w) ((w)->state == KSMBD_WORK_CANCELLED) -#define WORK_CLOSED(w) ((w)->state == KSMBD_WORK_CLOSED) -#define WORK_ACTIVE(w) ((w)->state == KSMBD_WORK_ACTIVE) - -#define RESPONSE_BUF_NEXT(w) \ - (((w)->response_buf + (w)->next_smb2_rsp_hdr_off)) -#define REQUEST_BUF_NEXT(w) \ - (((w)->request_buf + (w)->next_smb2_rcv_hdr_off)) +/** + * ksmbd_resp_buf_next - Get next buffer on compound response. + * @work: smb work containing response buffer + */ +static inline void *ksmbd_resp_buf_next(struct ksmbd_work *work) +{ + return work->response_buf + work->next_smb2_rsp_hdr_off; +} + +/** + * ksmbd_req_buf_next - Get next buffer on compound request. + * @work: smb work containing response buffer + */ +static inline void *ksmbd_req_buf_next(struct ksmbd_work *work) +{ + return work->request_buf + work->next_smb2_rcv_hdr_off; +} struct ksmbd_work *ksmbd_alloc_work_struct(void); void ksmbd_free_work_struct(struct ksmbd_work *work); diff --git a/fs/cifsd/mgmt/ksmbd_ida.c b/fs/ksmbd/mgmt/ksmbd_ida.c index 54194d959a5e..54194d959a5e 100644 --- a/fs/cifsd/mgmt/ksmbd_ida.c +++ b/fs/ksmbd/mgmt/ksmbd_ida.c diff --git a/fs/cifsd/mgmt/ksmbd_ida.h b/fs/ksmbd/mgmt/ksmbd_ida.h index 2bc07b16cfde..2bc07b16cfde 100644 --- a/fs/cifsd/mgmt/ksmbd_ida.h +++ b/fs/ksmbd/mgmt/ksmbd_ida.h diff --git a/fs/cifsd/mgmt/share_config.c b/fs/ksmbd/mgmt/share_config.c index bcc4ae4381b9..cb72d30f5b71 100644 --- a/fs/cifsd/mgmt/share_config.c +++ b/fs/ksmbd/mgmt/share_config.c @@ -15,7 +15,6 @@ #include "share_config.h" #include "user_config.h" #include "user_session.h" -#include "../buffer_pool.h" #include "../transport_ipc.h" #define SHARE_HASH_BITS 3 @@ -140,7 +139,7 @@ static struct ksmbd_share_config *share_config_request(char *name) share->name = kstrdup(name, GFP_KERNEL); if (!test_share_config_flag(share, KSMBD_SHARE_FLAG_PIPE)) { - share->path = kstrdup(KSMBD_SHARE_CONFIG_PATH(resp), + share->path = kstrdup(ksmbd_share_config_path(resp), GFP_KERNEL); if (share->path) share->path_sz = strlen(share->path); diff --git a/fs/cifsd/mgmt/share_config.h b/fs/ksmbd/mgmt/share_config.h index 953befc94e84..953befc94e84 100644 --- a/fs/cifsd/mgmt/share_config.h +++ b/fs/ksmbd/mgmt/share_config.h diff --git a/fs/cifsd/mgmt/tree_connect.c b/fs/ksmbd/mgmt/tree_connect.c index 029a9e81e844..0d28e723a28c 100644 --- a/fs/cifsd/mgmt/tree_connect.c +++ b/fs/ksmbd/mgmt/tree_connect.c @@ -7,7 +7,6 @@ #include <linux/slab.h> #include <linux/xarray.h> -#include "../buffer_pool.h" #include "../transport_ipc.h" #include "../connection.h" diff --git a/fs/cifsd/mgmt/tree_connect.h b/fs/ksmbd/mgmt/tree_connect.h index 4e40ec3f4774..18e2a996e0aa 100644 --- a/fs/cifsd/mgmt/tree_connect.h +++ b/fs/ksmbd/mgmt/tree_connect.h @@ -8,7 +8,7 @@ #include <linux/hashtable.h> -#include "../ksmbd_server.h" +#include "../ksmbd_netlink.h" struct ksmbd_share_config; struct ksmbd_user; diff --git a/fs/cifsd/mgmt/user_config.c b/fs/ksmbd/mgmt/user_config.c index 7f898c5bda25..d21629ae5c89 100644 --- a/fs/cifsd/mgmt/user_config.c +++ b/fs/ksmbd/mgmt/user_config.c @@ -7,7 +7,6 @@ #include <linux/mm.h> #include "user_config.h" -#include "../buffer_pool.h" #include "../transport_ipc.h" struct ksmbd_user *ksmbd_login_user(const char *account) diff --git a/fs/cifsd/mgmt/user_config.h b/fs/ksmbd/mgmt/user_config.h index b2bb074a0150..b2bb074a0150 100644 --- a/fs/cifsd/mgmt/user_config.h +++ b/fs/ksmbd/mgmt/user_config.h diff --git a/fs/cifsd/mgmt/user_session.c b/fs/ksmbd/mgmt/user_session.c index 739588a6c96a..8d8ffd8c6f19 100644 --- a/fs/cifsd/mgmt/user_session.c +++ b/fs/ksmbd/mgmt/user_session.c @@ -14,7 +14,6 @@ #include "tree_connect.h" #include "../transport_ipc.h" #include "../connection.h" -#include "../buffer_pool.h" #include "../vfs_cache.h" static DEFINE_IDA(session_ida); @@ -31,15 +30,12 @@ struct ksmbd_session_rpc { static void free_channel_list(struct ksmbd_session *sess) { - struct channel *chann; - struct list_head *tmp, *t; - - list_for_each_safe(tmp, t, &sess->ksmbd_chann_list) { - chann = list_entry(tmp, struct channel, chann_list); - if (chann) { - list_del(&chann->chann_list); - kfree(chann); - } + struct channel *chann, *tmp; + + list_for_each_entry_safe(chann, tmp, &sess->ksmbd_chann_list, + chann_list) { + list_del(&chann->chann_list); + kfree(chann); } } @@ -88,7 +84,7 @@ static int __rpc_method(char *rpc_name) if (!strcmp(rpc_name, "\\lsarpc") || !strcmp(rpc_name, "lsarpc")) return KSMBD_RPC_LSARPC_METHOD_INVOKE; - ksmbd_err("Unsupported RPC: %s\n", rpc_name); + pr_err("Unsupported RPC: %s\n", rpc_name); return 0; } @@ -158,11 +154,9 @@ void ksmbd_session_destroy(struct ksmbd_session *sess) list_del(&sess->sessions_entry); - if (IS_SMB2(sess->conn)) { - down_write(&sessions_table_lock); - hash_del(&sess->hlist); - up_write(&sessions_table_lock); - } + down_write(&sessions_table_lock); + hash_del(&sess->hlist); + up_write(&sessions_table_lock); if (sess->user) ksmbd_free_user(sess->user); @@ -207,7 +201,8 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn) } } -bool ksmbd_session_id_match(struct ksmbd_session *sess, unsigned long long id) +static bool ksmbd_session_id_match(struct ksmbd_session *sess, + unsigned long long id) { return sess->id == id; } @@ -232,7 +227,7 @@ int get_session(struct ksmbd_session *sess) void put_session(struct ksmbd_session *sess) { if (atomic_dec_and_test(&sess->refcnt)) - ksmbd_err("get/%s seems to be mismatched.", __func__); + pr_err("get/%s seems to be mismatched.", __func__); } struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id) @@ -250,6 +245,52 @@ struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id) return sess; } +struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn, + unsigned long long id) +{ + struct ksmbd_session *sess; + + sess = ksmbd_session_lookup(conn, id); + if (!sess && conn->binding) + sess = ksmbd_session_lookup_slowpath(id); + return sess; +} + +struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn, + u64 sess_id) +{ + struct preauth_session *sess; + + sess = kmalloc(sizeof(struct preauth_session), GFP_KERNEL); + if (!sess) + return NULL; + + sess->id = sess_id; + memcpy(sess->Preauth_HashValue, conn->preauth_info->Preauth_HashValue, + PREAUTH_HASHVALUE_SIZE); + list_add(&sess->preauth_entry, &conn->preauth_sess_table); + + return sess; +} + +static bool ksmbd_preauth_session_id_match(struct preauth_session *sess, + unsigned long long id) +{ + return sess->id == id; +} + +struct preauth_session *ksmbd_preauth_session_lookup(struct ksmbd_conn *conn, + unsigned long long id) +{ + struct preauth_session *sess = NULL; + + list_for_each_entry(sess, &conn->preauth_sess_table, preauth_entry) { + if (ksmbd_preauth_session_id_match(sess, id)) + return sess; + } + return NULL; +} + static int __init_smb2_session(struct ksmbd_session *sess) { int id = ksmbd_acquire_smb2_uid(&session_ida); diff --git a/fs/cifsd/mgmt/user_session.h b/fs/ksmbd/mgmt/user_session.h index 761bf4776cf1..82289c3cbd2b 100644 --- a/fs/cifsd/mgmt/user_session.h +++ b/fs/ksmbd/mgmt/user_session.h @@ -26,8 +26,8 @@ struct channel { struct preauth_session { __u8 Preauth_HashValue[PREAUTH_HASHVALUE_SIZE]; - u64 sess_id; - struct list_head list_entry; + u64 id; + struct list_head preauth_entry; }; struct ksmbd_session { @@ -82,13 +82,18 @@ struct ksmbd_session *ksmbd_smb2_session_create(void); void ksmbd_session_destroy(struct ksmbd_session *sess); -bool ksmbd_session_id_match(struct ksmbd_session *sess, unsigned long long id); struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id); struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn, unsigned long long id); void ksmbd_session_register(struct ksmbd_conn *conn, struct ksmbd_session *sess); void ksmbd_sessions_deregister(struct ksmbd_conn *conn); +struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn, + unsigned long long id); +struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn, + u64 sess_id); +struct preauth_session *ksmbd_preauth_session_lookup(struct ksmbd_conn *conn, + unsigned long long id); int ksmbd_acquire_tree_conn_id(struct ksmbd_session *sess); void ksmbd_release_tree_conn_id(struct ksmbd_session *sess, int id); diff --git a/fs/cifsd/misc.c b/fs/ksmbd/misc.c index 1c6ed20f4a18..0b307ca28a19 100644 --- a/fs/cifsd/misc.c +++ b/fs/ksmbd/misc.c @@ -107,7 +107,7 @@ static int ksmbd_validate_stream_name(char *stream_name) stream_name++; if (c == '/' || c == ':' || c == '\\') { - ksmbd_err("Stream name validation failed: %c\n", c); + pr_err("Stream name validation failed: %c\n", c); return -ENOENT; } } diff --git a/fs/cifsd/misc.h b/fs/ksmbd/misc.h index af8717d4d85b..af8717d4d85b 100644 --- a/fs/cifsd/misc.h +++ b/fs/ksmbd/misc.h diff --git a/fs/cifsd/ndr.c b/fs/ksmbd/ndr.c index 14189832c65e..cf0df78259c9 100644 --- a/fs/cifsd/ndr.c +++ b/fs/ksmbd/ndr.c @@ -9,21 +9,9 @@ #include "glob.h" #include "ndr.h" -#define PAYLOAD_HEAD(d) ((d)->data + (d)->offset) - -#define KSMBD_ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) - -#define KSMBD_ALIGN(x, a) \ - ({ \ - typeof(x) ret = (x); \ - if (((x) & ((typeof(x))(a) - 1)) != 0) \ - ret = KSMBD_ALIGN_MASK(x, (typeof(x))(a) - 1); \ - ret; \ - }) - -static void align_offset(struct ndr *ndr, int n) +static inline char *ndr_get_field(struct ndr *n) { - ndr->offset = KSMBD_ALIGN(ndr->offset, n); + return n->data + n->offset; } static int try_to_realloc_ndr_blob(struct ndr *n, size_t sz) @@ -45,7 +33,7 @@ static void ndr_write_int16(struct ndr *n, __u16 value) if (n->length <= n->offset + sizeof(value)) try_to_realloc_ndr_blob(n, sizeof(value)); - *(__le16 *)PAYLOAD_HEAD(n) = cpu_to_le16(value); + *(__le16 *)ndr_get_field(n) = cpu_to_le16(value); n->offset += sizeof(value); } @@ -54,7 +42,7 @@ static void ndr_write_int32(struct ndr *n, __u32 value) if (n->length <= n->offset + sizeof(value)) try_to_realloc_ndr_blob(n, sizeof(value)); - *(__le32 *)PAYLOAD_HEAD(n) = cpu_to_le32(value); + *(__le32 *)ndr_get_field(n) = cpu_to_le32(value); n->offset += sizeof(value); } @@ -63,7 +51,7 @@ static void ndr_write_int64(struct ndr *n, __u64 value) if (n->length <= n->offset + sizeof(value)) try_to_realloc_ndr_blob(n, sizeof(value)); - *(__le64 *)PAYLOAD_HEAD(n) = cpu_to_le64(value); + *(__le64 *)ndr_get_field(n) = cpu_to_le64(value); n->offset += sizeof(value); } @@ -72,7 +60,7 @@ static int ndr_write_bytes(struct ndr *n, void *value, size_t sz) if (n->length <= n->offset + sz) try_to_realloc_ndr_blob(n, sz); - memcpy(PAYLOAD_HEAD(n), value, sz); + memcpy(ndr_get_field(n), value, sz); n->offset += sz; return 0; } @@ -82,27 +70,27 @@ static int ndr_write_string(struct ndr *n, void *value, size_t sz) if (n->length <= n->offset + sz) try_to_realloc_ndr_blob(n, sz); - strncpy(PAYLOAD_HEAD(n), value, sz); + strncpy(ndr_get_field(n), value, sz); sz++; n->offset += sz; - align_offset(n, 2); + n->offset = ALIGN(n->offset, 2); return 0; } static int ndr_read_string(struct ndr *n, void *value, size_t sz) { - int len = strnlen(PAYLOAD_HEAD(n), sz); + int len = strnlen(ndr_get_field(n), sz); - memcpy(value, PAYLOAD_HEAD(n), len); + memcpy(value, ndr_get_field(n), len); len++; n->offset += len; - align_offset(n, 2); + n->offset = ALIGN(n->offset, 2); return 0; } static int ndr_read_bytes(struct ndr *n, void *value, size_t sz) { - memcpy(value, PAYLOAD_HEAD(n), sz); + memcpy(value, ndr_get_field(n), sz); n->offset += sz; return 0; } @@ -111,7 +99,7 @@ static __u16 ndr_read_int16(struct ndr *n) { __u16 ret; - ret = le16_to_cpu(*(__le16 *)PAYLOAD_HEAD(n)); + ret = le16_to_cpu(*(__le16 *)ndr_get_field(n)); n->offset += sizeof(__u16); return ret; } @@ -120,7 +108,7 @@ static __u32 ndr_read_int32(struct ndr *n) { __u32 ret; - ret = le32_to_cpu(*(__le32 *)PAYLOAD_HEAD(n)); + ret = le32_to_cpu(*(__le32 *)ndr_get_field(n)); n->offset += sizeof(__u32); return ret; } @@ -129,7 +117,7 @@ static __u64 ndr_read_int64(struct ndr *n) { __u64 ret; - ret = le64_to_cpu(*(__le64 *)PAYLOAD_HEAD(n)); + ret = le64_to_cpu(*(__le64 *)ndr_get_field(n)); n->offset += sizeof(__u64); return ret; } @@ -178,14 +166,14 @@ int ndr_decode_dos_attr(struct ndr *n, struct xattr_dos_attrib *da) da->version = ndr_read_int16(n); if (da->version != 3 && da->version != 4) { - ksmbd_err("v%d version is not supported\n", da->version); + pr_err("v%d version is not supported\n", da->version); return -EINVAL; } version2 = ndr_read_int32(n); if (da->version != version2) { - ksmbd_err("ndr version mismatched(version: %d, version2: %d)\n", - da->version, version2); + pr_err("ndr version mismatched(version: %d, version2: %d)\n", + da->version, version2); return -EINVAL; } @@ -210,20 +198,20 @@ static int ndr_encode_posix_acl_entry(struct ndr *n, struct xattr_smb_acl *acl) int i; ndr_write_int32(n, acl->count); - align_offset(n, 8); + n->offset = ALIGN(n->offset, 8); ndr_write_int32(n, acl->count); ndr_write_int32(n, 0); for (i = 0; i < acl->count; i++) { - align_offset(n, 8); + n->offset = ALIGN(n->offset, 8); ndr_write_int16(n, acl->entries[i].type); ndr_write_int16(n, acl->entries[i].type); if (acl->entries[i].type == SMB_ACL_USER) { - align_offset(n, 8); + n->offset = ALIGN(n->offset, 8); ndr_write_int64(n, acl->entries[i].uid); } else if (acl->entries[i].type == SMB_ACL_GROUP) { - align_offset(n, 8); + n->offset = ALIGN(n->offset, 8); ndr_write_int64(n, acl->entries[i].gid); } @@ -234,7 +222,9 @@ static int ndr_encode_posix_acl_entry(struct ndr *n, struct xattr_smb_acl *acl) return 0; } -int ndr_encode_posix_acl(struct ndr *n, struct inode *inode, +int ndr_encode_posix_acl(struct ndr *n, + struct user_namespace *user_ns, + struct inode *inode, struct xattr_smb_acl *acl, struct xattr_smb_acl *def_acl) { @@ -262,8 +252,8 @@ int ndr_encode_posix_acl(struct ndr *n, struct inode *inode, ndr_write_int32(n, 0); } - ndr_write_int64(n, from_kuid(&init_user_ns, inode->i_uid)); - ndr_write_int64(n, from_kgid(&init_user_ns, inode->i_gid)); + ndr_write_int64(n, from_kuid(user_ns, inode->i_uid)); + ndr_write_int64(n, from_kgid(user_ns, inode->i_gid)); ndr_write_int32(n, inode->i_mode); if (acl) { @@ -309,14 +299,14 @@ int ndr_decode_v4_ntacl(struct ndr *n, struct xattr_ntacl *acl) n->offset = 0; acl->version = ndr_read_int16(n); if (acl->version != 4) { - ksmbd_err("v%d version is not supported\n", acl->version); + pr_err("v%d version is not supported\n", acl->version); return -EINVAL; } version2 = ndr_read_int32(n); if (acl->version != version2) { - ksmbd_err("ndr version mismatched(version: %d, version2: %d)\n", - acl->version, version2); + pr_err("ndr version mismatched(version: %d, version2: %d)\n", + acl->version, version2); return -EINVAL; } @@ -329,7 +319,7 @@ int ndr_decode_v4_ntacl(struct ndr *n, struct xattr_ntacl *acl) ndr_read_bytes(n, acl->desc, 10); if (strncmp(acl->desc, "posix_acl", 9)) { - ksmbd_err("Invalid acl description : %s\n", acl->desc); + pr_err("Invalid acl description : %s\n", acl->desc); return -EINVAL; } diff --git a/fs/cifsd/ndr.h b/fs/ksmbd/ndr.h index 77b2d1ac93a0..60ca265d1bb0 100644 --- a/fs/cifsd/ndr.h +++ b/fs/ksmbd/ndr.h @@ -14,8 +14,8 @@ struct ndr { int ndr_encode_dos_attr(struct ndr *n, struct xattr_dos_attrib *da); int ndr_decode_dos_attr(struct ndr *n, struct xattr_dos_attrib *da); -int ndr_encode_posix_acl(struct ndr *n, struct inode *inode, - struct xattr_smb_acl *acl, +int ndr_encode_posix_acl(struct ndr *n, struct user_namespace *user_ns, + struct inode *inode, struct xattr_smb_acl *acl, struct xattr_smb_acl *def_acl); int ndr_encode_v4_ntacl(struct ndr *n, struct xattr_ntacl *acl); int ndr_encode_v3_ntacl(struct ndr *n, struct xattr_ntacl *acl); diff --git a/fs/cifsd/nterr.h b/fs/ksmbd/nterr.h index 2f358f88a018..2f358f88a018 100644 --- a/fs/cifsd/nterr.h +++ b/fs/ksmbd/nterr.h diff --git a/fs/cifsd/ntlmssp.h b/fs/ksmbd/ntlmssp.h index adaf4c0cbe8f..adaf4c0cbe8f 100644 --- a/fs/cifsd/ntlmssp.h +++ b/fs/ksmbd/ntlmssp.h diff --git a/fs/cifsd/oplock.c b/fs/ksmbd/oplock.c index 5868cdca7187..5484b5bf75b0 100644 --- a/fs/cifsd/oplock.c +++ b/fs/ksmbd/oplock.c @@ -11,7 +11,6 @@ #include "smb_common.h" #include "smbstatus.h" -#include "buffer_pool.h" #include "connection.h" #include "mgmt/user_session.h" #include "mgmt/share_config.h" @@ -40,7 +39,7 @@ static struct oplock_info *alloc_opinfo(struct ksmbd_work *work, opinfo->sess = sess; opinfo->conn = sess->conn; - opinfo->level = OPLOCK_NONE; + opinfo->level = SMB2_OPLOCK_LEVEL_NONE; opinfo->op_state = OPLOCK_STATE_NONE; opinfo->pending_break = 0; opinfo->fid = id; @@ -231,9 +230,9 @@ int opinfo_write_to_read(struct oplock_info *opinfo) if (!(opinfo->level == SMB2_OPLOCK_LEVEL_BATCH || opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE)) { - ksmbd_err("bad oplock(0x%x)\n", opinfo->level); + pr_err("bad oplock(0x%x)\n", opinfo->level); if (opinfo->is_lease) - ksmbd_err("lease state(0x%x)\n", lease->state); + pr_err("lease state(0x%x)\n", lease->state); return -EINVAL; } opinfo->level = SMB2_OPLOCK_LEVEL_II; @@ -270,9 +269,9 @@ int opinfo_write_to_none(struct oplock_info *opinfo) if (!(opinfo->level == SMB2_OPLOCK_LEVEL_BATCH || opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE)) { - ksmbd_err("bad oplock(0x%x)\n", opinfo->level); + pr_err("bad oplock(0x%x)\n", opinfo->level); if (opinfo->is_lease) - ksmbd_err("lease state(0x%x)\n", lease->state); + pr_err("lease state(0x%x)\n", lease->state); return -EINVAL; } opinfo->level = SMB2_OPLOCK_LEVEL_NONE; @@ -292,9 +291,9 @@ int opinfo_read_to_none(struct oplock_info *opinfo) struct lease *lease = opinfo->o_lease; if (opinfo->level != SMB2_OPLOCK_LEVEL_II) { - ksmbd_err("bad oplock(0x%x)\n", opinfo->level); + pr_err("bad oplock(0x%x)\n", opinfo->level); if (opinfo->is_lease) - ksmbd_err("lease state(0x%x)\n", lease->state); + pr_err("lease state(0x%x)\n", lease->state); return -EINVAL; } opinfo->level = SMB2_OPLOCK_LEVEL_NONE; @@ -623,7 +622,7 @@ static void __smb2_oplock_break_noti(struct work_struct *wk) } if (allocate_oplock_break_buf(work)) { - ksmbd_err("smb2_allocate_rsp_buf failed! "); + pr_err("smb2_allocate_rsp_buf failed! "); atomic_dec(&conn->r_count); ksmbd_fd_put(work, fp); ksmbd_free_work_struct(work); @@ -632,7 +631,8 @@ static void __smb2_oplock_break_noti(struct work_struct *wk) rsp_hdr = work->response_buf; memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2); - rsp_hdr->smb2_buf_length = cpu_to_be32(HEADER_SIZE_NO_BUF_LEN(conn)); + rsp_hdr->smb2_buf_length = + cpu_to_be32(smb2_hdr_size_no_buflen(conn->vals)); rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER; rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE; rsp_hdr->CreditRequest = cpu_to_le16(0); @@ -738,7 +738,8 @@ static void __smb2_lease_break_noti(struct work_struct *wk) rsp_hdr = work->response_buf; memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2); - rsp_hdr->smb2_buf_length = cpu_to_be32(HEADER_SIZE_NO_BUF_LEN(conn)); + rsp_hdr->smb2_buf_length = + cpu_to_be32(smb2_hdr_size_no_buflen(conn->vals)); rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER; rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE; rsp_hdr->CreditRequest = cpu_to_le16(0); @@ -1110,7 +1111,9 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid, goto set_lev; /* grant none-oplock if second open is trunc */ - if (ATTR_FP(fp)) { + if (fp->attrib_only && fp->cdoption != FILE_OVERWRITE_IF_LE && + fp->cdoption != FILE_OVERWRITE_LE && + fp->cdoption != FILE_SUPERSEDE_LE) { req_op_level = SMB2_OPLOCK_LEVEL_NONE; goto set_lev; } @@ -1578,7 +1581,7 @@ void create_disk_id_rsp_buf(char *cc, __u64 file_id, __u64 vol_id) void create_posix_rsp_buf(char *cc, struct ksmbd_file *fp) { struct create_posix_rsp *buf; - struct inode *inode = FP_INODE(fp); + struct inode *inode = file_inode(fp->filp); buf = (struct create_posix_rsp *)cc; memset(buf, 0, sizeof(struct create_posix_rsp)); @@ -1609,9 +1612,9 @@ void create_posix_rsp_buf(char *cc, struct ksmbd_file *fp) buf->nlink = cpu_to_le32(inode->i_nlink); buf->reparse_tag = cpu_to_le32(fp->volatile_id); buf->mode = cpu_to_le32(inode->i_mode); - id_to_sid(from_kuid(&init_user_ns, inode->i_uid), + id_to_sid(from_kuid(file_mnt_user_ns(fp->filp), inode->i_uid), SIDNFS_USER, (struct smb_sid *)&buf->SidBuffer[0]); - id_to_sid(from_kgid(&init_user_ns, inode->i_gid), + id_to_sid(from_kgid(file_mnt_user_ns(fp->filp), inode->i_gid), SIDNFS_GROUP, (struct smb_sid *)&buf->SidBuffer[20]); } @@ -1681,18 +1684,18 @@ int smb2_check_durable_oplock(struct ksmbd_file *fp, if (opinfo && opinfo->is_lease) { if (!lctx) { - ksmbd_err("open does not include lease\n"); + pr_err("open does not include lease\n"); ret = -EBADF; goto out; } if (memcmp(opinfo->o_lease->lease_key, lctx->lease_key, SMB2_LEASE_KEY_SIZE)) { - ksmbd_err("invalid lease key\n"); + pr_err("invalid lease key\n"); ret = -EBADF; goto out; } if (name && strcmp(fp->filename, name)) { - ksmbd_err("invalid name reconnect %s\n", name); + pr_err("invalid name reconnect %s\n", name); ret = -EINVAL; goto out; } diff --git a/fs/cifsd/oplock.h b/fs/ksmbd/oplock.h index 9fb7ea74e86c..119b8047cfbd 100644 --- a/fs/cifsd/oplock.h +++ b/fs/ksmbd/oplock.h @@ -11,12 +11,6 @@ #define OPLOCK_WAIT_TIME (35 * HZ) -/* SMB Oplock levels */ -#define OPLOCK_NONE 0 -#define OPLOCK_EXCLUSIVE 1 -#define OPLOCK_BATCH 2 -#define OPLOCK_READ 3 /* level 2 oplock */ - /* SMB2 Oplock levels */ #define SMB2_OPLOCK_LEVEL_NONE 0x00 #define SMB2_OPLOCK_LEVEL_II 0x01 diff --git a/fs/cifsd/server.c b/fs/ksmbd/server.c index a99963b849d5..a8c59e96a2f7 100644 --- a/fs/cifsd/server.c +++ b/fs/ksmbd/server.c @@ -16,7 +16,6 @@ #include "server.h" #include "smb_common.h" #include "smbstatus.h" -#include "buffer_pool.h" #include "connection.h" #include "transport_ipc.h" #include "mgmt/user_session.h" @@ -278,7 +277,7 @@ static int queue_ksmbd_work(struct ksmbd_conn *conn) work = ksmbd_alloc_work_struct(); if (!work) { - ksmbd_err("allocation for work failed\n"); + pr_err("allocation for work failed\n"); return -ENOMEM; } @@ -443,7 +442,7 @@ static ssize_t kill_server_store(struct class *class, if (!sysfs_streq(buf, "hard")) return len; - ksmbd_info("kill command received\n"); + pr_info("kill command received\n"); mutex_lock(&ctrl_lock); WRITE_ONCE(server_conf.state, SERVER_STATE_RESETTING); __module_get(THIS_MODULE); @@ -536,7 +535,8 @@ static int ksmbd_server_shutdown(void) ksmbd_crypto_destroy(); ksmbd_free_global_file_table(); destroy_lease_table(NULL); - ksmbd_destroy_buffer_pools(); + ksmbd_work_pool_destroy(); + ksmbd_exit_file_cache(); server_conf_free(); return 0; } @@ -547,7 +547,7 @@ static int __init ksmbd_server_init(void) ret = class_register(&ksmbd_control_class); if (ret) { - ksmbd_err("Unable to register ksmbd-control class\n"); + pr_err("Unable to register ksmbd-control class\n"); return ret; } @@ -557,13 +557,17 @@ static int __init ksmbd_server_init(void) if (ret) goto err_unregister; - ret = ksmbd_init_buffer_pools(); + ret = ksmbd_work_pool_init(); if (ret) goto err_unregister; + ret = ksmbd_init_file_cache(); + if (ret) + goto err_destroy_work_pools; + ret = ksmbd_ipc_init(); if (ret) - goto err_free_session_table; + goto err_exit_file_cache; ret = ksmbd_init_global_file_table(); if (ret) @@ -590,8 +594,10 @@ err_destroy_file_table: ksmbd_free_global_file_table(); err_ipc_release: ksmbd_ipc_release(); -err_free_session_table: - ksmbd_destroy_buffer_pools(); +err_exit_file_cache: + ksmbd_exit_file_cache(); +err_destroy_work_pools: + ksmbd_work_pool_destroy(); err_unregister: class_unregister(&ksmbd_control_class); diff --git a/fs/cifsd/server.h b/fs/ksmbd/server.h index b682d28963e8..ac9d932f8c8a 100644 --- a/fs/cifsd/server.h +++ b/fs/ksmbd/server.h @@ -8,14 +8,24 @@ #include "smbacl.h" -#define SERVER_STATE_STARTING_UP 0 -#define SERVER_STATE_RUNNING 1 -#define SERVER_STATE_RESETTING 2 -#define SERVER_STATE_SHUTTING_DOWN 3 - -#define SERVER_CONF_NETBIOS_NAME 0 -#define SERVER_CONF_SERVER_STRING 1 -#define SERVER_CONF_WORK_GROUP 2 +/* + * Server state type + */ +enum { + SERVER_STATE_STARTING_UP, + SERVER_STATE_RUNNING, + SERVER_STATE_RESETTING, + SERVER_STATE_SHUTTING_DOWN, +}; + +/* + * Server global config string index + */ +enum { + SERVER_CONF_NETBIOS_NAME, + SERVER_CONF_SERVER_STRING, + SERVER_CONF_WORK_GROUP, +}; struct ksmbd_server_config { unsigned int flags; diff --git a/fs/cifsd/smb2misc.c b/fs/ksmbd/smb2misc.c index c4b870dbf683..4508631c5706 100644 --- a/fs/cifsd/smb2misc.c +++ b/fs/ksmbd/smb2misc.c @@ -317,15 +317,13 @@ static int smb2_validate_credit_charge(struct smb2_hdr *hdr) return 0; } + credit_charge = max(1, credit_charge); max_len = max(req_len, expect_resp_len); calc_credit_num = DIV_ROUND_UP(max_len, SMB2_MAX_BUFFER_SIZE); - if (!credit_charge && max_len > SMB2_MAX_BUFFER_SIZE) { - ksmbd_err("credit charge is zero and payload size(%d) is bigger than 64K\n", - max_len); - return 1; - } else if (credit_charge < calc_credit_num) { - ksmbd_err("credit charge : %d, calc_credit_num : %d\n", - credit_charge, calc_credit_num); + + if (credit_charge < calc_credit_num) { + pr_err("Insufficient credit charge, given: %d, needed: %d\n", + credit_charge, calc_credit_num); return 1; } @@ -341,7 +339,7 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work) __u32 len = get_rfc1002_len(pdu); if (work->next_smb2_rcv_hdr_off) { - pdu = REQUEST_BUF_NEXT(work); + pdu = ksmbd_req_buf_next(work); hdr = &pdu->hdr; } diff --git a/fs/cifsd/smb2ops.c b/fs/ksmbd/smb2ops.c index 8999c3faf4fc..8262908e467c 100644 --- a/fs/cifsd/smb2ops.c +++ b/fs/ksmbd/smb2ops.c @@ -12,7 +12,6 @@ #include "connection.h" #include "smb_common.h" #include "server.h" -#include "ksmbd_server.h" static struct smb_version_values smb21_server_values = { .version_string = SMB21_VERSION_STRING, @@ -229,6 +228,9 @@ void init_smb3_0_server(struct ksmbd_conn *conn) if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION && conn->cli_cap & SMB2_GLOBAL_CAP_ENCRYPTION) conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION; + + if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) + conn->vals->capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL; } /** @@ -250,6 +252,9 @@ void init_smb3_02_server(struct ksmbd_conn *conn) if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION && conn->cli_cap & SMB2_GLOBAL_CAP_ENCRYPTION) conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION; + + if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) + conn->vals->capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL; } /** @@ -271,6 +276,9 @@ int init_smb3_11_server(struct ksmbd_conn *conn) if (conn->cipher_type) conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION; + if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) + conn->vals->capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL; + INIT_LIST_HEAD(&conn->preauth_sess_table); return 0; } diff --git a/fs/cifsd/smb2pdu.c b/fs/ksmbd/smb2pdu.c index ac15a9287310..dda90812feef 100644 --- a/fs/cifsd/smb2pdu.c +++ b/fs/ksmbd/smb2pdu.c @@ -10,6 +10,7 @@ #include <linux/namei.h> #include <linux/statfs.h> #include <linux/ethtool.h> +#include <linux/falloc.h> #include "glob.h" #include "smb2pdu.h" @@ -19,7 +20,6 @@ #include "auth.h" #include "asn1.h" -#include "buffer_pool.h" #include "connection.h" #include "transport_ipc.h" #include "vfs.h" @@ -40,8 +40,8 @@ static void __wbuf(struct ksmbd_work *work, void **req, void **rsp) { if (work->next_smb2_rcv_hdr_off) { - *req = REQUEST_BUF_NEXT(work); - *rsp = RESPONSE_BUF_NEXT(work); + *req = ksmbd_req_buf_next(work); + *rsp = ksmbd_resp_buf_next(work); } else { *req = work->request_buf; *rsp = work->response_buf; @@ -64,21 +64,19 @@ static inline int check_session_id(struct ksmbd_conn *conn, u64 id) if (id == 0 || id == -1) return 0; - sess = ksmbd_session_lookup(conn, id); + sess = ksmbd_session_lookup_all(conn, id); if (sess) return 1; - ksmbd_err("Invalid user session id: %llu\n", id); + pr_err("Invalid user session id: %llu\n", id); return 0; } -struct channel *lookup_chann_list(struct ksmbd_session *sess) +struct channel *lookup_chann_list(struct ksmbd_session *sess, struct ksmbd_conn *conn) { struct channel *chann; - struct list_head *t; - list_for_each(t, &sess->ksmbd_chann_list) { - chann = list_entry(t, struct channel, chann_list); - if (chann && chann->conn == sess->conn) + list_for_each_entry(chann, &sess->ksmbd_chann_list, chann_list) { + if (chann->conn == conn) return chann; } @@ -112,7 +110,7 @@ int smb2_get_ksmbd_tcon(struct ksmbd_work *work) tree_id = le32_to_cpu(req_hdr->Id.SyncId.TreeId); work->tcon = ksmbd_tree_conn_lookup(work->sess, tree_id); if (!work->tcon) { - ksmbd_err("Invalid tid %d\n", tree_id); + pr_err("Invalid tid %d\n", tree_id); return -1; } @@ -128,7 +126,7 @@ void smb2_set_err_rsp(struct ksmbd_work *work) struct smb2_err_rsp *err_rsp; if (work->next_smb2_rcv_hdr_off) - err_rsp = RESPONSE_BUF_NEXT(work); + err_rsp = ksmbd_resp_buf_next(work); else err_rsp = work->response_buf; @@ -198,7 +196,7 @@ u16 get_smb2_cmd_val(struct ksmbd_work *work) struct smb2_hdr *rcv_hdr; if (work->next_smb2_rcv_hdr_off) - rcv_hdr = REQUEST_BUF_NEXT(work); + rcv_hdr = ksmbd_req_buf_next(work); else rcv_hdr = work->request_buf; return le16_to_cpu(rcv_hdr->Command); @@ -214,7 +212,7 @@ void set_smb2_rsp_status(struct ksmbd_work *work, __le32 err) struct smb2_hdr *rsp_hdr; if (work->next_smb2_rcv_hdr_off) - rsp_hdr = RESPONSE_BUF_NEXT(work); + rsp_hdr = ksmbd_resp_buf_next(work); else rsp_hdr = work->response_buf; rsp_hdr->Status = err; @@ -245,7 +243,7 @@ int init_smb2_neg_rsp(struct ksmbd_work *work) memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2); rsp_hdr->smb2_buf_length = - cpu_to_be32(HEADER_SIZE_NO_BUF_LEN(conn)); + cpu_to_be32(smb2_hdr_size_no_buflen(conn->vals)); rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER; rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE; @@ -317,8 +315,8 @@ static int smb2_consume_credit_charge(struct ksmbd_work *work, */ int smb2_set_rsp_credits(struct ksmbd_work *work) { - struct smb2_hdr *req_hdr = REQUEST_BUF_NEXT(work); - struct smb2_hdr *hdr = RESPONSE_BUF_NEXT(work); + struct smb2_hdr *req_hdr = ksmbd_req_buf_next(work); + struct smb2_hdr *hdr = ksmbd_resp_buf_next(work); struct ksmbd_conn *conn = work->conn; unsigned short credits_requested = le16_to_cpu(req_hdr->CreditRequest); unsigned short credit_charge = 1, credits_granted = 0; @@ -332,7 +330,7 @@ int smb2_set_rsp_credits(struct ksmbd_work *work) min_credits = conn->max_credits >> 4; if (conn->total_credits >= conn->max_credits) { - ksmbd_err("Total credits overflow: %d\n", conn->total_credits); + pr_err("Total credits overflow: %d\n", conn->total_credits); conn->total_credits = min_credits; } @@ -385,8 +383,8 @@ out: */ static void init_chained_smb2_rsp(struct ksmbd_work *work) { - struct smb2_hdr *req = REQUEST_BUF_NEXT(work); - struct smb2_hdr *rsp = RESPONSE_BUF_NEXT(work); + struct smb2_hdr *req = ksmbd_req_buf_next(work); + struct smb2_hdr *rsp = ksmbd_resp_buf_next(work); struct smb2_hdr *rsp_hdr; struct smb2_hdr *rcv_hdr; int next_hdr_offset = 0; @@ -424,8 +422,8 @@ static void init_chained_smb2_rsp(struct ksmbd_work *work) new_len, work->next_smb2_rcv_hdr_off, work->next_smb2_rsp_hdr_off); - rsp_hdr = RESPONSE_BUF_NEXT(work); - rcv_hdr = REQUEST_BUF_NEXT(work); + rsp_hdr = ksmbd_resp_buf_next(work); + rcv_hdr = ksmbd_req_buf_next(work); if (!(rcv_hdr->Flags & SMB2_FLAGS_RELATED_OPERATIONS)) { ksmbd_debug(SMB, "related flag should be set\n"); @@ -464,7 +462,7 @@ bool is_chained_smb2_message(struct ksmbd_work *work) if (hdr->ProtocolId != SMB2_PROTO_NUMBER) return false; - hdr = REQUEST_BUF_NEXT(work); + hdr = ksmbd_req_buf_next(work); if (le32_to_cpu(hdr->NextCommand) > 0) { ksmbd_debug(SMB, "got SMB2 chained command\n"); init_chained_smb2_rsp(work); @@ -499,7 +497,8 @@ int init_smb2_rsp_hdr(struct ksmbd_work *work) struct ksmbd_conn *conn = work->conn; memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2); - rsp_hdr->smb2_buf_length = cpu_to_be32(HEADER_SIZE_NO_BUF_LEN(conn)); + rsp_hdr->smb2_buf_length = + cpu_to_be32(smb2_hdr_size_no_buflen(conn->vals)); rsp_hdr->ProtocolId = rcv_hdr->ProtocolId; rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE; rsp_hdr->Command = rcv_hdr->Command; @@ -538,10 +537,8 @@ int smb2_allocate_rsp_buf(struct ksmbd_work *work) size_t sz = small_sz; int cmd = le16_to_cpu(hdr->Command); - if (cmd == SMB2_IOCTL_HE || cmd == SMB2_QUERY_DIRECTORY_HE) { + if (cmd == SMB2_IOCTL_HE || cmd == SMB2_QUERY_DIRECTORY_HE) sz = large_sz; - work->set_trans_buf = true; - } if (cmd == SMB2_QUERY_INFO_HE) { struct smb2_query_info_req *req; @@ -549,22 +546,15 @@ int smb2_allocate_rsp_buf(struct ksmbd_work *work) req = work->request_buf; if (req->InfoType == SMB2_O_INFO_FILE && (req->FileInfoClass == FILE_FULL_EA_INFORMATION || - req->FileInfoClass == FILE_ALL_INFORMATION)) { + req->FileInfoClass == FILE_ALL_INFORMATION)) sz = large_sz; - work->set_trans_buf = true; - } } /* allocate large response buf for chained commands */ if (le32_to_cpu(hdr->NextCommand) > 0) sz = large_sz; - if (server_conf.flags & KSMBD_GLOBAL_FLAG_CACHE_TBUF && - work->set_trans_buf) - work->response_buf = ksmbd_find_buffer(sz); - else - work->response_buf = kvmalloc(sz, GFP_KERNEL | __GFP_ZERO); - + work->response_buf = kvmalloc(sz, GFP_KERNEL | __GFP_ZERO); if (!work->response_buf) return -ENOMEM; @@ -600,7 +590,7 @@ int smb2_check_user_session(struct ksmbd_work *work) sess_id = le64_to_cpu(req_hdr->SessionId); /* Check for validity of user session */ - work->sess = ksmbd_session_lookup(conn, sess_id); + work->sess = ksmbd_session_lookup_all(conn, sess_id); if (work->sess) return 1; ksmbd_debug(SMB, "Invalid user session, Uid %llu\n", sess_id); @@ -646,7 +636,7 @@ smb2_get_name(struct ksmbd_share_config *share, const char *src, name = smb_strndup_from_utf16(src, maxlen, 1, local_nls); if (IS_ERR(name)) { - ksmbd_err("failed to get name %ld\n", PTR_ERR(name)); + pr_err("failed to get name %ld\n", PTR_ERR(name)); return name; } @@ -657,7 +647,7 @@ smb2_get_name(struct ksmbd_share_config *share, const char *src, unixname = convert_to_unix_name(share, name); kfree(name); if (!unixname) { - ksmbd_err("can not convert absolute name\n"); + pr_err("can not convert absolute name\n"); return ERR_PTR(-ENOMEM); } @@ -676,7 +666,7 @@ int setup_async_work(struct ksmbd_work *work, void (*fn)(void **), void **arg) id = ksmbd_acquire_async_msg_id(&conn->async_ida); if (id < 0) { - ksmbd_err("Failed to alloc async message id\n"); + pr_err("Failed to alloc async message id\n"); return id; } work->syncronous = false; @@ -1017,13 +1007,13 @@ int smb2_handle_negotiate(struct ksmbd_work *work) ksmbd_debug(SMB, "Received negotiate request\n"); conn->need_neg = false; if (ksmbd_conn_good(work)) { - ksmbd_err("conn->tcp_status is already in CifsGood State\n"); + pr_err("conn->tcp_status is already in CifsGood State\n"); work->send_no_response = 1; return rc; } if (req->DialectCount == 0) { - ksmbd_err("malformed packet\n"); + pr_err("malformed packet\n"); rsp->hdr.Status = STATUS_INVALID_PARAMETER; rc = -EINVAL; goto err_out; @@ -1043,8 +1033,8 @@ int smb2_handle_negotiate(struct ksmbd_work *work) status = deassemble_neg_contexts(conn, req); if (status != STATUS_SUCCESS) { - ksmbd_err("deassemble_neg_contexts error(0x%x)\n", - status); + pr_err("deassemble_neg_contexts error(0x%x)\n", + status); rsp->hdr.Status = status; rc = -EINVAL; goto err_out; @@ -1165,18 +1155,30 @@ static int generate_preauth_hash(struct ksmbd_work *work) { struct ksmbd_conn *conn = work->conn; struct ksmbd_session *sess = work->sess; + u8 *preauth_hash; if (conn->dialect != SMB311_PROT_ID) return 0; - if (!sess->Preauth_HashValue) { - if (alloc_preauth_hash(sess, conn)) - return -ENOMEM; + if (conn->binding) { + struct preauth_session *preauth_sess; + + preauth_sess = ksmbd_preauth_session_lookup(conn, sess->id); + if (!preauth_sess) { + preauth_sess = ksmbd_preauth_session_alloc(conn, sess->id); + if (!preauth_sess) + return -ENOMEM; + } + + preauth_hash = preauth_sess->Preauth_HashValue; + } else { + if (!sess->Preauth_HashValue) + if (alloc_preauth_hash(sess, conn)) + return -ENOMEM; + preauth_hash = sess->Preauth_HashValue; } - ksmbd_gen_preauth_integrity_hash(conn, - work->request_buf, - sess->Preauth_HashValue); + ksmbd_gen_preauth_integrity_hash(conn, work->request_buf, preauth_hash); return 0; } @@ -1293,7 +1295,7 @@ static struct ksmbd_user *session_user(struct ksmbd_conn *conn, true, conn->local_nls); if (IS_ERR(name)) { - ksmbd_err("cannot allocate memory\n"); + pr_err("cannot allocate memory\n"); return NULL; } @@ -1383,15 +1385,19 @@ static int ntlm_authenticate(struct ksmbd_work *work) * that it is reauthentication. And the user/password * has been verified, so return it here. */ - if (sess->state == SMB2_SESSION_VALID) + if (sess->state == SMB2_SESSION_VALID) { + if (conn->binding) + goto binding_session; return 0; + } if ((conn->sign || server_conf.enforced_signing) || (req->SecurityMode & SMB2_NEGOTIATE_SIGNING_REQUIRED)) sess->sign = true; if (conn->vals->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION && - conn->ops->generate_encryptionkey) { + conn->ops->generate_encryptionkey && + !(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) { rc = conn->ops->generate_encryptionkey(sess); if (rc) { ksmbd_debug(SMB, @@ -1409,8 +1415,9 @@ static int ntlm_authenticate(struct ksmbd_work *work) } } +binding_session: if (conn->dialect >= SMB30_PROT_ID) { - chann = lookup_chann_list(sess); + chann = lookup_chann_list(sess, conn); if (!chann) { chann = kmalloc(sizeof(struct channel), GFP_KERNEL); if (!chann) @@ -1423,7 +1430,7 @@ static int ntlm_authenticate(struct ksmbd_work *work) } if (conn->ops->generate_signingkey) { - rc = conn->ops->generate_signingkey(sess); + rc = conn->ops->generate_signingkey(sess, conn); if (rc) { ksmbd_debug(SMB, "SMB3 signing key generation failed\n"); rsp->hdr.Status = STATUS_LOGON_FAILURE; @@ -1433,7 +1440,7 @@ static int ntlm_authenticate(struct ksmbd_work *work) if (conn->dialect > SMB20_PROT_ID) { if (!ksmbd_conn_lookup_dialect(conn)) { - ksmbd_err("fail to verify the dialect\n"); + pr_err("fail to verify the dialect\n"); rsp->hdr.Status = STATUS_USER_SESSION_DELETED; return -EPERM; } @@ -1500,7 +1507,7 @@ static int krb5_authenticate(struct ksmbd_work *work) } if (conn->dialect >= SMB30_PROT_ID) { - chann = lookup_chann_list(sess); + chann = lookup_chann_list(sess, conn); if (!chann) { chann = kmalloc(sizeof(struct channel), GFP_KERNEL); if (!chann) @@ -1513,7 +1520,7 @@ static int krb5_authenticate(struct ksmbd_work *work) } if (conn->ops->generate_signingkey) { - retval = conn->ops->generate_signingkey(sess); + retval = conn->ops->generate_signingkey(sess, conn); if (retval) { ksmbd_debug(SMB, "SMB3 signing key generation failed\n"); rsp->hdr.Status = STATUS_LOGON_FAILURE; @@ -1523,7 +1530,7 @@ static int krb5_authenticate(struct ksmbd_work *work) if (conn->dialect > SMB20_PROT_ID) { if (!ksmbd_conn_lookup_dialect(conn)) { - ksmbd_err("fail to verify the dialect\n"); + pr_err("fail to verify the dialect\n"); rsp->hdr.Status = STATUS_USER_SESSION_DELETED; return -EPERM; } @@ -1562,12 +1569,59 @@ int smb2_sess_setup(struct ksmbd_work *work) } rsp->hdr.SessionId = cpu_to_le64(sess->id); ksmbd_session_register(conn, sess); + } else if (conn->dialect >= SMB30_PROT_ID && + (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) && + req->Flags & SMB2_SESSION_REQ_FLAG_BINDING) { + u64 sess_id = le64_to_cpu(req->hdr.SessionId); + + sess = ksmbd_session_lookup_slowpath(sess_id); + if (!sess) { + rc = -ENOENT; + goto out_err; + } + + if (conn->dialect != sess->conn->dialect) { + rc = -EINVAL; + goto out_err; + } + + if (!(req->hdr.Flags & SMB2_FLAGS_SIGNED)) { + rc = -EINVAL; + goto out_err; + } + + if (strncmp(conn->ClientGUID, sess->conn->ClientGUID, + SMB2_CLIENT_GUID_SIZE)) { + rc = -ENOENT; + goto out_err; + } + + if (sess->state == SMB2_SESSION_IN_PROGRESS) { + rc = -EACCES; + goto out_err; + } + + if (sess->state == SMB2_SESSION_EXPIRED) { + rc = -EFAULT; + goto out_err; + } + + if (ksmbd_session_lookup(conn, sess_id)) { + rc = -EACCES; + goto out_err; + } + + conn->binding = true; + } else if ((conn->dialect < SMB30_PROT_ID || + server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) && + (req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) { + rc = -EACCES; + goto out_err; } else { sess = ksmbd_session_lookup(conn, le64_to_cpu(req->hdr.SessionId)); if (!sess) { rc = -ENOENT; - rsp->hdr.Status = STATUS_USER_SESSION_DELETED; goto out_err; } } @@ -1585,15 +1639,15 @@ int smb2_sess_setup(struct ksmbd_work *work) } if (server_conf.auth_mechs & conn->auth_mechs) { + rc = generate_preauth_hash(work); + if (rc) + goto out_err; + if (conn->preferred_auth_mech & (KSMBD_AUTH_KRB5 | KSMBD_AUTH_MSKRB5)) { - rc = generate_preauth_hash(work); - if (rc) - goto out_err; - rc = krb5_authenticate(work); if (rc) { - rsp->hdr.Status = STATUS_INVALID_PARAMETER; + rc = -EINVAL; goto out_err; } @@ -1602,10 +1656,6 @@ int smb2_sess_setup(struct ksmbd_work *work) kfree(sess->Preauth_HashValue); sess->Preauth_HashValue = NULL; } else if (conn->preferred_auth_mech == KSMBD_AUTH_NTLMSSP) { - rc = generate_preauth_hash(work); - if (rc) - goto out_err; - if (negblob->MessageType == NtLmNegotiate) { rc = ntlm_negotiate(work, negblob); if (rc) @@ -1625,22 +1675,41 @@ int smb2_sess_setup(struct ksmbd_work *work) ksmbd_conn_set_good(work); sess->state = SMB2_SESSION_VALID; + if (conn->binding) { + struct preauth_session *preauth_sess; + + preauth_sess = + ksmbd_preauth_session_lookup(conn, sess->id); + if (preauth_sess) { + list_del(&preauth_sess->preauth_entry); + kfree(preauth_sess); + } + } kfree(sess->Preauth_HashValue); sess->Preauth_HashValue = NULL; } } else { /* TODO: need one more negotiation */ - ksmbd_err("Not support the preferred authentication\n"); + pr_err("Not support the preferred authentication\n"); rc = -EINVAL; - rsp->hdr.Status = STATUS_INVALID_PARAMETER; } } else { - ksmbd_err("Not support authentication\n"); + pr_err("Not support authentication\n"); rc = -EINVAL; - rsp->hdr.Status = STATUS_INVALID_PARAMETER; } out_err: + if (rc == -EINVAL) + rsp->hdr.Status = STATUS_INVALID_PARAMETER; + else if (rc == -ENOENT) + rsp->hdr.Status = STATUS_USER_SESSION_DELETED; + else if (rc == -EACCES) + rsp->hdr.Status = STATUS_REQUEST_NOT_ACCEPTED; + else if (rc == -EFAULT) + rsp->hdr.Status = STATUS_NETWORK_SESSION_EXPIRED; + else if (rc) + rsp->hdr.Status = STATUS_LOGON_FAILURE; + if (conn->use_spnego && conn->mechToken) { kfree(conn->mechToken); conn->mechToken = NULL; @@ -1675,7 +1744,7 @@ int smb2_tree_connect(struct ksmbd_work *work) le16_to_cpu(req->PathLength), true, conn->local_nls); if (IS_ERR(treename)) { - ksmbd_err("treename is NULL\n"); + pr_err("treename is NULL\n"); status.ret = KSMBD_TREE_CONN_STATUS_ERROR; goto out_err1; } @@ -1768,21 +1837,27 @@ out_err1: * @file_present: is file already present * @access: file access flags * @disposition: file disposition flags + * @may_flags: set with MAY_ flags * * Return: file open flags */ static int smb2_create_open_flags(bool file_present, __le32 access, - __le32 disposition) + __le32 disposition, + int *may_flags) { int oflags = O_NONBLOCK | O_LARGEFILE; if (access & FILE_READ_DESIRED_ACCESS_LE && - access & FILE_WRITE_DESIRE_ACCESS_LE) + access & FILE_WRITE_DESIRE_ACCESS_LE) { oflags |= O_RDWR; - else if (access & FILE_WRITE_DESIRE_ACCESS_LE) + *may_flags = MAY_OPEN | MAY_READ | MAY_WRITE; + } else if (access & FILE_WRITE_DESIRE_ACCESS_LE) { oflags |= O_WRONLY; - else + *may_flags = MAY_OPEN | MAY_WRITE; + } else { oflags |= O_RDONLY; + *may_flags = MAY_OPEN | MAY_READ; + } if (access == FILE_READ_ATTRIBUTES_LE) oflags |= O_PATH; @@ -1816,6 +1891,7 @@ static int smb2_create_open_flags(bool file_present, __le32 access, break; } } + return oflags; } @@ -1919,7 +1995,7 @@ static noinline int create_smb2_pipe(struct ksmbd_work *work) id = ksmbd_session_rpc_open(work->sess, name); if (id < 0) { - ksmbd_err("Unable to open RPC pipe: %d\n", id); + pr_err("Unable to open RPC pipe: %d\n", id); err = id; goto out; } @@ -2005,14 +2081,16 @@ static int smb2_set_ea(struct smb2_ea_info *eabuf, struct path *path) value = (char *)&eabuf->name + eabuf->EaNameLength + 1; if (!eabuf->EaValueLength) { - rc = ksmbd_vfs_casexattr_len(path->dentry, + rc = ksmbd_vfs_casexattr_len(mnt_user_ns(path->mnt), + path->dentry, attr_name, XATTR_USER_PREFIX_LEN + eabuf->EaNameLength); /* delete the EA only when it exits */ if (rc > 0) { - rc = ksmbd_vfs_remove_xattr(path->dentry, + rc = ksmbd_vfs_remove_xattr(mnt_user_ns(path->mnt), + path->dentry, attr_name); if (rc < 0) { @@ -2026,7 +2104,8 @@ static int smb2_set_ea(struct smb2_ea_info *eabuf, struct path *path) /* if the EA doesn't exist, just do nothing. */ rc = 0; } else { - rc = ksmbd_vfs_setxattr(path->dentry, attr_name, value, + rc = ksmbd_vfs_setxattr(mnt_user_ns(path->mnt), + path->dentry, attr_name, value, le16_to_cpu(eabuf->EaValueLength), 0); if (rc < 0) { ksmbd_debug(SMB, @@ -2053,7 +2132,7 @@ static inline int check_context_err(void *ctx, char *str) ksmbd_debug(SMB, "find context %s err %d\n", str, err); if (err == -EINVAL) { - ksmbd_err("bad name length\n"); + pr_err("bad name length\n"); return err; } @@ -2079,7 +2158,8 @@ static noinline int smb2_set_stream_name_xattr(struct path *path, fp->stream.size = xattr_stream_size; /* Check if there is stream prefix in xattr space */ - rc = ksmbd_vfs_casexattr_len(path->dentry, + rc = ksmbd_vfs_casexattr_len(mnt_user_ns(path->mnt), + path->dentry, xattr_stream_name, xattr_stream_size); if (rc >= 0) @@ -2090,19 +2170,20 @@ static noinline int smb2_set_stream_name_xattr(struct path *path, return -EBADF; } - rc = ksmbd_vfs_setxattr(path->dentry, xattr_stream_name, NULL, 0, 0); + rc = ksmbd_vfs_setxattr(mnt_user_ns(path->mnt), + path->dentry, xattr_stream_name, NULL, 0, 0); if (rc < 0) - ksmbd_err("Failed to store XATTR stream name :%d\n", rc); + pr_err("Failed to store XATTR stream name :%d\n", rc); return 0; } -static int smb2_remove_smb_xattrs(struct dentry *dentry) +static int smb2_remove_smb_xattrs(struct path *path) { char *name, *xattr_list = NULL; ssize_t xattr_list_len; int err = 0; - xattr_list_len = ksmbd_vfs_listxattr(dentry, &xattr_list); + xattr_list_len = ksmbd_vfs_listxattr(path->dentry, &xattr_list); if (xattr_list_len < 0) { goto out; } else if (!xattr_list_len) { @@ -2120,7 +2201,8 @@ static int smb2_remove_smb_xattrs(struct dentry *dentry) strncmp(&name[XATTR_USER_PREFIX_LEN], STREAM_PREFIX, STREAM_PREFIX_LEN)) continue; - err = ksmbd_vfs_remove_xattr(dentry, name); + err = ksmbd_vfs_remove_xattr(mnt_user_ns(path->mnt), + path->dentry, name); if (err) ksmbd_debug(SMB, "remove xattr failed : %s\n", name); } @@ -2134,11 +2216,11 @@ static int smb2_create_truncate(struct path *path) int rc = vfs_truncate(path, 0); if (rc) { - ksmbd_err("vfs_truncate failed, rc %d\n", rc); + pr_err("vfs_truncate failed, rc %d\n", rc); return rc; } - rc = smb2_remove_smb_xattrs(path->dentry); + rc = smb2_remove_smb_xattrs(path); if (rc == -EOPNOTSUPP) rc = 0; if (rc) @@ -2164,7 +2246,8 @@ static void smb2_new_xattrs(struct ksmbd_tree_connect *tcon, struct path *path, da.flags = XATTR_DOSINFO_ATTRIB | XATTR_DOSINFO_CREATE_TIME | XATTR_DOSINFO_ITIME; - rc = ksmbd_vfs_set_dos_attrib_xattr(path->dentry, &da); + rc = ksmbd_vfs_set_dos_attrib_xattr(mnt_user_ns(path->mnt), + path->dentry, &da); if (rc) ksmbd_debug(SMB, "failed to store file attribute into xattr\n"); } @@ -2182,7 +2265,8 @@ static void smb2_update_xattrs(struct ksmbd_tree_connect *tcon, KSMBD_SHARE_FLAG_STORE_DOS_ATTRS)) return; - rc = ksmbd_vfs_get_dos_attrib_xattr(path->dentry, &da); + rc = ksmbd_vfs_get_dos_attrib_xattr(mnt_user_ns(path->mnt), + path->dentry, &da); if (rc > 0) { fp->f_ci->m_fattr = cpu_to_le32(da.attr); fp->create_time = da.create_time; @@ -2220,8 +2304,8 @@ static int smb2_creat(struct ksmbd_work *work, struct path *path, char *name, rc = ksmbd_vfs_kern_path(name, 0, path, 0); if (rc) { - ksmbd_err("cannot get linux path (%s), err = %d\n", - name, rc); + pr_err("cannot get linux path (%s), err = %d\n", + name, rc); return rc; } return 0; @@ -2229,7 +2313,7 @@ static int smb2_creat(struct ksmbd_work *work, struct path *path, char *name, static int smb2_create_sd_buffer(struct ksmbd_work *work, struct smb2_create_req *req, - struct dentry *dentry) + struct path *path) { struct create_context *context; int rc = -ENOENT; @@ -2245,7 +2329,8 @@ static int smb2_create_sd_buffer(struct ksmbd_work *work, ksmbd_debug(SMB, "Set ACLs using SMB2_CREATE_SD_BUFFER context\n"); sd_buf = (struct create_sd_buf_req *)context; - rc = set_info_sec(work->conn, work->tcon, dentry, &sd_buf->ntsd, + rc = set_info_sec(work->conn, work->tcon, + path, &sd_buf->ntsd, le32_to_cpu(sd_buf->ccontext.DataLength), true); } @@ -2259,9 +2344,9 @@ static void ksmbd_acls_fattr(struct smb_fattr *fattr, struct inode *inode) fattr->cf_mode = inode->i_mode; fattr->cf_dacls = NULL; - fattr->cf_acls = ksmbd_vfs_get_acl(inode, ACL_TYPE_ACCESS); + fattr->cf_acls = get_acl(inode, ACL_TYPE_ACCESS); if (S_ISDIR(inode->i_mode)) - fattr->cf_dacls = ksmbd_vfs_get_acl(inode, ACL_TYPE_DEFAULT); + fattr->cf_dacls = get_acl(inode, ACL_TYPE_DEFAULT); } /** @@ -2287,7 +2372,7 @@ int smb2_open(struct ksmbd_work *work) struct create_ea_buf_req *ea_buf = NULL; struct oplock_info *opinfo; __le32 *next_ptr = NULL; - int req_op_level = 0, open_flags = 0, file_info = 0; + int req_op_level = 0, open_flags = 0, may_flags = 0, file_info = 0; int rc = 0, len = 0; int contxt_cnt = 0, query_disk_id = 0; int maximal_access_ctxt = 0, posix_ctxt = 0; @@ -2320,7 +2405,7 @@ int smb2_open(struct ksmbd_work *work) if (req->NameLength) { if ((req->CreateOptions & FILE_DIRECTORY_FILE_LE) && *(char *)req->Buffer == '\\') { - ksmbd_err("not allow directory name included leading slash\n"); + pr_err("not allow directory name included leading slash\n"); rc = -EINVAL; goto err_out1; } @@ -2377,16 +2462,16 @@ int smb2_open(struct ksmbd_work *work) lc = parse_lease_state(req); if (le32_to_cpu(req->ImpersonationLevel) > le32_to_cpu(IL_DELEGATE_LE)) { - ksmbd_err("Invalid impersonationlevel : 0x%x\n", - le32_to_cpu(req->ImpersonationLevel)); + pr_err("Invalid impersonationlevel : 0x%x\n", + le32_to_cpu(req->ImpersonationLevel)); rc = -EIO; rsp->hdr.Status = STATUS_BAD_IMPERSONATION_LEVEL; goto err_out1; } if (req->CreateOptions && !(req->CreateOptions & CREATE_OPTIONS_MASK)) { - ksmbd_err("Invalid create options : 0x%x\n", - le32_to_cpu(req->CreateOptions)); + pr_err("Invalid create options : 0x%x\n", + le32_to_cpu(req->CreateOptions)); rc = -EINVAL; goto err_out1; } else { @@ -2413,22 +2498,22 @@ int smb2_open(struct ksmbd_work *work) if (le32_to_cpu(req->CreateDisposition) > le32_to_cpu(FILE_OVERWRITE_IF_LE)) { - ksmbd_err("Invalid create disposition : 0x%x\n", - le32_to_cpu(req->CreateDisposition)); + pr_err("Invalid create disposition : 0x%x\n", + le32_to_cpu(req->CreateDisposition)); rc = -EINVAL; goto err_out1; } if (!(req->DesiredAccess & DESIRED_ACCESS_MASK)) { - ksmbd_err("Invalid desired access : 0x%x\n", - le32_to_cpu(req->DesiredAccess)); + pr_err("Invalid desired access : 0x%x\n", + le32_to_cpu(req->DesiredAccess)); rc = -EACCES; goto err_out1; } if (req->FileAttributes && !(req->FileAttributes & ATTR_MASK_LE)) { - ksmbd_err("Invalid file attribute : 0x%x\n", - le32_to_cpu(req->FileAttributes)); + pr_err("Invalid file attribute : 0x%x\n", + le32_to_cpu(req->FileAttributes)); rc = -EINVAL; goto err_out1; } @@ -2557,7 +2642,7 @@ int smb2_open(struct ksmbd_work *work) rc = 0; } else { file_present = true; - generic_fillattr(&init_user_ns, d_inode(path.dentry), &stat); + generic_fillattr(mnt_user_ns(path.mnt), d_inode(path.dentry), &stat); } if (stream_name) { if (req->CreateOptions & FILE_DIRECTORY_FILE_LE) { @@ -2608,7 +2693,7 @@ int smb2_open(struct ksmbd_work *work) daccess = smb_map_generic_desired_access(req->DesiredAccess); if (file_present && !(req->CreateOptions & FILE_DELETE_ON_CLOSE_LE)) { - rc = smb_check_perm_dacl(conn, path.dentry, &daccess, + rc = smb_check_perm_dacl(conn, &path, &daccess, sess->user->uid); if (rc) goto err_out; @@ -2618,7 +2703,8 @@ int smb2_open(struct ksmbd_work *work) if (!file_present) { daccess = cpu_to_le32(GENERIC_ALL_FLAGS); } else { - rc = ksmbd_vfs_query_maximal_access(path.dentry, + rc = ksmbd_vfs_query_maximal_access(mnt_user_ns(path.mnt), + path.dentry, &daccess); if (rc) goto err_out; @@ -2628,7 +2714,8 @@ int smb2_open(struct ksmbd_work *work) } open_flags = smb2_create_open_flags(file_present, daccess, - req->CreateDisposition); + req->CreateDisposition, + &may_flags); if (!test_tree_conn_flag(tcon, KSMBD_TREE_CONN_FLAG_WRITABLE)) { if (open_flags & O_CREAT) { @@ -2655,21 +2742,24 @@ int smb2_open(struct ksmbd_work *work) goto err_out; } } else if (!already_permitted) { - bool may_delete; - - may_delete = daccess & FILE_DELETE_LE || - req->CreateOptions & FILE_DELETE_ON_CLOSE_LE; - /* FILE_READ_ATTRIBUTE is allowed without inode_permission, * because execute(search) permission on a parent directory, * is already granted. */ if (daccess & ~(FILE_READ_ATTRIBUTES_LE | FILE_READ_CONTROL_LE)) { - rc = ksmbd_vfs_inode_permission(path.dentry, - open_flags & O_ACCMODE, - may_delete); + rc = inode_permission(mnt_user_ns(path.mnt), + d_inode(path.dentry), + may_flags); if (rc) goto err_out; + + if ((daccess & FILE_DELETE_LE) || + (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE)) { + rc = ksmbd_vfs_may_delete(mnt_user_ns(path.mnt), + path.dentry); + if (rc) + goto err_out; + } } } @@ -2683,7 +2773,7 @@ int smb2_open(struct ksmbd_work *work) filp = dentry_open(&path, open_flags, current_cred()); if (IS_ERR(filp)) { rc = PTR_ERR(filp); - ksmbd_err("dentry open for dir failed, rc %d\n", rc); + pr_err("dentry open for dir failed, rc %d\n", rc); goto err_out; } @@ -2729,21 +2819,24 @@ int smb2_open(struct ksmbd_work *work) int posix_acl_rc; struct inode *inode = d_inode(path.dentry); - posix_acl_rc = ksmbd_vfs_inherit_posix_acl(inode, d_inode(path.dentry->d_parent)); + posix_acl_rc = ksmbd_vfs_inherit_posix_acl(mnt_user_ns(path.mnt), + inode, + d_inode(path.dentry->d_parent)); if (posix_acl_rc) ksmbd_debug(SMB, "inherit posix acl failed : %d\n", posix_acl_rc); if (test_share_config_flag(work->tcon->share_conf, KSMBD_SHARE_FLAG_ACL_XATTR)) { - rc = smb_inherit_dacl(conn, path.dentry, sess->user->uid, + rc = smb_inherit_dacl(conn, &path, sess->user->uid, sess->user->gid); } if (rc) { - rc = smb2_create_sd_buffer(work, req, path.dentry); + rc = smb2_create_sd_buffer(work, req, &path); if (rc) { if (posix_acl_rc) - ksmbd_vfs_set_init_posix_acl(inode); + ksmbd_vfs_set_init_posix_acl(mnt_user_ns(path.mnt), + inode); if (test_share_config_flag(work->tcon->share_conf, KSMBD_SHARE_FLAG_ACL_XATTR)) { @@ -2765,22 +2858,24 @@ int smb2_open(struct ksmbd_work *work) if (!pntsd) goto err_out; - rc = build_sec_desc(pntsd, NULL, + rc = build_sec_desc(mnt_user_ns(path.mnt), + pntsd, NULL, OWNER_SECINFO | - GROUP_SECINFO | - DACL_SECINFO, + GROUP_SECINFO | + DACL_SECINFO, &pntsd_size, &fattr); posix_acl_release(fattr.cf_acls); posix_acl_release(fattr.cf_dacls); rc = ksmbd_vfs_set_sd_xattr(conn, + mnt_user_ns(path.mnt), path.dentry, pntsd, pntsd_size); kfree(pntsd); if (rc) - ksmbd_err("failed to store ntacl in xattr : %d\n", - rc); + pr_err("failed to store ntacl in xattr : %d\n", + rc); } } } @@ -2815,7 +2910,7 @@ int smb2_open(struct ksmbd_work *work) rc = ksmbd_vfs_getattr(&path, &stat); if (rc) { - generic_fillattr(&init_user_ns, d_inode(path.dentry), &stat); + generic_fillattr(mnt_user_ns(path.mnt), d_inode(path.dentry), &stat); rc = 0; } @@ -2829,7 +2924,7 @@ int smb2_open(struct ksmbd_work *work) if (!test_share_config_flag(work->tcon->share_conf, KSMBD_SHARE_FLAG_OPLOCKS) || (req_op_level == SMB2_OPLOCK_LEVEL_LEASE && !(conn->vals->capabilities & SMB2_GLOBAL_CAP_LEASING))) { - if (share_ret < 0 && !S_ISDIR(FP_INODE(fp)->i_mode)) { + if (share_ret < 0 && !S_ISDIR(file_inode(fp->filp)->i_mode)) { rc = share_ret; goto err_out; } @@ -2881,10 +2976,12 @@ int smb2_open(struct ksmbd_work *work) ksmbd_debug(SMB, "request smb2 create allocate size : %llu\n", alloc_size); - err = ksmbd_vfs_alloc_size(work, fp, alloc_size); + smb_break_all_levII_oplock(work, fp, 1); + err = vfs_fallocate(fp->filp, FALLOC_FL_KEEP_SIZE, 0, + alloc_size); if (err < 0) ksmbd_debug(SMB, - "ksmbd_vfs_alloc_size is failed : %d\n", + "vfs_fallocate is failed : %d\n", err); } @@ -2914,7 +3011,8 @@ int smb2_open(struct ksmbd_work *work) memcpy(fp->client_guid, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE); - generic_fillattr(&init_user_ns, FP_INODE(fp), &stat); + generic_fillattr(file_mnt_user_ns(fp->filp), file_inode(fp->filp), + &stat); rsp->StructureSize = cpu_to_le16(89); rcu_read_lock(); @@ -2966,7 +3064,8 @@ int smb2_open(struct ksmbd_work *work) struct create_context *mxac_ccontext; if (maximal_access == 0) - ksmbd_vfs_query_maximal_access(path.dentry, + ksmbd_vfs_query_maximal_access(mnt_user_ns(path.mnt), + path.dentry, &maximal_access); mxac_ccontext = (struct create_context *)(rsp->Buffer + le32_to_cpu(rsp->CreateContextsLength)); @@ -3169,6 +3268,7 @@ static int dentry_name(struct ksmbd_dir_info *d_info, int info_level) * @conn: connection instance * @info_level: smb information level * @d_info: structure included variables for query dir + * @user_ns: user namespace * @ksmbd_kstat: ksmbd wrapper of dirent stat information * * if directory has many entries, find first can't read it fully. @@ -3178,6 +3278,7 @@ static int dentry_name(struct ksmbd_dir_info *d_info, int info_level) */ static int smb2_populate_readdir_entry(struct ksmbd_conn *conn, int info_level, struct ksmbd_dir_info *d_info, + struct user_namespace *user_ns, struct ksmbd_kstat *ksmbd_kstat) { int next_entry_offset = 0; @@ -3330,9 +3431,9 @@ static int smb2_populate_readdir_entry(struct ksmbd_conn *conn, int info_level, S_ISDIR(ksmbd_kstat->kstat->mode) ? ATTR_DIRECTORY_LE : ATTR_ARCHIVE_LE; if (d_info->hide_dot_file && d_info->name[0] == '.') posix_info->DosAttributes |= ATTR_HIDDEN_LE; - id_to_sid(from_kuid(&init_user_ns, ksmbd_kstat->kstat->uid), + id_to_sid(from_kuid(user_ns, ksmbd_kstat->kstat->uid), SIDNFS_USER, (struct smb_sid *)&posix_info->SidBuffer[0]); - id_to_sid(from_kgid(&init_user_ns, ksmbd_kstat->kstat->gid), + id_to_sid(from_kgid(user_ns, ksmbd_kstat->kstat->gid), SIDNFS_GROUP, (struct smb_sid *)&posix_info->SidBuffer[20]); memcpy(posix_info->name, conv_name, conv_len); posix_info->name_len = cpu_to_le32(conv_len); @@ -3414,12 +3515,14 @@ static int process_query_dir_entries(struct smb2_query_dir_private *priv) ksmbd_kstat.kstat = &kstat; if (priv->info_level != FILE_NAMES_INFORMATION) ksmbd_vfs_fill_dentry_attrs(priv->work, + file_mnt_user_ns(priv->dir_fp->filp), dent, &ksmbd_kstat); rc = smb2_populate_readdir_entry(priv->work->conn, priv->info_level, priv->d_info, + file_mnt_user_ns(priv->dir_fp->filp), &ksmbd_kstat); dput(dent); if (rc) @@ -3628,16 +3731,17 @@ int smb2_query_dir(struct ksmbd_work *work) } if (!(dir_fp->daccess & FILE_LIST_DIRECTORY_LE) || - inode_permission(&init_user_ns, file_inode(dir_fp->filp), + inode_permission(file_mnt_user_ns(dir_fp->filp), + file_inode(dir_fp->filp), MAY_READ | MAY_EXEC)) { - ksmbd_err("no right to enumerate directory (%s)\n", - FP_FILENAME(dir_fp)); + pr_err("no right to enumerate directory (%pd)\n", + dir_fp->filp->f_path.dentry); rc = -EACCES; goto err_out2; } if (!S_ISDIR(file_inode(dir_fp->filp)->i_mode)) { - ksmbd_err("can't do query dir for a file\n"); + pr_err("can't do query dir for a file\n"); rc = -EINVAL; goto err_out2; } @@ -3695,7 +3799,7 @@ int smb2_query_dir(struct ksmbd_work *work) dir_fp->readdir_data.private = &query_dir_private; set_ctx_actor(&dir_fp->readdir_data.ctx, __query_dir); - rc = ksmbd_vfs_readdir(dir_fp->filp, &dir_fp->readdir_data); + rc = iterate_dir(dir_fp->filp, &dir_fp->readdir_data.ctx); if (rc == 0) restart_ctx(&dir_fp->readdir_data.ctx); if (rc == -ENOSPC) @@ -3738,7 +3842,7 @@ int smb2_query_dir(struct ksmbd_work *work) return 0; err_out: - ksmbd_err("error while processing smb2 query dir rc = %d\n", rc); + pr_err("error while processing smb2 query dir rc = %d\n", rc); kfree(srch_ptr); err_out2: @@ -3776,7 +3880,7 @@ static int buffer_check_err(int reqOutputBufferLength, { if (reqOutputBufferLength < le32_to_cpu(rsp->OutputBufferLength)) { if (reqOutputBufferLength < infoclass_size) { - ksmbd_err("Invalid Buffer Size Requested\n"); + pr_err("Invalid Buffer Size Requested\n"); rsp->hdr.Status = STATUS_INFO_LENGTH_MISMATCH; rsp->hdr.smb2_buf_length = cpu_to_be32(sizeof(struct smb2_hdr) - 4); return -EINVAL; @@ -3879,8 +3983,8 @@ static int smb2_get_ea(struct ksmbd_work *work, struct ksmbd_file *fp, struct path *path; if (!(fp->daccess & FILE_READ_EA_LE)) { - ksmbd_err("Not permitted to read ext attr : 0x%x\n", - fp->daccess); + pr_err("Not permitted to read ext attr : 0x%x\n", + fp->daccess); return -EACCES; } @@ -3953,7 +4057,8 @@ static int smb2_get_ea(struct ksmbd_work *work, struct ksmbd_file *fp, buf_free_len -= (offsetof(struct smb2_ea_info, name) + name_len + 1); /* bailout if xattr can't fit in buf_free_len */ - value_len = ksmbd_vfs_getxattr(path->dentry, name, &buf); + value_len = ksmbd_vfs_getxattr(mnt_user_ns(path->mnt), + path->dentry, name, &buf); if (value_len <= 0) { rc = -ENOENT; rsp->hdr.Status = STATUS_INVALID_HANDLE; @@ -4036,13 +4141,14 @@ static int get_file_basic_info(struct smb2_query_info_rsp *rsp, u64 time; if (!(fp->daccess & FILE_READ_ATTRIBUTES_LE)) { - ksmbd_err("no right to read the attributes : 0x%x\n", - fp->daccess); + pr_err("no right to read the attributes : 0x%x\n", + fp->daccess); return -EACCES; } basic_info = (struct smb2_file_all_info *)rsp->Buffer; - generic_fillattr(&init_user_ns, FP_INODE(fp), &stat); + generic_fillattr(file_mnt_user_ns(fp->filp), file_inode(fp->filp), + &stat); basic_info->CreationTime = cpu_to_le64(fp->create_time); time = ksmbd_UnixTimeToNT(stat.atime); basic_info->LastAccessTime = cpu_to_le64(time); @@ -4082,8 +4188,8 @@ static void get_file_standard_info(struct smb2_query_info_rsp *rsp, struct inode *inode; struct kstat stat; - inode = FP_INODE(fp); - generic_fillattr(&init_user_ns, inode, &stat); + inode = file_inode(fp->filp); + generic_fillattr(file_mnt_user_ns(fp->filp), inode, &stat); sinfo = (struct smb2_file_standard_info *)rsp->Buffer; delete_pending = ksmbd_inode_pending_delete(fp); @@ -4137,8 +4243,8 @@ static int get_file_all_info(struct ksmbd_work *work, if (!filename) return -ENOMEM; - inode = FP_INODE(fp); - generic_fillattr(&init_user_ns, inode, &stat); + inode = file_inode(fp->filp); + generic_fillattr(file_mnt_user_ns(fp->filp), inode, &stat); ksmbd_debug(SMB, "filename = %s\n", filename); delete_pending = ksmbd_inode_pending_delete(fp); @@ -4185,14 +4291,15 @@ static void get_file_alternate_info(struct ksmbd_work *work, { struct ksmbd_conn *conn = work->conn; struct smb2_file_alt_name_info *file_info; + struct dentry *dentry = fp->filp->f_path.dentry; int conv_len; - char *filename; - filename = (char *)FP_FILENAME(fp); + spin_lock(&dentry->d_lock); file_info = (struct smb2_file_alt_name_info *)rsp->Buffer; conv_len = ksmbd_extract_shortname(conn, - filename, + dentry->d_name.name, file_info->FileName); + spin_unlock(&dentry->d_lock); file_info->FileNameLength = cpu_to_le32(conv_len); rsp->OutputBufferLength = cpu_to_le32(sizeof(struct smb2_file_alt_name_info) + conv_len); @@ -4212,7 +4319,8 @@ static void get_file_stream_info(struct ksmbd_work *work, ssize_t xattr_list_len; int nbytes = 0, streamlen, stream_name_len, next, idx = 0; - generic_fillattr(&init_user_ns, FP_INODE(fp), &stat); + generic_fillattr(file_mnt_user_ns(fp->filp), file_inode(fp->filp), + &stat); file_info = (struct smb2_file_stream_info *)rsp->Buffer; xattr_list_len = ksmbd_vfs_listxattr(path->dentry, &xattr_list); @@ -4291,7 +4399,8 @@ static void get_file_internal_info(struct smb2_query_info_rsp *rsp, struct smb2_file_internal_info *file_info; struct kstat stat; - generic_fillattr(&init_user_ns, FP_INODE(fp), &stat); + generic_fillattr(file_mnt_user_ns(fp->filp), file_inode(fp->filp), + &stat); file_info = (struct smb2_file_internal_info *)rsp->Buffer; file_info->IndexNumber = cpu_to_le64(stat.ino); rsp->OutputBufferLength = @@ -4308,15 +4417,15 @@ static int get_file_network_open_info(struct smb2_query_info_rsp *rsp, u64 time; if (!(fp->daccess & FILE_READ_ATTRIBUTES_LE)) { - ksmbd_err("no right to read the attributes : 0x%x\n", - fp->daccess); + pr_err("no right to read the attributes : 0x%x\n", + fp->daccess); return -EACCES; } file_info = (struct smb2_file_ntwrk_info *)rsp->Buffer; - inode = FP_INODE(fp); - generic_fillattr(&init_user_ns, inode, &stat); + inode = file_inode(fp->filp); + generic_fillattr(file_mnt_user_ns(fp->filp), inode, &stat); file_info->CreationTime = cpu_to_le64(fp->create_time); time = ksmbd_UnixTimeToNT(stat.atime); @@ -4377,7 +4486,8 @@ static void get_file_compression_info(struct smb2_query_info_rsp *rsp, struct smb2_file_comp_info *file_info; struct kstat stat; - generic_fillattr(&init_user_ns, FP_INODE(fp), &stat); + generic_fillattr(file_mnt_user_ns(fp->filp), file_inode(fp->filp), + &stat); file_info = (struct smb2_file_comp_info *)rsp->Buffer; file_info->CompressedFileSize = cpu_to_le64(stat.blocks << 9); @@ -4398,8 +4508,8 @@ static int get_file_attribute_tag_info(struct smb2_query_info_rsp *rsp, struct smb2_file_attr_tag_info *file_info; if (!(fp->daccess & FILE_READ_ATTRIBUTES_LE)) { - ksmbd_err("no right to read the attributes : 0x%x\n", - fp->daccess); + pr_err("no right to read the attributes : 0x%x\n", + fp->daccess); return -EACCES; } @@ -4416,7 +4526,7 @@ static int find_file_posix_info(struct smb2_query_info_rsp *rsp, struct ksmbd_file *fp, void *rsp_org) { struct smb311_posix_qinfo *file_info; - struct inode *inode = FP_INODE(fp); + struct inode *inode = file_inode(fp->filp); u64 time; file_info = (struct smb311_posix_qinfo *)rsp->Buffer; @@ -4553,7 +4663,7 @@ static int smb2_get_info_file(struct ksmbd_work *work, break; case SMB_FIND_FILE_POSIX_INFO: if (!work->tcon->posix_extensions) { - ksmbd_err("client doesn't negotiate with SMB3.1.1 POSIX Extensions\n"); + pr_err("client doesn't negotiate with SMB3.1.1 POSIX Extensions\n"); rc = -EOPNOTSUPP; } else { rc = find_file_posix_info(rsp, fp, rsp_org); @@ -4592,13 +4702,13 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, rc = ksmbd_vfs_kern_path(share->path, lookup_flags, &path, 0); if (rc) { - ksmbd_err("cannot create vfs path\n"); + pr_err("cannot create vfs path\n"); return -EIO; } rc = vfs_statfs(&path, &stfs); if (rc) { - ksmbd_err("cannot do stat of path %s\n", share->path); + pr_err("cannot do stat of path %s\n", share->path); path_put(&path); return -EIO; } @@ -4669,16 +4779,12 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, case FS_SIZE_INFORMATION: { struct filesystem_info *info; - unsigned short logical_sector_size; info = (struct filesystem_info *)(rsp->Buffer); - logical_sector_size = - ksmbd_vfs_logical_sector_size(d_inode(path.dentry)); - info->TotalAllocationUnits = cpu_to_le64(stfs.f_blocks); info->FreeAllocationUnits = cpu_to_le64(stfs.f_bfree); - info->SectorsPerAllocationUnit = cpu_to_le32(stfs.f_bsize >> 9); - info->BytesPerSector = cpu_to_le32(logical_sector_size); + info->SectorsPerAllocationUnit = cpu_to_le32(1); + info->BytesPerSector = cpu_to_le32(stfs.f_bsize); rsp->OutputBufferLength = cpu_to_le32(24); inc_rfc1001_len(rsp_org, 24); fs_infoclass_size = FS_SIZE_INFORMATION_SIZE; @@ -4687,19 +4793,15 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, case FS_FULL_SIZE_INFORMATION: { struct smb2_fs_full_size_info *info; - unsigned short logical_sector_size; info = (struct smb2_fs_full_size_info *)(rsp->Buffer); - logical_sector_size = - ksmbd_vfs_logical_sector_size(d_inode(path.dentry)); - info->TotalAllocationUnits = cpu_to_le64(stfs.f_blocks); info->CallerAvailableAllocationUnits = cpu_to_le64(stfs.f_bavail); info->ActualAvailableAllocationUnits = cpu_to_le64(stfs.f_bfree); - info->SectorsPerAllocationUnit = cpu_to_le32(stfs.f_bsize >> 9); - info->BytesPerSector = cpu_to_le32(logical_sector_size); + info->SectorsPerAllocationUnit = cpu_to_le32(1); + info->BytesPerSector = cpu_to_le32(stfs.f_bsize); rsp->OutputBufferLength = cpu_to_le32(32); inc_rfc1001_len(rsp_org, 32); fs_infoclass_size = FS_FULL_SIZE_INFORMATION_SIZE; @@ -4729,19 +4831,15 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, case FS_SECTOR_SIZE_INFORMATION: { struct smb3_fs_ss_info *info; - struct ksmbd_fs_sector_size fs_ss; info = (struct smb3_fs_ss_info *)(rsp->Buffer); - ksmbd_vfs_smb2_sector_size(d_inode(path.dentry), &fs_ss); - info->LogicalBytesPerSector = - cpu_to_le32(fs_ss.logical_sector_size); + info->LogicalBytesPerSector = cpu_to_le32(stfs.f_bsize); info->PhysicalBytesPerSectorForAtomicity = - cpu_to_le32(fs_ss.physical_sector_size); - info->PhysicalBytesPerSectorForPerf = - cpu_to_le32(fs_ss.optimal_io_size); + cpu_to_le32(stfs.f_bsize); + info->PhysicalBytesPerSectorForPerf = cpu_to_le32(stfs.f_bsize); info->FSEffPhysicalBytesPerSectorForAtomicity = - cpu_to_le32(fs_ss.optimal_io_size); + cpu_to_le32(stfs.f_bsize); info->Flags = cpu_to_le32(SSINFO_FLAGS_ALIGNED_DEVICE | SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE); info->ByteOffsetForSectorAlignment = 0; @@ -4776,16 +4874,13 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, case FS_POSIX_INFORMATION: { struct filesystem_posix_info *info; - unsigned short logical_sector_size; if (!work->tcon->posix_extensions) { - ksmbd_err("client doesn't negotiate with SMB3.1.1 POSIX Extensions\n"); + pr_err("client doesn't negotiate with SMB3.1.1 POSIX Extensions\n"); rc = -EOPNOTSUPP; } else { info = (struct filesystem_posix_info *)(rsp->Buffer); - logical_sector_size = - ksmbd_vfs_logical_sector_size(d_inode(path.dentry)); - info->OptimalTransferSize = cpu_to_le32(logical_sector_size); + info->OptimalTransferSize = cpu_to_le32(stfs.f_bsize); info->BlockSize = cpu_to_le32(stfs.f_bsize); info->TotalBlocks = cpu_to_le64(stfs.f_blocks); info->BlocksAvail = cpu_to_le64(stfs.f_bfree); @@ -4822,9 +4917,11 @@ static int smb2_get_info_sec(struct ksmbd_work *work, int addition_info = le32_to_cpu(req->AdditionalInformation); int rc; - if (addition_info & ~(OWNER_SECINFO | GROUP_SECINFO | DACL_SECINFO)) { - ksmbd_debug(SMB, "Unsupported addition info: 0x%x)\n", - addition_info); + if (addition_info & ~(OWNER_SECINFO | GROUP_SECINFO | DACL_SECINFO | + PROTECTED_DACL_SECINFO | + UNPROTECTED_DACL_SECINFO)) { + pr_err("Unsupported addition info: 0x%x)\n", + addition_info); pntsd->revision = cpu_to_le16(1); pntsd->type = cpu_to_le16(SELF_RELATIVE | DACL_PROTECTED); @@ -4858,14 +4955,16 @@ static int smb2_get_info_sec(struct ksmbd_work *work, if (!fp) return -ENOENT; - inode = FP_INODE(fp); + inode = file_inode(fp->filp); ksmbd_acls_fattr(&fattr, inode); if (test_share_config_flag(work->tcon->share_conf, KSMBD_SHARE_FLAG_ACL_XATTR)) - ksmbd_vfs_get_sd_xattr(work->conn, fp->filp->f_path.dentry, &ppntsd); + ksmbd_vfs_get_sd_xattr(work->conn, file_mnt_user_ns(fp->filp), + fp->filp->f_path.dentry, &ppntsd); - rc = build_sec_desc(pntsd, ppntsd, addition_info, &secdesclen, &fattr); + rc = build_sec_desc(file_mnt_user_ns(fp->filp), + pntsd, ppntsd, addition_info, &secdesclen, &fattr); posix_acl_release(fattr.cf_acls); posix_acl_release(fattr.cf_dacls); kfree(ppntsd); @@ -5040,7 +5139,7 @@ int smb2_close(struct ksmbd_work *work) goto out; } - inode = FP_INODE(fp); + inode = file_inode(fp->filp); rsp->Flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB; rsp->AllocationSize = S_ISDIR(inode->i_mode) ? 0 : cpu_to_le64(inode->i_blocks << 9); @@ -5146,7 +5245,7 @@ static int smb2_rename(struct ksmbd_work *work, struct ksmbd_file *fp, len = strlen(new_name); if (new_name[len - 1] != '/') { - ksmbd_err("not allow base filename in rename\n"); + pr_err("not allow base filename in rename\n"); rc = -ESHARE; goto out; } @@ -5158,12 +5257,13 @@ static int smb2_rename(struct ksmbd_work *work, struct ksmbd_file *fp, if (rc) goto out; - rc = ksmbd_vfs_setxattr(fp->filp->f_path.dentry, + rc = ksmbd_vfs_setxattr(file_mnt_user_ns(fp->filp), + fp->filp->f_path.dentry, xattr_stream_name, NULL, 0, 0); if (rc < 0) { - ksmbd_err("failed to store stream name in xattr: %d\n", - rc); + pr_err("failed to store stream name in xattr: %d\n", + rc); rc = -EINVAL; goto out; } @@ -5322,7 +5422,7 @@ static int set_file_basic_info(struct ksmbd_file *fp, char *buf, if (file_info->Attributes) { if (!S_ISDIR(inode->i_mode) && file_info->Attributes & ATTR_DIRECTORY_LE) { - ksmbd_err("can't change a file to a directory\n"); + pr_err("can't change a file to a directory\n"); return -EINVAL; } @@ -5342,7 +5442,8 @@ static int set_file_basic_info(struct ksmbd_file *fp, char *buf, da.flags = XATTR_DOSINFO_ATTRIB | XATTR_DOSINFO_CREATE_TIME | XATTR_DOSINFO_ITIME; - rc = ksmbd_vfs_set_dos_attrib_xattr(filp->f_path.dentry, &da); + rc = ksmbd_vfs_set_dos_attrib_xattr(file_mnt_user_ns(filp), + filp->f_path.dentry, &da); if (rc) ksmbd_debug(SMB, "failed to restore file attribute in EA\n"); @@ -5363,14 +5464,14 @@ static int set_file_basic_info(struct ksmbd_file *fp, char *buf, if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) return -EACCES; - rc = setattr_prepare(&init_user_ns, dentry, &attrs); + rc = setattr_prepare(file_mnt_user_ns(filp), dentry, &attrs); if (rc) return -EINVAL; inode_lock(inode); - setattr_copy(&init_user_ns, inode, &attrs); + setattr_copy(file_mnt_user_ns(filp), inode, &attrs); attrs.ia_valid &= ~ATTR_CTIME; - rc = notify_change(&init_user_ns, dentry, &attrs, NULL); + rc = notify_change(file_mnt_user_ns(filp), dentry, &attrs, NULL); inode_unlock(inode); } return 0; @@ -5398,9 +5499,11 @@ static int set_file_allocation_info(struct ksmbd_work *work, inode = file_inode(fp->filp); if (alloc_blks > inode->i_blocks) { - rc = ksmbd_vfs_alloc_size(work, fp, alloc_blks * 512); + smb_break_all_levII_oplock(work, fp, 1); + rc = vfs_fallocate(fp->filp, FALLOC_FL_KEEP_SIZE, 0, + alloc_blks * 512); if (rc && rc != -EOPNOTSUPP) { - ksmbd_err("ksmbd_vfs_alloc_size is failed : %d\n", rc); + pr_err("vfs_fallocate is failed : %d\n", rc); return rc; } } else if (alloc_blks < inode->i_blocks) { @@ -5416,8 +5519,8 @@ static int set_file_allocation_info(struct ksmbd_work *work, size = i_size_read(inode); rc = ksmbd_vfs_truncate(work, NULL, fp, alloc_blks * 512); if (rc) { - ksmbd_err("truncate failed! filename : %s, err %d\n", - fp->filename, rc); + pr_err("truncate failed! filename : %s, err %d\n", + fp->filename, rc); return rc; } if (size < alloc_blks * 512) @@ -5467,19 +5570,32 @@ static int set_rename_info(struct ksmbd_work *work, struct ksmbd_file *fp, char *buf) { struct ksmbd_file *parent_fp; + struct dentry *parent; + struct dentry *dentry = fp->filp->f_path.dentry; + int ret; if (!(fp->daccess & FILE_DELETE_LE)) { - ksmbd_err("no right to delete : 0x%x\n", fp->daccess); + pr_err("no right to delete : 0x%x\n", fp->daccess); return -EACCES; } if (ksmbd_stream_fd(fp)) goto next; - parent_fp = ksmbd_lookup_fd_inode(PARENT_INODE(fp)); + parent = dget_parent(dentry); + ret = ksmbd_vfs_lock_parent(parent, dentry); + if (ret) { + dput(parent); + return ret; + } + + parent_fp = ksmbd_lookup_fd_inode(d_inode(parent)); + inode_unlock(d_inode(parent)); + dput(parent); + if (parent_fp) { if (parent_fp->daccess & FILE_DELETE_LE) { - ksmbd_err("parent dir is opened with delete access\n"); + pr_err("parent dir is opened with delete access\n"); return -ESHARE; } } @@ -5495,7 +5611,7 @@ static int set_file_disposition_info(struct ksmbd_file *fp, char *buf) struct inode *inode; if (!(fp->daccess & FILE_DELETE_LE)) { - ksmbd_err("no right to delete : 0x%x\n", fp->daccess); + pr_err("no right to delete : 0x%x\n", fp->daccess); return -EACCES; } @@ -5516,19 +5632,19 @@ static int set_file_position_info(struct ksmbd_file *fp, char *buf) { struct smb2_file_pos_info *file_info; loff_t current_byte_offset; - unsigned short sector_size; + unsigned long sector_size; struct inode *inode; inode = file_inode(fp->filp); file_info = (struct smb2_file_pos_info *)buf; current_byte_offset = le64_to_cpu(file_info->CurrentByteOffset); - sector_size = ksmbd_vfs_logical_sector_size(inode); + sector_size = inode->i_sb->s_blocksize; if (current_byte_offset < 0 || (fp->coption == FILE_NO_INTERMEDIATE_BUFFERING_LE && current_byte_offset & (sector_size - 1))) { - ksmbd_err("CurrentByteOffset is not valid : %llu\n", - current_byte_offset); + pr_err("CurrentByteOffset is not valid : %llu\n", + current_byte_offset); return -EINVAL; } @@ -5547,7 +5663,7 @@ static int set_file_mode_info(struct ksmbd_file *fp, char *buf) if ((mode & ~FILE_MODE_INFO_MASK) || (mode & FILE_SYNCHRONOUS_IO_ALERT_LE && mode & FILE_SYNCHRONOUS_IO_NONALERT_LE)) { - ksmbd_err("Mode is not valid : 0x%x\n", le32_to_cpu(mode)); + pr_err("Mode is not valid : 0x%x\n", le32_to_cpu(mode)); return -EINVAL; } @@ -5608,8 +5724,8 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp, case FILE_FULL_EA_INFORMATION: { if (!(fp->daccess & FILE_WRITE_EA_LE)) { - ksmbd_err("Not permitted to write ext attr: 0x%x\n", - fp->daccess); + pr_err("Not permitted to write ext attr: 0x%x\n", + fp->daccess); return -EACCES; } @@ -5624,7 +5740,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp, return set_file_mode_info(fp, buf); } - ksmbd_err("Unimplemented Fileinfoclass :%d\n", info_class); + pr_err("Unimplemented Fileinfoclass :%d\n", info_class); return -EOPNOTSUPP; } @@ -5635,7 +5751,7 @@ static int smb2_set_info_sec(struct ksmbd_file *fp, int addition_info, fp->saccess |= FILE_SHARE_DELETE_LE; - return set_info_sec(fp->conn, fp->tcon, fp->filp->f_path.dentry, pntsd, + return set_info_sec(fp->conn, fp->tcon, &fp->filp->f_path, pntsd, buf_len, false); } @@ -5657,8 +5773,8 @@ int smb2_set_info(struct ksmbd_work *work) rsp_org = work->response_buf; if (work->next_smb2_rcv_hdr_off) { - req = REQUEST_BUF_NEXT(work); - rsp = RESPONSE_BUF_NEXT(work); + req = ksmbd_req_buf_next(work); + rsp = ksmbd_resp_buf_next(work); if (!HAS_FILE_ID(le64_to_cpu(req->VolatileFileId))) { ksmbd_debug(SMB, "Compound request set FID = %u\n", work->compound_fid); @@ -5852,7 +5968,7 @@ int smb2_read(struct ksmbd_work *work) } if (!(fp->daccess & (FILE_READ_DATA_LE | FILE_READ_ATTRIBUTES_LE))) { - ksmbd_err("Not permitted to read : 0x%x\n", fp->daccess); + pr_err("Not permitted to read : 0x%x\n", fp->daccess); err = -EACCES; goto out; } @@ -5868,16 +5984,10 @@ int smb2_read(struct ksmbd_work *work) goto out; } - ksmbd_debug(SMB, "filename %s, offset %lld, len %zu\n", FP_FILENAME(fp), - offset, length); + ksmbd_debug(SMB, "filename %pd, offset %lld, len %zu\n", + fp->filp->f_path.dentry, offset, length); - if (server_conf.flags & KSMBD_GLOBAL_FLAG_CACHE_RBUF) { - work->aux_payload_buf = - ksmbd_find_buffer(conn->vals->max_read_size); - work->set_read_buf = true; - } else { - work->aux_payload_buf = kvmalloc(length, GFP_KERNEL | __GFP_ZERO); - } + work->aux_payload_buf = kvmalloc(length, GFP_KERNEL | __GFP_ZERO); if (!work->aux_payload_buf) { err = -ENOMEM; goto out; @@ -5890,10 +6000,7 @@ int smb2_read(struct ksmbd_work *work) } if ((nbytes == 0 && length != 0) || nbytes < mincount) { - if (server_conf.flags & KSMBD_GLOBAL_FLAG_CACHE_RBUF) - ksmbd_release_buffer(work->aux_payload_buf); - else - kvfree(work->aux_payload_buf); + kvfree(work->aux_payload_buf); work->aux_payload_buf = NULL; rsp->hdr.Status = STATUS_END_OF_FILE; smb2_set_err_rsp(work); @@ -5910,10 +6017,7 @@ int smb2_read(struct ksmbd_work *work) remain_bytes = smb2_read_rdma_channel(work, req, work->aux_payload_buf, nbytes); - if (server_conf.flags & KSMBD_GLOBAL_FLAG_CACHE_RBUF) - ksmbd_release_buffer(work->aux_payload_buf); - else - kvfree(work->aux_payload_buf); + kvfree(work->aux_payload_buf); work->aux_payload_buf = NULL; nbytes = 0; @@ -5984,9 +6088,9 @@ static noinline int smb2_write_pipe(struct ksmbd_work *work) } else { if ((le16_to_cpu(req->DataOffset) > get_rfc1002_len(req)) || (le16_to_cpu(req->DataOffset) + length > get_rfc1002_len(req))) { - ksmbd_err("invalid write data offset %u, smb_len %u\n", - le16_to_cpu(req->DataOffset), - get_rfc1002_len(req)); + pr_err("invalid write data offset %u, smb_len %u\n", + le16_to_cpu(req->DataOffset), + get_rfc1002_len(req)); err = -EINVAL; goto out; } @@ -6117,7 +6221,7 @@ int smb2_write(struct ksmbd_work *work) } if (!(fp->daccess & (FILE_WRITE_DATA_LE | FILE_READ_ATTRIBUTES_LE))) { - ksmbd_err("Not permitted to write : 0x%x\n", fp->daccess); + pr_err("Not permitted to write : 0x%x\n", fp->daccess); err = -EACCES; goto out; } @@ -6143,9 +6247,9 @@ int smb2_write(struct ksmbd_work *work) } else { if ((le16_to_cpu(req->DataOffset) > get_rfc1002_len(req)) || (le16_to_cpu(req->DataOffset) + length > get_rfc1002_len(req))) { - ksmbd_err("invalid write data offset %u, smb_len %u\n", - le16_to_cpu(req->DataOffset), - get_rfc1002_len(req)); + pr_err("invalid write data offset %u, smb_len %u\n", + le16_to_cpu(req->DataOffset), + get_rfc1002_len(req)); err = -EINVAL; goto out; } @@ -6158,8 +6262,8 @@ int smb2_write(struct ksmbd_work *work) if (le32_to_cpu(req->Flags) & SMB2_WRITEFLAG_WRITE_THROUGH) writethrough = true; - ksmbd_debug(SMB, "filename %s, offset %lld, len %zu\n", - FP_FILENAME(fp), offset, length); + ksmbd_debug(SMB, "filename %pd, offset %lld, len %zu\n", + fp->filp->f_path.dentry, offset, length); err = ksmbd_vfs_write(work, fp, data_buf, length, &offset, writethrough, &nbytes); if (err < 0) @@ -6258,7 +6362,6 @@ int smb2_cancel(struct ksmbd_work *work) struct smb2_hdr *hdr = work->request_buf; struct smb2_hdr *chdr; struct ksmbd_work *cancel_work = NULL; - struct list_head *tmp; int canceled = 0; struct list_head *command_list; @@ -6269,9 +6372,8 @@ int smb2_cancel(struct ksmbd_work *work) command_list = &conn->async_requests; spin_lock(&conn->request_lock); - list_for_each(tmp, command_list) { - cancel_work = list_entry(tmp, struct ksmbd_work, - async_request_entry); + list_for_each_entry(cancel_work, command_list, + async_request_entry) { chdr = cancel_work->request_buf; if (cancel_work->async_id != @@ -6290,9 +6392,7 @@ int smb2_cancel(struct ksmbd_work *work) command_list = &conn->requests; spin_lock(&conn->request_lock); - list_for_each(tmp, command_list) { - cancel_work = list_entry(tmp, struct ksmbd_work, - request_entry); + list_for_each_entry(cancel_work, command_list, request_entry) { chdr = cancel_work->request_buf; if (chdr->MessageId != hdr->MessageId || @@ -6479,7 +6579,7 @@ int smb2_lock(struct ksmbd_work *work) lock_start = le64_to_cpu(lock_ele[i].Offset); lock_length = le64_to_cpu(lock_ele[i].Length); if (lock_start > U64_MAX - lock_length) { - ksmbd_err("Invalid lock range requested\n"); + pr_err("Invalid lock range requested\n"); rsp->hdr.Status = STATUS_INVALID_LOCK_RANGE; goto out; } @@ -6509,7 +6609,7 @@ int smb2_lock(struct ksmbd_work *work) cmp_lock->fl->fl_end >= flock->fl_end) { if (cmp_lock->fl->fl_type != F_UNLCK && flock->fl_type != F_UNLCK) { - ksmbd_err("conflict two locks in one request\n"); + pr_err("conflict two locks in one request\n"); rsp->hdr.Status = STATUS_INVALID_PARAMETER; goto out; @@ -6582,7 +6682,7 @@ int smb2_lock(struct ksmbd_work *work) if (cmp_lock->zero_len && !smb_lock->zero_len && cmp_lock->start > smb_lock->start && cmp_lock->start < smb_lock->end) { - ksmbd_err("previous lock conflict with zero byte lock range\n"); + pr_err("previous lock conflict with zero byte lock range\n"); rsp->hdr.Status = STATUS_LOCK_NOT_GRANTED; goto out; } @@ -6590,7 +6690,7 @@ int smb2_lock(struct ksmbd_work *work) if (smb_lock->zero_len && !cmp_lock->zero_len && smb_lock->start > cmp_lock->start && smb_lock->start < cmp_lock->end) { - ksmbd_err("current lock conflict with zero byte lock range\n"); + pr_err("current lock conflict with zero byte lock range\n"); rsp->hdr.Status = STATUS_LOCK_NOT_GRANTED; goto out; } @@ -6599,7 +6699,7 @@ int smb2_lock(struct ksmbd_work *work) cmp_lock->end > smb_lock->start) || (cmp_lock->start < smb_lock->end && cmp_lock->end >= smb_lock->end)) && !cmp_lock->zero_len && !smb_lock->zero_len) { - ksmbd_err("Not allow lock operation on exclusive lock range\n"); + pr_err("Not allow lock operation on exclusive lock range\n"); rsp->hdr.Status = STATUS_LOCK_NOT_GRANTED; goto out; @@ -6607,7 +6707,7 @@ int smb2_lock(struct ksmbd_work *work) } if (smb_lock->fl->fl_type == F_UNLCK && nolock) { - ksmbd_err("Try to unlock nolocked range\n"); + pr_err("Try to unlock nolocked range\n"); rsp->hdr.Status = STATUS_RANGE_NOT_LOCKED; goto out; } @@ -6621,7 +6721,7 @@ no_check_gl: flock = smb_lock->fl; list_del(&smb_lock->llist); retry: - err = ksmbd_vfs_lock(filp, smb_lock->cmd, flock); + err = vfs_lock_file(filp, smb_lock->cmd, flock, NULL); skip: if (flags & SMB2_LOCKFLAG_UNLOCK) { if (!err) { @@ -6665,12 +6765,12 @@ skip: err = ksmbd_vfs_posix_lock_wait(flock); - if (!WORK_ACTIVE(work)) { + if (work->state != KSMBD_WORK_ACTIVE) { list_del(&smb_lock->llist); list_del(&smb_lock->glist); locks_free_lock(flock); - if (WORK_CANCELLED(work)) { + if (work->state == KSMBD_WORK_CANCELLED) { spin_lock(&fp->f_lock); list_del(&work->fp_entry); spin_unlock(&fp->f_lock); @@ -6734,9 +6834,9 @@ out: rlock->fl_start = smb_lock->start; rlock->fl_end = smb_lock->end; - err = ksmbd_vfs_lock(filp, 0, rlock); + err = vfs_lock_file(filp, 0, rlock, NULL); if (err) - ksmbd_err("rollback unlock fail : %d\n", err); + pr_err("rollback unlock fail : %d\n", err); list_del(&smb_lock->llist); list_del(&smb_lock->glist); locks_free_lock(smb_lock->fl); @@ -6923,8 +7023,8 @@ static int fsctl_query_iface_info_ioctl(struct ksmbd_conn *conn, netdev->ethtool_ops->get_link_ksettings(netdev, &cmd); speed = cmd.base.speed; } else { - ksmbd_err("%s %s\n", netdev->name, - "speed is unknown, defaulting to 1Gb/sec"); + pr_err("%s %s\n", netdev->name, + "speed is unknown, defaulting to 1Gb/sec"); speed = SPEED_1000; } @@ -7119,12 +7219,14 @@ static inline int fsctl_set_sparse(struct ksmbd_work *work, u64 id, KSMBD_SHARE_FLAG_STORE_DOS_ATTRS)) { struct xattr_dos_attrib da; - ret = ksmbd_vfs_get_dos_attrib_xattr(fp->filp->f_path.dentry, &da); + ret = ksmbd_vfs_get_dos_attrib_xattr(file_mnt_user_ns(fp->filp), + fp->filp->f_path.dentry, &da); if (ret <= 0) goto out; da.attr = le32_to_cpu(fp->f_ci->m_fattr); - ret = ksmbd_vfs_set_dos_attrib_xattr(fp->filp->f_path.dentry, &da); + ret = ksmbd_vfs_set_dos_attrib_xattr(file_mnt_user_ns(fp->filp), + fp->filp->f_path.dentry, &da); if (ret) fp->f_ci->m_fattr = old_fattr; } @@ -7172,8 +7274,8 @@ int smb2_ioctl(struct ksmbd_work *work) rsp_org = work->response_buf; if (work->next_smb2_rcv_hdr_off) { - req = REQUEST_BUF_NEXT(work); - rsp = RESPONSE_BUF_NEXT(work); + req = ksmbd_req_buf_next(work); + rsp = ksmbd_resp_buf_next(work); if (!HAS_FILE_ID(le64_to_cpu(req->VolatileFileId))) { ksmbd_debug(SMB, "Compound request set FID = %u\n", work->compound_fid); @@ -7336,13 +7438,13 @@ int smb2_ioctl(struct ksmbd_work *work) reparse_ptr = (struct reparse_data_buffer *)&rsp->Buffer[0]; fp = ksmbd_lookup_fd_fast(work, id); if (!fp) { - ksmbd_err("not found fp!!\n"); + pr_err("not found fp!!\n"); ret = -ENOENT; goto out; } reparse_ptr->ReparseTag = - smb2_get_reparse_tag_special_file(FP_INODE(fp)->i_mode); + smb2_get_reparse_tag_special_file(file_inode(fp->filp)->i_mode); reparse_ptr->ReparseDataLength = 0; ksmbd_fd_put(work, fp); nbytes = sizeof(struct reparse_data_buffer); @@ -7359,14 +7461,14 @@ int smb2_ioctl(struct ksmbd_work *work) fp_in = ksmbd_lookup_fd_slow(work, dup_ext->VolatileFileHandle, dup_ext->PersistentFileHandle); if (!fp_in) { - ksmbd_err("not found file handle in duplicate extent to file\n"); + pr_err("not found file handle in duplicate extent to file\n"); ret = -ENOENT; goto out; } fp_out = ksmbd_lookup_fd_fast(work, id); if (!fp_out) { - ksmbd_err("not found fp\n"); + pr_err("not found fp\n"); ret = -ENOENT; goto dup_ext_out; } @@ -7380,8 +7482,8 @@ int smb2_ioctl(struct ksmbd_work *work) ret = -EOPNOTSUPP; goto dup_ext_out; } else if (cloned != length) { - cloned = ksmbd_vfs_copy_file_range(fp_in->filp, src_off, - fp_out->filp, dst_off, length); + cloned = vfs_copy_file_range(fp_in->filp, src_off, + fp_out->filp, dst_off, length, 0); if (cloned != length) { if (cloned < 0) ret = cloned; @@ -7463,7 +7565,7 @@ static void smb20_oplock_break_ack(struct ksmbd_work *work) opinfo = opinfo_get(fp); if (!opinfo) { - ksmbd_err("unexpected null oplock_info\n"); + pr_err("unexpected null oplock_info\n"); rsp->hdr.Status = STATUS_INVALID_OPLOCK_PROTOCOL; smb2_set_err_rsp(work); ksmbd_fd_put(work, fp); @@ -7526,8 +7628,8 @@ static void smb20_oplock_break_ack(struct ksmbd_work *work) rsp_oplevel = SMB2_OPLOCK_LEVEL_NONE; break; default: - ksmbd_err("unknown oplock change 0x%x -> 0x%x\n", - opinfo->level, rsp_oplevel); + pr_err("unknown oplock change 0x%x -> 0x%x\n", + opinfo->level, rsp_oplevel); } if (ret < 0) { @@ -7603,8 +7705,8 @@ static void smb21_lease_break_ack(struct ksmbd_work *work) lease = opinfo->o_lease; if (opinfo->op_state == OPLOCK_STATE_NONE) { - ksmbd_err("unexpected lease break state 0x%x\n", - opinfo->op_state); + pr_err("unexpected lease break state 0x%x\n", + opinfo->op_state); rsp->hdr.Status = STATUS_UNSUCCESSFUL; goto err_out; } @@ -7796,7 +7898,7 @@ int smb2_check_sign_req(struct ksmbd_work *work) hdr_org = hdr = work->request_buf; if (work->next_smb2_rcv_hdr_off) - hdr = REQUEST_BUF_NEXT(work); + hdr = ksmbd_req_buf_next(work); if (!hdr->NextCommand && !work->next_smb2_rcv_hdr_off) len = be32_to_cpu(hdr_org->smb2_buf_length); @@ -7817,7 +7919,7 @@ int smb2_check_sign_req(struct ksmbd_work *work) return 0; if (memcmp(signature, signature_req, SMB2_SIGNATURE_SIZE)) { - ksmbd_err("bad smb2 signature\n"); + pr_err("bad smb2 signature\n"); return 0; } @@ -7840,9 +7942,9 @@ void smb2_set_sign_rsp(struct ksmbd_work *work) hdr_org = hdr = work->response_buf; if (work->next_smb2_rsp_hdr_off) - hdr = RESPONSE_BUF_NEXT(work); + hdr = ksmbd_resp_buf_next(work); - req_hdr = REQUEST_BUF_NEXT(work); + req_hdr = ksmbd_req_buf_next(work); if (!work->next_smb2_rsp_hdr_off) { len = get_rfc1002_len(hdr_org); @@ -7883,7 +7985,7 @@ void smb2_set_sign_rsp(struct ksmbd_work *work) */ int smb3_check_sign_req(struct ksmbd_work *work) { - struct ksmbd_conn *conn; + struct ksmbd_conn *conn = work->conn; char *signing_key; struct smb2_hdr *hdr, *hdr_org; struct channel *chann; @@ -7894,7 +7996,7 @@ int smb3_check_sign_req(struct ksmbd_work *work) hdr_org = hdr = work->request_buf; if (work->next_smb2_rcv_hdr_off) - hdr = REQUEST_BUF_NEXT(work); + hdr = ksmbd_req_buf_next(work); if (!hdr->NextCommand && !work->next_smb2_rcv_hdr_off) len = be32_to_cpu(hdr_org->smb2_buf_length); @@ -7906,17 +8008,15 @@ int smb3_check_sign_req(struct ksmbd_work *work) if (le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) { signing_key = work->sess->smb3signingkey; - conn = work->sess->conn; } else { - chann = lookup_chann_list(work->sess); + chann = lookup_chann_list(work->sess, conn); if (!chann) return 0; signing_key = chann->smb3signingkey; - conn = chann->conn; } if (!signing_key) { - ksmbd_err("SMB3 signing key is not generated\n"); + pr_err("SMB3 signing key is not generated\n"); return 0; } @@ -7929,7 +8029,7 @@ int smb3_check_sign_req(struct ksmbd_work *work) return 0; if (memcmp(signature, signature_req, SMB2_SIGNATURE_SIZE)) { - ksmbd_err("bad smb2 signature\n"); + pr_err("bad smb2 signature\n"); return 0; } @@ -7943,7 +8043,7 @@ int smb3_check_sign_req(struct ksmbd_work *work) */ void smb3_set_sign_rsp(struct ksmbd_work *work) { - struct ksmbd_conn *conn; + struct ksmbd_conn *conn = work->conn; struct smb2_hdr *req_hdr; struct smb2_hdr *hdr, *hdr_org; struct channel *chann; @@ -7955,9 +8055,9 @@ void smb3_set_sign_rsp(struct ksmbd_work *work) hdr_org = hdr = work->response_buf; if (work->next_smb2_rsp_hdr_off) - hdr = RESPONSE_BUF_NEXT(work); + hdr = ksmbd_resp_buf_next(work); - req_hdr = REQUEST_BUF_NEXT(work); + req_hdr = ksmbd_req_buf_next(work); if (!work->next_smb2_rsp_hdr_off) { len = get_rfc1002_len(hdr_org); @@ -7970,13 +8070,11 @@ void smb3_set_sign_rsp(struct ksmbd_work *work) if (le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) { signing_key = work->sess->smb3signingkey; - conn = work->sess->conn; } else { - chann = lookup_chann_list(work->sess); + chann = lookup_chann_list(work->sess, work->conn); if (!chann) return; signing_key = chann->smb3signingkey; - conn = chann->conn; } if (!signing_key) @@ -8020,11 +8118,21 @@ void smb3_preauth_hash_rsp(struct ksmbd_work *work) ksmbd_gen_preauth_integrity_hash(conn, (char *)rsp, conn->preauth_info->Preauth_HashValue); - if (le16_to_cpu(rsp->Command) == SMB2_SESSION_SETUP_HE && - sess && sess->state == SMB2_SESSION_IN_PROGRESS) { + if (le16_to_cpu(rsp->Command) == SMB2_SESSION_SETUP_HE && sess) { __u8 *hash_value; - hash_value = sess->Preauth_HashValue; + if (conn->binding) { + struct preauth_session *preauth_sess; + + preauth_sess = ksmbd_preauth_session_lookup(conn, sess->id); + if (!preauth_sess) + return; + hash_value = preauth_sess->Preauth_HashValue; + } else { + hash_value = sess->Preauth_HashValue; + if (!hash_value) + return; + } ksmbd_gen_preauth_integrity_hash(conn, (char *)rsp, hash_value); } @@ -8116,22 +8224,22 @@ int smb3_decrypt_req(struct ksmbd_work *work) unsigned int orig_len = le32_to_cpu(tr_hdr->OriginalMessageSize); int rc = 0; - sess = ksmbd_session_lookup(conn, le64_to_cpu(tr_hdr->SessionId)); + sess = ksmbd_session_lookup_all(conn, le64_to_cpu(tr_hdr->SessionId)); if (!sess) { - ksmbd_err("invalid session id(%llx) in transform header\n", - le64_to_cpu(tr_hdr->SessionId)); + pr_err("invalid session id(%llx) in transform header\n", + le64_to_cpu(tr_hdr->SessionId)); return -ECONNABORTED; } if (pdu_length + 4 < sizeof(struct smb2_transform_hdr) + sizeof(struct smb2_hdr)) { - ksmbd_err("Transform message is too small (%u)\n", - pdu_length); + pr_err("Transform message is too small (%u)\n", + pdu_length); return -ECONNABORTED; } if (pdu_length + 4 < orig_len + sizeof(struct smb2_transform_hdr)) { - ksmbd_err("Transform message is broken\n"); + pr_err("Transform message is broken\n"); return -ECONNABORTED; } @@ -8159,7 +8267,7 @@ bool smb3_11_final_sess_setup_resp(struct ksmbd_work *work) return false; if (work->next_smb2_rcv_hdr_off) - rsp = RESPONSE_BUF_NEXT(work); + rsp = ksmbd_resp_buf_next(work); if (le16_to_cpu(rsp->Command) == SMB2_SESSION_SETUP_HE && rsp->Status == STATUS_SUCCESS) diff --git a/fs/cifsd/smb2pdu.h b/fs/ksmbd/smb2pdu.h index 0d5349e75dd9..0eac40e1ba65 100644 --- a/fs/cifsd/smb2pdu.h +++ b/fs/ksmbd/smb2pdu.h @@ -1647,7 +1647,8 @@ struct file_lock *smb_flock_init(struct file *f); int setup_async_work(struct ksmbd_work *work, void (*fn)(void **), void **arg); void smb2_send_interim_resp(struct ksmbd_work *work, __le32 status); -struct channel *lookup_chann_list(struct ksmbd_session *sess); +struct channel *lookup_chann_list(struct ksmbd_session *sess, + struct ksmbd_conn *conn); void smb3_preauth_hash_rsp(struct ksmbd_work *work); int smb3_is_transform_hdr(void *buf); int smb3_decrypt_req(struct ksmbd_work *work); diff --git a/fs/cifsd/smb_common.c b/fs/ksmbd/smb_common.c index 039030968b50..f770f3ffb840 100644 --- a/fs/cifsd/smb_common.c +++ b/fs/ksmbd/smb_common.c @@ -274,6 +274,7 @@ int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work, int info_level, char *search_pattern, int (*fn)(struct ksmbd_conn *, int, struct ksmbd_dir_info *, + struct user_namespace *, struct ksmbd_kstat *)) { int i, rc = 0; @@ -300,9 +301,11 @@ int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work, int info_level, ksmbd_kstat.kstat = &kstat; ksmbd_vfs_fill_dentry_attrs(work, + file_mnt_user_ns(dir->filp), dir->filp->f_path.dentry->d_parent, &ksmbd_kstat); - rc = fn(conn, info_level, d_info, &ksmbd_kstat); + rc = fn(conn, info_level, d_info, + file_mnt_user_ns(dir->filp), &ksmbd_kstat); if (rc) break; if (d_info->out_buf_len <= 0) @@ -447,7 +450,7 @@ int ksmbd_smb_negotiate_common(struct ksmbd_work *work, unsigned int command) return smb_handle_negotiate(work); } - ksmbd_err("Unknown SMB negotiation command: %u\n", command); + pr_err("Unknown SMB negotiation command: %u\n", command); return -EINVAL; } @@ -481,16 +484,14 @@ int ksmbd_smb_check_shared_mode(struct file *filp, struct ksmbd_file *curr_fp) { int rc = 0; struct ksmbd_file *prev_fp; - struct list_head *cur; /* * Lookup fp in master fp list, and check desired access and * shared mode between previous open and current open. */ read_lock(&curr_fp->f_ci->m_lock); - list_for_each(cur, &curr_fp->f_ci->m_fp_list) { - prev_fp = list_entry(cur, struct ksmbd_file, node); - if (file_inode(filp) != FP_INODE(prev_fp)) + list_for_each_entry(prev_fp, &curr_fp->f_ci->m_fp_list, node) { + if (file_inode(filp) != file_inode(prev_fp->filp)) continue; if (filp == prev_fp->filp) diff --git a/fs/cifsd/smb_common.h b/fs/ksmbd/smb_common.h index 6e7404b8db96..6ab28aa33024 100644 --- a/fs/cifsd/smb_common.h +++ b/fs/ksmbd/smb_common.h @@ -50,12 +50,6 @@ extern struct list_head global_lock_list; -#define IS_SMB2(x) ((x)->vals->protocol_id != SMB10_PROT_ID) - -#define HEADER_SIZE(conn) ((conn)->vals->header_size) -#define HEADER_SIZE_NO_BUF_LEN(conn) ((conn)->vals->header_size - 4) -#define MAX_HEADER_SIZE(conn) ((conn)->vals->max_header_size) - /* RFC 1002 session packet types */ #define RFC1002_SESSION_MESSAGE 0x00 #define RFC1002_SESSION_REQUEST 0x81 @@ -479,7 +473,7 @@ struct smb_version_ops { bool (*is_sign_req)(struct ksmbd_work *work, unsigned int command); int (*check_sign_req)(struct ksmbd_work *work); void (*set_sign_rsp)(struct ksmbd_work *work); - int (*generate_signingkey)(struct ksmbd_session *sess); + int (*generate_signingkey)(struct ksmbd_session *sess, struct ksmbd_conn *conn); int (*generate_encryptionkey)(struct ksmbd_session *sess); int (*is_transform_hdr)(void *buf); int (*decrypt_req)(struct ksmbd_work *work); @@ -490,6 +484,12 @@ struct smb_version_cmds { int (*proc)(struct ksmbd_work *swork); }; +static inline size_t +smb2_hdr_size_no_buflen(struct smb_version_values *vals) +{ + return vals->header_size - 4; +} + int ksmbd_min_protocol(void); int ksmbd_max_protocol(void); @@ -514,6 +514,7 @@ int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work, int (*fn)(struct ksmbd_conn *, int, struct ksmbd_dir_info *, + struct user_namespace *, struct ksmbd_kstat *)); int ksmbd_extract_shortname(struct ksmbd_conn *conn, diff --git a/fs/cifsd/smbacl.c b/fs/ksmbd/smbacl.c index 63db8c015f9d..4ee714b9b351 100644 --- a/fs/cifsd/smbacl.c +++ b/fs/ksmbd/smbacl.c @@ -14,7 +14,6 @@ #include "smb_common.h" #include "server.h" #include "misc.h" -#include "ksmbd_server.h" #include "mgmt/share_config.h" static const struct smb_sid domain = {1, 4, {0, 0, 0, 0, 0, 5}, @@ -254,7 +253,8 @@ void id_to_sid(unsigned int cid, uint sidtype, struct smb_sid *ssid) ssid->num_subauth++; } -static int sid_to_id(struct smb_sid *psid, uint sidtype, +static int sid_to_id(struct user_namespace *user_ns, + struct smb_sid *psid, uint sidtype, struct smb_fattr *fattr) { int rc = -EINVAL; @@ -264,8 +264,8 @@ static int sid_to_id(struct smb_sid *psid, uint sidtype, * Just return an error. */ if (unlikely(psid->num_subauth > SID_MAX_SUB_AUTHORITIES)) { - ksmbd_err("%s: %u subauthorities is too many!\n", - __func__, psid->num_subauth); + pr_err("%s: %u subauthorities is too many!\n", + __func__, psid->num_subauth); return -EIO; } @@ -275,8 +275,8 @@ static int sid_to_id(struct smb_sid *psid, uint sidtype, id = le32_to_cpu(psid->sub_auth[psid->num_subauth - 1]); if (id > 0) { - uid = make_kuid(&init_user_ns, id); - if (uid_valid(uid) && kuid_has_mapping(&init_user_ns, uid)) { + uid = make_kuid(user_ns, id); + if (uid_valid(uid) && kuid_has_mapping(user_ns, uid)) { fattr->cf_uid = uid; rc = 0; } @@ -287,8 +287,8 @@ static int sid_to_id(struct smb_sid *psid, uint sidtype, id = le32_to_cpu(psid->sub_auth[psid->num_subauth - 1]); if (id > 0) { - gid = make_kgid(&init_user_ns, id); - if (gid_valid(gid) && kgid_has_mapping(&init_user_ns, gid)) { + gid = make_kgid(user_ns, id); + if (gid_valid(gid) && kgid_has_mapping(user_ns, gid)) { fattr->cf_gid = gid; rc = 0; } @@ -363,7 +363,8 @@ void free_acl_state(struct posix_acl_state *state) kfree(state->groups); } -static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl, +static void parse_dacl(struct user_namespace *user_ns, + struct smb_acl *pdacl, char *end_of_acl, struct smb_sid *pownersid, struct smb_sid *pgrpsid, struct smb_fattr *fattr) { @@ -383,7 +384,7 @@ static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl, /* validate that we do not go past end of acl */ if (end_of_acl <= (char *)pdacl || end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) { - ksmbd_err("ACL too small to parse DACL\n"); + pr_err("ACL too small to parse DACL\n"); return; } @@ -475,10 +476,10 @@ static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl, acl_mode = access_flags_to_mode(fattr, ppace[i]->access_req, ppace[i]->type); temp_fattr.cf_uid = INVALID_UID; - ret = sid_to_id(&ppace[i]->sid, SIDOWNER, &temp_fattr); + ret = sid_to_id(user_ns, &ppace[i]->sid, SIDOWNER, &temp_fattr); if (ret || uid_eq(temp_fattr.cf_uid, INVALID_UID)) { - ksmbd_err("%s: Error %d mapping Owner SID to uid\n", - __func__, ret); + pr_err("%s: Error %d mapping Owner SID to uid\n", + __func__, ret); continue; } @@ -532,7 +533,7 @@ static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl, if (acl_state.users->n || acl_state.groups->n) { acl_state.mask.allow = 0x07; - fattr->cf_acls = ksmbd_vfs_posix_acl_alloc(acl_state.users->n + + fattr->cf_acls = posix_acl_alloc(acl_state.users->n + acl_state.groups->n + 4, GFP_KERNEL); if (fattr->cf_acls) { cf_pace = fattr->cf_acls->a_entries; @@ -543,7 +544,7 @@ static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl, if (default_acl_state.users->n || default_acl_state.groups->n) { default_acl_state.mask.allow = 0x07; fattr->cf_dacls = - ksmbd_vfs_posix_acl_alloc(default_acl_state.users->n + + posix_acl_alloc(default_acl_state.users->n + default_acl_state.groups->n + 4, GFP_KERNEL); if (fattr->cf_dacls) { cf_pdace = fattr->cf_dacls->a_entries; @@ -554,7 +555,8 @@ static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl, free_acl_state(&default_acl_state); } -static void set_posix_acl_entries_dacl(struct smb_ace *pndace, +static void set_posix_acl_entries_dacl(struct user_namespace *user_ns, + struct smb_ace *pndace, struct smb_fattr *fattr, u32 *num_aces, u16 *size, u32 nt_aces_num) { @@ -578,14 +580,14 @@ static void set_posix_acl_entries_dacl(struct smb_ace *pndace, uid_t uid; unsigned int sid_type = SIDOWNER; - uid = from_kuid(&init_user_ns, pace->e_uid); + uid = from_kuid(user_ns, pace->e_uid); if (!uid) sid_type = SIDUNIX_USER; id_to_sid(uid, sid_type, sid); } else if (pace->e_tag == ACL_GROUP) { gid_t gid; - gid = from_kgid(&init_user_ns, pace->e_gid); + gid = from_kgid(user_ns, pace->e_gid); id_to_sid(gid, SIDUNIX_GROUP, sid); } else if (pace->e_tag == ACL_OTHER && !nt_aces_num) { smb_copy_sid(sid, &sid_everyone); @@ -644,12 +646,12 @@ posix_default_acl: if (pace->e_tag == ACL_USER) { uid_t uid; - uid = from_kuid(&init_user_ns, pace->e_uid); + uid = from_kuid(user_ns, pace->e_uid); id_to_sid(uid, SIDCREATOR_OWNER, sid); } else if (pace->e_tag == ACL_GROUP) { gid_t gid; - gid = from_kgid(&init_user_ns, pace->e_gid); + gid = from_kgid(user_ns, pace->e_gid); id_to_sid(gid, SIDCREATOR_GROUP, sid); } else { kfree(sid); @@ -667,7 +669,9 @@ posix_default_acl: } } -static void set_ntacl_dacl(struct smb_acl *pndacl, struct smb_acl *nt_dacl, +static void set_ntacl_dacl(struct user_namespace *user_ns, + struct smb_acl *pndacl, + struct smb_acl *nt_dacl, const struct smb_sid *pownersid, const struct smb_sid *pgrpsid, struct smb_fattr *fattr) @@ -688,12 +692,14 @@ static void set_ntacl_dacl(struct smb_acl *pndacl, struct smb_acl *nt_dacl, } } - set_posix_acl_entries_dacl(pndace, fattr, &num_aces, &size, nt_num_aces); + set_posix_acl_entries_dacl(user_ns, pndace, fattr, + &num_aces, &size, nt_num_aces); pndacl->num_aces = cpu_to_le32(num_aces); pndacl->size = cpu_to_le16(le16_to_cpu(pndacl->size) + size); } -static void set_mode_dacl(struct smb_acl *pndacl, struct smb_fattr *fattr) +static void set_mode_dacl(struct user_namespace *user_ns, + struct smb_acl *pndacl, struct smb_fattr *fattr) { struct smb_ace *pace, *pndace; u32 num_aces = 0; @@ -704,12 +710,13 @@ static void set_mode_dacl(struct smb_acl *pndacl, struct smb_fattr *fattr) pace = pndace = (struct smb_ace *)((char *)pndacl + sizeof(struct smb_acl)); if (fattr->cf_acls) { - set_posix_acl_entries_dacl(pndace, fattr, &num_aces, &size, num_aces); + set_posix_acl_entries_dacl(user_ns, pndace, fattr, + &num_aces, &size, num_aces); goto out; } /* owner RID */ - uid = from_kuid(&init_user_ns, fattr->cf_uid); + uid = from_kuid(user_ns, fattr->cf_uid); if (uid) sid = &server_conf.domain_sid; else @@ -726,7 +733,7 @@ static void set_mode_dacl(struct smb_acl *pndacl, struct smb_fattr *fattr) ace_size = fill_ace_for_sid(pace, &sid_unix_groups, ACCESS_ALLOWED, 0, fattr->cf_mode, 0070); pace->sid.sub_auth[pace->sid.num_subauth++] = - cpu_to_le32(from_kgid(&init_user_ns, fattr->cf_gid)); + cpu_to_le32(from_kgid(user_ns, fattr->cf_gid)); pace->size = cpu_to_le16(ace_size + 4); size += le16_to_cpu(pace->size); pace = (struct smb_ace *)((char *)pndace + size); @@ -764,7 +771,7 @@ static int parse_sid(struct smb_sid *psid, char *end_of_acl) * bytes long (assuming no sub-auths - e.g. the null SID */ if (end_of_acl < (char *)psid + 8) { - ksmbd_err("ACL too small to parse SID %p\n", psid); + pr_err("ACL too small to parse SID %p\n", psid); return -EINVAL; } @@ -772,8 +779,8 @@ static int parse_sid(struct smb_sid *psid, char *end_of_acl) } /* Convert CIFS ACL to POSIX form */ -int parse_sec_desc(struct smb_ntsd *pntsd, int acl_len, - struct smb_fattr *fattr) +int parse_sec_desc(struct user_namespace *user_ns, struct smb_ntsd *pntsd, + int acl_len, struct smb_fattr *fattr) { int rc = 0; struct smb_sid *owner_sid_ptr, *group_sid_ptr; @@ -808,14 +815,14 @@ int parse_sec_desc(struct smb_ntsd *pntsd, int acl_len, if (pntsd->osidoffset) { rc = parse_sid(owner_sid_ptr, end_of_acl); if (rc) { - ksmbd_err("%s: Error %d parsing Owner SID\n", __func__, rc); + pr_err("%s: Error %d parsing Owner SID\n", __func__, rc); return rc; } - rc = sid_to_id(owner_sid_ptr, SIDOWNER, fattr); + rc = sid_to_id(user_ns, owner_sid_ptr, SIDOWNER, fattr); if (rc) { - ksmbd_err("%s: Error %d mapping Owner SID to uid\n", - __func__, rc); + pr_err("%s: Error %d mapping Owner SID to uid\n", + __func__, rc); owner_sid_ptr = NULL; } } @@ -823,14 +830,14 @@ int parse_sec_desc(struct smb_ntsd *pntsd, int acl_len, if (pntsd->gsidoffset) { rc = parse_sid(group_sid_ptr, end_of_acl); if (rc) { - ksmbd_err("%s: Error %d mapping Owner SID to gid\n", - __func__, rc); + pr_err("%s: Error %d mapping Owner SID to gid\n", + __func__, rc); return rc; } - rc = sid_to_id(group_sid_ptr, SIDUNIX_GROUP, fattr); + rc = sid_to_id(user_ns, group_sid_ptr, SIDUNIX_GROUP, fattr); if (rc) { - ksmbd_err("%s: Error %d mapping Group SID to gid\n", - __func__, rc); + pr_err("%s: Error %d mapping Group SID to gid\n", + __func__, rc); group_sid_ptr = NULL; } } @@ -842,15 +849,16 @@ int parse_sec_desc(struct smb_ntsd *pntsd, int acl_len, pntsd->type |= cpu_to_le16(DACL_PROTECTED); if (dacloffset) { - parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr, group_sid_ptr, - fattr); + parse_dacl(user_ns, dacl_ptr, end_of_acl, + owner_sid_ptr, group_sid_ptr, fattr); } return 0; } /* Convert permission bits from mode to equivalent CIFS ACL */ -int build_sec_desc(struct smb_ntsd *pntsd, struct smb_ntsd *ppntsd, +int build_sec_desc(struct user_namespace *user_ns, + struct smb_ntsd *pntsd, struct smb_ntsd *ppntsd, int addition_info, __u32 *secdesclen, struct smb_fattr *fattr) { @@ -867,7 +875,7 @@ int build_sec_desc(struct smb_ntsd *pntsd, struct smb_ntsd *ppntsd, if (!nowner_sid_ptr) return -ENOMEM; - uid = from_kuid(&init_user_ns, fattr->cf_uid); + uid = from_kuid(user_ns, fattr->cf_uid); if (!uid) sid_type = SIDUNIX_USER; id_to_sid(uid, sid_type, nowner_sid_ptr); @@ -878,7 +886,7 @@ int build_sec_desc(struct smb_ntsd *pntsd, struct smb_ntsd *ppntsd, return -ENOMEM; } - gid = from_kgid(&init_user_ns, fattr->cf_gid); + gid = from_kgid(user_ns, fattr->cf_gid); id_to_sid(gid, SIDUNIX_GROUP, ngroup_sid_ptr); offset = sizeof(struct smb_ntsd); @@ -910,7 +918,7 @@ int build_sec_desc(struct smb_ntsd *pntsd, struct smb_ntsd *ppntsd, dacl_ptr->num_aces = 0; if (!ppntsd) { - set_mode_dacl(dacl_ptr, fattr); + set_mode_dacl(user_ns, dacl_ptr, fattr); } else if (!ppntsd->dacloffset) { goto out; } else { @@ -918,8 +926,8 @@ int build_sec_desc(struct smb_ntsd *pntsd, struct smb_ntsd *ppntsd, ppdacl_ptr = (struct smb_acl *)((char *)ppntsd + le32_to_cpu(ppntsd->dacloffset)); - set_ntacl_dacl(dacl_ptr, ppdacl_ptr, nowner_sid_ptr, - ngroup_sid_ptr, fattr); + set_ntacl_dacl(user_ns, dacl_ptr, ppdacl_ptr, + nowner_sid_ptr, ngroup_sid_ptr, fattr); } pntsd->dacloffset = cpu_to_le32(offset); offset += le16_to_cpu(dacl_ptr->size); @@ -942,7 +950,8 @@ static void smb_set_ace(struct smb_ace *ace, const struct smb_sid *sid, u8 type, ace->size = cpu_to_le16(1 + 1 + 2 + 4 + 1 + 1 + 6 + (sid->num_subauth * 4)); } -int smb_inherit_dacl(struct ksmbd_conn *conn, struct dentry *dentry, +int smb_inherit_dacl(struct ksmbd_conn *conn, + struct path *path, unsigned int uid, unsigned int gid) { const struct smb_sid *psid, *creator = NULL; @@ -950,13 +959,14 @@ int smb_inherit_dacl(struct ksmbd_conn *conn, struct dentry *dentry, struct smb_acl *parent_pdacl; struct smb_ntsd *parent_pntsd = NULL; struct smb_sid owner_sid, group_sid; - struct dentry *parent = dentry->d_parent; + struct dentry *parent = path->dentry->d_parent; int inherited_flags = 0, flags = 0, i, ace_cnt = 0, nt_size = 0; int rc = -ENOENT, num_aces, dacloffset, pntsd_type, acl_len; char *aces_base; - bool is_dir = S_ISDIR(d_inode(dentry)->i_mode); + bool is_dir = S_ISDIR(d_inode(path->dentry)->i_mode); - acl_len = ksmbd_vfs_get_sd_xattr(conn, parent, &parent_pntsd); + acl_len = ksmbd_vfs_get_sd_xattr(conn, mnt_user_ns(path->mnt), + parent, &parent_pntsd); if (acl_len <= 0) return rc; dacloffset = le32_to_cpu(parent_pntsd->dacloffset); @@ -1087,7 +1097,8 @@ pass: pntsd_size += sizeof(struct smb_acl) + nt_size; } - ksmbd_vfs_set_sd_xattr(conn, dentry, pntsd, pntsd_size); + ksmbd_vfs_set_sd_xattr(conn, mnt_user_ns(path->mnt), + path->dentry, pntsd, pntsd_size); kfree(pntsd); rc = 0; } @@ -1110,7 +1121,7 @@ bool smb_inherit_flags(int flags, bool is_dir) return false; } -int smb_check_perm_dacl(struct ksmbd_conn *conn, struct dentry *dentry, +int smb_check_perm_dacl(struct ksmbd_conn *conn, struct path *path, __le32 *pdaccess, int uid) { struct smb_ntsd *pntsd = NULL; @@ -1128,7 +1139,8 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, struct dentry *dentry, char *end_of_acl; ksmbd_debug(SMB, "check permission using windows acl\n"); - acl_size = ksmbd_vfs_get_sd_xattr(conn, dentry, &pntsd); + acl_size = ksmbd_vfs_get_sd_xattr(conn, mnt_user_ns(path->mnt), + path->dentry, &pntsd); if (acl_size <= 0 || !pntsd || !pntsd->dacloffset) { kfree(pntsd); return 0; @@ -1202,16 +1214,18 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, struct dentry *dentry, granted = GENERIC_ALL_FLAGS; } - posix_acls = ksmbd_vfs_get_acl(d_inode(dentry), ACL_TYPE_ACCESS); + posix_acls = get_acl(d_inode(path->dentry), ACL_TYPE_ACCESS); if (posix_acls && !found) { unsigned int id = -1; pa_entry = posix_acls->a_entries; for (i = 0; i < posix_acls->a_count; i++, pa_entry++) { if (pa_entry->e_tag == ACL_USER) - id = from_kuid(&init_user_ns, pa_entry->e_uid); + id = from_kuid(mnt_user_ns(path->mnt), + pa_entry->e_uid); else if (pa_entry->e_tag == ACL_GROUP) - id = from_kgid(&init_user_ns, pa_entry->e_gid); + id = from_kgid(mnt_user_ns(path->mnt), + pa_entry->e_gid); else continue; @@ -1262,18 +1276,18 @@ err_out: } int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon, - struct dentry *dentry, struct smb_ntsd *pntsd, int ntsd_len, + struct path *path, struct smb_ntsd *pntsd, int ntsd_len, bool type_check) { int rc; struct smb_fattr fattr = {{0}}; - struct inode *inode = d_inode(dentry); + struct inode *inode = d_inode(path->dentry); fattr.cf_uid = INVALID_UID; fattr.cf_gid = INVALID_GID; fattr.cf_mode = inode->i_mode; - rc = parse_sec_desc(pntsd, ntsd_len, &fattr); + rc = parse_sec_desc(mnt_user_ns(path->mnt), pntsd, ntsd_len, &fattr); if (rc) goto out; @@ -1284,14 +1298,14 @@ int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon, inode->i_gid = fattr.cf_gid; mark_inode_dirty(inode); - ksmbd_vfs_remove_acl_xattrs(dentry); + ksmbd_vfs_remove_acl_xattrs(mnt_user_ns(path->mnt), path->dentry); /* Update posix acls */ if (fattr.cf_dacls) { - rc = ksmbd_vfs_set_posix_acl(inode, ACL_TYPE_ACCESS, - fattr.cf_acls); + rc = set_posix_acl(mnt_user_ns(path->mnt), inode, + ACL_TYPE_ACCESS, fattr.cf_acls); if (S_ISDIR(inode->i_mode) && fattr.cf_dacls) - rc = ksmbd_vfs_set_posix_acl(inode, ACL_TYPE_DEFAULT, - fattr.cf_dacls); + rc = set_posix_acl(mnt_user_ns(path->mnt), inode, + ACL_TYPE_DEFAULT, fattr.cf_dacls); } /* Check it only calling from SD BUFFER context */ @@ -1300,8 +1314,9 @@ int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon, if (test_share_config_flag(tcon->share_conf, KSMBD_SHARE_FLAG_ACL_XATTR)) { /* Update WinACL in xattr */ - ksmbd_vfs_remove_sd_xattrs(dentry); - ksmbd_vfs_set_sd_xattr(conn, dentry, pntsd, ntsd_len); + ksmbd_vfs_remove_sd_xattrs(mnt_user_ns(path->mnt), path->dentry); + ksmbd_vfs_set_sd_xattr(conn, mnt_user_ns(path->mnt), + path->dentry, pntsd, ntsd_len); } out: diff --git a/fs/cifsd/smbacl.h b/fs/ksmbd/smbacl.h index fb5480f0aa89..940f686a1d95 100644 --- a/fs/cifsd/smbacl.h +++ b/fs/ksmbd/smbacl.h @@ -17,18 +17,28 @@ #define NUM_AUTHS (6) /* number of authority fields */ #define SID_MAX_SUB_AUTHORITIES (15) /* max number of sub authority fields */ -#define ACCESS_ALLOWED 0 -#define ACCESS_DENIED 1 - -#define SIDOWNER 1 -#define SIDGROUP 2 -#define SIDCREATOR_OWNER 3 -#define SIDCREATOR_GROUP 4 -#define SIDUNIX_USER 5 -#define SIDUNIX_GROUP 6 -#define SIDNFS_USER 7 -#define SIDNFS_GROUP 8 -#define SIDNFS_MODE 9 +/* + * ACE types - see MS-DTYP 2.4.4.1 + */ +enum { + ACCESS_ALLOWED, + ACCESS_DENIED, +}; + +/* + * Security ID types + */ +enum { + SIDOWNER = 1, + SIDGROUP, + SIDCREATOR_OWNER, + SIDCREATOR_GROUP, + SIDUNIX_USER, + SIDUNIX_GROUP, + SIDNFS_USER, + SIDNFS_GROUP, + SIDNFS_MODE, +}; /* Revision for ACLs */ #define SD_REVISION 1 @@ -179,23 +189,23 @@ struct posix_acl_state { struct posix_ace_state_array *groups; }; -int parse_sec_desc(struct smb_ntsd *pntsd, int acl_len, - struct smb_fattr *fattr); -int build_sec_desc(struct smb_ntsd *pntsd, struct smb_ntsd *ppntsd, - int addition_info, __u32 *secdesclen, - struct smb_fattr *fattr); +int parse_sec_desc(struct user_namespace *user_ns, struct smb_ntsd *pntsd, + int acl_len, struct smb_fattr *fattr); +int build_sec_desc(struct user_namespace *user_ns, struct smb_ntsd *pntsd, + struct smb_ntsd *ppntsd, int addition_info, + __u32 *secdesclen, struct smb_fattr *fattr); int init_acl_state(struct posix_acl_state *state, int cnt); void free_acl_state(struct posix_acl_state *state); void posix_state_to_acl(struct posix_acl_state *state, struct posix_acl_entry *pace); int compare_sids(const struct smb_sid *ctsid, const struct smb_sid *cwsid); bool smb_inherit_flags(int flags, bool is_dir); -int smb_inherit_dacl(struct ksmbd_conn *conn, struct dentry *dentry, +int smb_inherit_dacl(struct ksmbd_conn *conn, struct path *path, unsigned int uid, unsigned int gid); -int smb_check_perm_dacl(struct ksmbd_conn *conn, struct dentry *dentry, +int smb_check_perm_dacl(struct ksmbd_conn *conn, struct path *path, __le32 *pdaccess, int uid); int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon, - struct dentry *dentry, struct smb_ntsd *pntsd, int ntsd_len, + struct path *path, struct smb_ntsd *pntsd, int ntsd_len, bool type_check); void id_to_sid(unsigned int cid, uint sidtype, struct smb_sid *ssid); void ksmbd_init_domain(u32 *sub_auth); diff --git a/fs/cifsd/smbfsctl.h b/fs/ksmbd/smbfsctl.h index b98418aae20c..b98418aae20c 100644 --- a/fs/cifsd/smbfsctl.h +++ b/fs/ksmbd/smbfsctl.h diff --git a/fs/cifsd/smbstatus.h b/fs/ksmbd/smbstatus.h index 108a8b6ed24a..108a8b6ed24a 100644 --- a/fs/cifsd/smbstatus.h +++ b/fs/ksmbd/smbstatus.h diff --git a/fs/cifsd/transport_ipc.c b/fs/ksmbd/transport_ipc.c index b09df832431f..ca5099118fdf 100644 --- a/fs/cifsd/transport_ipc.c +++ b/fs/ksmbd/transport_ipc.c @@ -16,7 +16,6 @@ #include "vfs_cache.h" #include "transport_ipc.h" -#include "buffer_pool.h" #include "server.h" #include "smb_common.h" @@ -39,16 +38,14 @@ static DEFINE_IDA(ipc_ida); static unsigned int ksmbd_tools_pid; -#define KSMBD_IPC_MSG_HANDLE(m) (*(unsigned int *)m) - static bool ksmbd_ipc_validate_version(struct genl_info *m) { if (m->genlhdr->version != KSMBD_GENL_VERSION) { - ksmbd_err("%s. ksmbd: %d, kernel module: %d. %s.\n", - "Daemon and kernel module version mismatch", - m->genlhdr->version, - KSMBD_GENL_VERSION, - "User-space ksmbd should terminate"); + pr_err("%s. ksmbd: %d, kernel module: %d. %s.\n", + "Daemon and kernel module version mismatch", + m->genlhdr->version, + KSMBD_GENL_VERSION, + "User-space ksmbd should terminate"); return false; } return true; @@ -57,12 +54,9 @@ static bool ksmbd_ipc_validate_version(struct genl_info *m) struct ksmbd_ipc_msg { unsigned int type; unsigned int sz; - unsigned char ____payload[0]; + unsigned char payload[]; }; -#define KSMBD_IPC_MSG_PAYLOAD(m) \ - ((void *)(((struct ksmbd_ipc_msg *)(m))->____payload)) - struct ipc_msg_table_entry { unsigned int handle; unsigned int type; @@ -252,7 +246,7 @@ static void ipc_msg_handle_free(int handle) static int handle_response(int type, void *payload, size_t sz) { - int handle = KSMBD_IPC_MSG_HANDLE(payload); + unsigned int handle = *(unsigned int *)payload; struct ipc_msg_table_entry *entry; int ret = 0; @@ -268,8 +262,8 @@ static int handle_response(int type, void *payload, size_t sz) * request message type + 1. */ if (entry->type + 1 != type) { - ksmbd_err("Waiting for IPC type %d, got %d. Ignore.\n", - entry->type + 1, type); + pr_err("Waiting for IPC type %d, got %d. Ignore.\n", + entry->type + 1, type); } entry->response = kvmalloc(sz, GFP_KERNEL | __GFP_ZERO); @@ -314,9 +308,9 @@ static int ipc_server_config_on_startup(struct ksmbd_startup_request *req) ret |= ksmbd_tcp_set_interfaces(KSMBD_STARTUP_CONFIG_INTERFACES(req), req->ifc_list_sz); if (ret) { - ksmbd_err("Server configuration error: %s %s %s\n", - req->netbios_name, req->server_string, - req->work_group); + pr_err("Server configuration error: %s %s %s\n", + req->netbios_name, req->server_string, + req->work_group); return ret; } @@ -354,7 +348,7 @@ static int handle_startup_event(struct sk_buff *skb, struct genl_info *info) mutex_lock(&startup_lock); if (!ksmbd_server_configurable()) { mutex_unlock(&startup_lock); - ksmbd_err("Server reset is in progress, can't start daemon\n"); + pr_err("Server reset is in progress, can't start daemon\n"); return -EINVAL; } @@ -364,7 +358,7 @@ static int handle_startup_event(struct sk_buff *skb, struct genl_info *info) goto out; } - ksmbd_err("Reconnect to a new user space daemon\n"); + pr_err("Reconnect to a new user space daemon\n"); } else { struct ksmbd_startup_request *req; @@ -385,7 +379,7 @@ out: static int handle_unsupported_event(struct sk_buff *skb, struct genl_info *info) { - ksmbd_err("Unknown IPC event: %d, ignore.\n", info->genlhdr->cmd); + pr_err("Unknown IPC event: %d, ignore.\n", info->genlhdr->cmd); return -EINVAL; } @@ -433,7 +427,7 @@ static int ipc_msg_send(struct ksmbd_ipc_msg *msg) if (!nlh) goto out; - ret = nla_put(skb, msg->type, msg->sz, KSMBD_IPC_MSG_PAYLOAD(msg)); + ret = nla_put(skb, msg->type, msg->sz, msg->payload); if (ret) { genlmsg_cancel(skb, nlh); goto out; @@ -510,7 +504,7 @@ struct ksmbd_login_response *ksmbd_ipc_login_request(const char *account) return NULL; msg->type = KSMBD_EVENT_LOGIN_REQUEST; - req = KSMBD_IPC_MSG_PAYLOAD(msg); + req = (struct ksmbd_login_request *)msg->payload; req->handle = ksmbd_acquire_id(&ipc_ida); strscpy(req->account, account, KSMBD_REQ_MAX_ACCOUNT_NAME_SZ); @@ -533,7 +527,7 @@ ksmbd_ipc_spnego_authen_request(const char *spnego_blob, int blob_len) return NULL; msg->type = KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST; - req = KSMBD_IPC_MSG_PAYLOAD(msg); + req = (struct ksmbd_spnego_authen_request *)msg->payload; req->handle = ksmbd_acquire_id(&ipc_ida); req->spnego_blob_len = blob_len; memcpy(req->spnego_blob, spnego_blob, blob_len); @@ -565,7 +559,7 @@ ksmbd_ipc_tree_connect_request(struct ksmbd_session *sess, return NULL; msg->type = KSMBD_EVENT_TREE_CONNECT_REQUEST; - req = KSMBD_IPC_MSG_PAYLOAD(msg); + req = (struct ksmbd_tree_connect_request *)msg->payload; req->handle = ksmbd_acquire_id(&ipc_ida); req->account_flags = sess->user->flags; @@ -598,7 +592,7 @@ int ksmbd_ipc_tree_disconnect_request(unsigned long long session_id, return -ENOMEM; msg->type = KSMBD_EVENT_TREE_DISCONNECT_REQUEST; - req = KSMBD_IPC_MSG_PAYLOAD(msg); + req = (struct ksmbd_tree_disconnect_request *)msg->payload; req->session_id = session_id; req->connect_id = connect_id; @@ -621,7 +615,7 @@ int ksmbd_ipc_logout_request(const char *account) return -ENOMEM; msg->type = KSMBD_EVENT_LOGOUT_REQUEST; - req = KSMBD_IPC_MSG_PAYLOAD(msg); + req = (struct ksmbd_logout_request *)msg->payload; strscpy(req->account, account, KSMBD_REQ_MAX_ACCOUNT_NAME_SZ); ret = ipc_msg_send(msg); @@ -644,7 +638,7 @@ ksmbd_ipc_share_config_request(const char *name) return NULL; msg->type = KSMBD_EVENT_SHARE_CONFIG_REQUEST; - req = KSMBD_IPC_MSG_PAYLOAD(msg); + req = (struct ksmbd_share_config_request *)msg->payload; req->handle = ksmbd_acquire_id(&ipc_ida); strscpy(req->share_name, name, KSMBD_REQ_MAX_SHARE_NAME); @@ -665,7 +659,7 @@ struct ksmbd_rpc_command *ksmbd_rpc_open(struct ksmbd_session *sess, int handle) return NULL; msg->type = KSMBD_EVENT_RPC_REQUEST; - req = KSMBD_IPC_MSG_PAYLOAD(msg); + req = (struct ksmbd_rpc_command *)msg->payload; req->handle = handle; req->flags = ksmbd_session_rpc_method(sess, handle); req->flags |= KSMBD_RPC_OPEN_METHOD; @@ -687,7 +681,7 @@ struct ksmbd_rpc_command *ksmbd_rpc_close(struct ksmbd_session *sess, int handle return NULL; msg->type = KSMBD_EVENT_RPC_REQUEST; - req = KSMBD_IPC_MSG_PAYLOAD(msg); + req = (struct ksmbd_rpc_command *)msg->payload; req->handle = handle; req->flags = ksmbd_session_rpc_method(sess, handle); req->flags |= KSMBD_RPC_CLOSE_METHOD; @@ -710,7 +704,7 @@ struct ksmbd_rpc_command *ksmbd_rpc_write(struct ksmbd_session *sess, int handle return NULL; msg->type = KSMBD_EVENT_RPC_REQUEST; - req = KSMBD_IPC_MSG_PAYLOAD(msg); + req = (struct ksmbd_rpc_command *)msg->payload; req->handle = handle; req->flags = ksmbd_session_rpc_method(sess, handle); req->flags |= rpc_context_flags(sess); @@ -734,7 +728,7 @@ struct ksmbd_rpc_command *ksmbd_rpc_read(struct ksmbd_session *sess, int handle) return NULL; msg->type = KSMBD_EVENT_RPC_REQUEST; - req = KSMBD_IPC_MSG_PAYLOAD(msg); + req = (struct ksmbd_rpc_command *)msg->payload; req->handle = handle; req->flags = ksmbd_session_rpc_method(sess, handle); req->flags |= rpc_context_flags(sess); @@ -758,7 +752,7 @@ struct ksmbd_rpc_command *ksmbd_rpc_ioctl(struct ksmbd_session *sess, int handle return NULL; msg->type = KSMBD_EVENT_RPC_REQUEST; - req = KSMBD_IPC_MSG_PAYLOAD(msg); + req = (struct ksmbd_rpc_command *)req->payload; req->handle = handle; req->flags = ksmbd_session_rpc_method(sess, handle); req->flags |= rpc_context_flags(sess); @@ -783,7 +777,7 @@ struct ksmbd_rpc_command *ksmbd_rpc_rap(struct ksmbd_session *sess, void *payloa return NULL; msg->type = KSMBD_EVENT_RPC_REQUEST; - req = KSMBD_IPC_MSG_PAYLOAD(msg); + req = (struct ksmbd_rpc_command *)req->payload; req->handle = ksmbd_acquire_id(&ipc_ida); req->flags = rpc_context_flags(sess); req->flags |= KSMBD_RPC_RAP_METHOD; @@ -828,7 +822,7 @@ static int __ipc_heartbeat(void) WRITE_ONCE(server_conf.state, SERVER_STATE_RESETTING); server_conf.ipc_last_active = 0; ksmbd_tools_pid = 0; - ksmbd_err("No IPC daemon response for %lus\n", delta / HZ); + pr_err("No IPC daemon response for %lus\n", delta / HZ); mutex_unlock(&startup_lock); return -EINVAL; } @@ -872,7 +866,7 @@ int ksmbd_ipc_init(void) ret = genl_register_family(&ksmbd_genl_family); if (ret) { - ksmbd_err("Failed to register KSMBD netlink interface %d\n", ret); + pr_err("Failed to register KSMBD netlink interface %d\n", ret); cancel_delayed_work_sync(&ipc_timer_work); } diff --git a/fs/cifsd/transport_ipc.h b/fs/ksmbd/transport_ipc.h index 9eacc895ffdb..9eacc895ffdb 100644 --- a/fs/cifsd/transport_ipc.h +++ b/fs/ksmbd/transport_ipc.h diff --git a/fs/cifsd/transport_rdma.c b/fs/ksmbd/transport_rdma.c index efaa9776841f..171fb3dd018a 100644 --- a/fs/cifsd/transport_rdma.c +++ b/fs/ksmbd/transport_rdma.c @@ -33,7 +33,6 @@ #include "connection.h" #include "smb_common.h" #include "smbstatus.h" -#include "buffer_pool.h" #include "transport_rdma.h" #define SMB_DIRECT_PORT 5445 @@ -159,8 +158,6 @@ struct smb_direct_transport { }; #define KSMBD_TRANS(t) ((struct ksmbd_transport *)&((t)->transport)) -#define SMB_DIRECT_TRANS(t) ((struct smb_direct_transport *)container_of(t, \ - struct smb_direct_transport, transport)) enum { SMB_DIRECT_MSG_NEGOTIATE_REQ = 0, @@ -205,9 +202,11 @@ struct smb_direct_rdma_rw_msg { struct scatterlist sg_list[0]; }; -#define BUFFER_NR_PAGES(buf, len) \ - (DIV_ROUND_UP((unsigned long)(buf) + (len), PAGE_SIZE) \ - - (unsigned long)(buf) / PAGE_SIZE) +static inline int get_buf_page_count(void *buf, int size) +{ + return DIV_ROUND_UP((uintptr_t)buf + size, PAGE_SIZE) - + (uintptr_t)buf / PAGE_SIZE; +} static void smb_direct_destroy_pools(struct smb_direct_transport *transport); static void smb_direct_post_recv_credits(struct work_struct *work); @@ -216,6 +215,12 @@ static int smb_direct_post_send_data(struct smb_direct_transport *t, struct kvec *iov, int niov, int remaining_data_length); +static inline struct smb_direct_transport * +smb_trans_direct_transfort(struct ksmbd_transport *t) +{ + return container_of(t, struct smb_direct_transport, transport); +} + static inline void *smb_direct_recvmsg_payload(struct smb_direct_recvmsg *recvmsg) { @@ -526,9 +531,9 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc) if (wc->status != IB_WC_SUCCESS || wc->opcode != IB_WC_RECV) { if (wc->status != IB_WC_WR_FLUSH_ERR) { - ksmbd_err("Recv error. status='%s (%d)' opcode=%d\n", - ib_wc_status_msg(wc->status), wc->status, - wc->opcode); + pr_err("Recv error. status='%s (%d)' opcode=%d\n", + ib_wc_status_msg(wc->status), wc->status, + wc->opcode); smb_direct_disconnect_rdma_connection(t); } put_empty_recvmsg(t, recvmsg); @@ -624,7 +629,7 @@ static int smb_direct_post_recv(struct smb_direct_transport *t, ret = ib_post_recv(t->qp, &wr, NULL); if (ret) { - ksmbd_err("Can't post recv: %d\n", ret); + pr_err("Can't post recv: %d\n", ret); ib_dma_unmap_single(t->cm_id->device, recvmsg->sge.addr, recvmsg->sge.length, DMA_FROM_DEVICE); @@ -642,11 +647,11 @@ static int smb_direct_read(struct ksmbd_transport *t, char *buf, int to_copy, to_read, data_read, offset; u32 data_length, remaining_data_length, data_offset; int rc; - struct smb_direct_transport *st = SMB_DIRECT_TRANS(t); + struct smb_direct_transport *st = smb_trans_direct_transfort(t); again: if (st->status != SMB_DIRECT_CS_CONNECTED) { - ksmbd_err("disconnected\n"); + pr_err("disconnected\n"); return -ENOTCONN; } @@ -795,7 +800,7 @@ static void smb_direct_post_recv_credits(struct work_struct *work) ret = smb_direct_post_recv(t, recvmsg); if (ret) { - ksmbd_err("Can't post recv: %d\n", ret); + pr_err("Can't post recv: %d\n", ret); put_recvmsg(t, recvmsg); break; } @@ -830,9 +835,9 @@ static void send_done(struct ib_cq *cq, struct ib_wc *wc) wc->opcode); if (wc->status != IB_WC_SUCCESS || wc->opcode != IB_WC_SEND) { - ksmbd_err("Send error. status='%s (%d)', opcode=%d\n", - ib_wc_status_msg(wc->status), wc->status, - wc->opcode); + pr_err("Send error. status='%s (%d)', opcode=%d\n", + ib_wc_status_msg(wc->status), wc->status, + wc->opcode); smb_direct_disconnect_rdma_connection(t); } @@ -881,7 +886,7 @@ static int smb_direct_post_send(struct smb_direct_transport *t, ret = ib_post_send(t->qp, wr, NULL); if (ret) { - ksmbd_err("failed to post send: %d\n", ret); + pr_err("failed to post send: %d\n", ret); if (wr->num_sge > 1) { if (atomic_dec_and_test(&t->send_payload_pending)) wake_up(&t->wait_send_payload_pending); @@ -1049,7 +1054,7 @@ static int get_sg_list(void *buf, int size, struct scatterlist *sg_list, int nen int offset, len; int i = 0; - if (nentries < BUFFER_NR_PAGES(buf, size)) + if (nentries < get_buf_page_count(buf, size)) return -EINVAL; offset = offset_in_page(buf); @@ -1159,11 +1164,11 @@ static int smb_direct_post_send_data(struct smb_direct_transport *t, sg, SMB_DIRECT_MAX_SEND_SGES - 1, DMA_TO_DEVICE); if (sg_cnt <= 0) { - ksmbd_err("failed to map buffer\n"); + pr_err("failed to map buffer\n"); ret = -ENOMEM; goto err; } else if (sg_cnt + msg->num_sge > SMB_DIRECT_MAX_SEND_SGES - 1) { - ksmbd_err("buffer not fitted into sges\n"); + pr_err("buffer not fitted into sges\n"); ret = -E2BIG; ib_dma_unmap_sg(t->cm_id->device, sg, sg_cnt, DMA_TO_DEVICE); @@ -1193,7 +1198,7 @@ static int smb_direct_writev(struct ksmbd_transport *t, struct kvec *iov, int niovs, int buflen, bool need_invalidate, unsigned int remote_key) { - struct smb_direct_transport *st = SMB_DIRECT_TRANS(t); + struct smb_direct_transport *st = smb_trans_direct_transfort(t); int remaining_data_length; int start, i, j; int max_iov_size = st->max_send_size - @@ -1291,8 +1296,8 @@ static void read_write_done(struct ib_cq *cq, struct ib_wc *wc, struct smb_direct_transport *t = msg->t; if (wc->status != IB_WC_SUCCESS) { - ksmbd_err("read/write error. opcode = %d, status = %s(%d)\n", - wc->opcode, ib_wc_status_msg(wc->status), wc->status); + pr_err("read/write error. opcode = %d, status = %s(%d)\n", + wc->opcode, ib_wc_status_msg(wc->status), wc->status); smb_direct_disconnect_rdma_connection(t); } @@ -1339,7 +1344,7 @@ static int smb_direct_rdma_xmit(struct smb_direct_transport *t, void *buf, msg->sgt.sgl = &msg->sg_list[0]; ret = sg_alloc_table_chained(&msg->sgt, - BUFFER_NR_PAGES(buf, buf_len), + get_buf_page_count(buf, buf_len), msg->sg_list, SG_CHUNK_SIZE); if (ret) { atomic_inc(&t->rw_avail_ops); @@ -1349,16 +1354,16 @@ static int smb_direct_rdma_xmit(struct smb_direct_transport *t, void *buf, ret = get_sg_list(buf, buf_len, msg->sgt.sgl, msg->sgt.orig_nents); if (ret <= 0) { - ksmbd_err("failed to get pages\n"); + pr_err("failed to get pages\n"); goto err; } ret = rdma_rw_ctx_init(&msg->rw_ctx, t->qp, t->qp->port, - msg->sg_list, BUFFER_NR_PAGES(buf, buf_len), + msg->sg_list, get_buf_page_count(buf, buf_len), 0, remote_offset, remote_key, is_read ? DMA_FROM_DEVICE : DMA_TO_DEVICE); if (ret < 0) { - ksmbd_err("failed to init rdma_rw_ctx: %d\n", ret); + pr_err("failed to init rdma_rw_ctx: %d\n", ret); goto err; } @@ -1370,7 +1375,7 @@ static int smb_direct_rdma_xmit(struct smb_direct_transport *t, void *buf, ret = ib_post_send(t->qp, first_wr, NULL); if (ret) { - ksmbd_err("failed to post send wr: %d\n", ret); + pr_err("failed to post send wr: %d\n", ret); goto err; } @@ -1392,7 +1397,7 @@ static int smb_direct_rdma_write(struct ksmbd_transport *t, void *buf, unsigned int buflen, u32 remote_key, u64 remote_offset, u32 remote_len) { - return smb_direct_rdma_xmit(SMB_DIRECT_TRANS(t), buf, buflen, + return smb_direct_rdma_xmit(smb_trans_direct_transfort(t), buf, buflen, remote_key, remote_offset, remote_len, false); } @@ -1401,14 +1406,14 @@ static int smb_direct_rdma_read(struct ksmbd_transport *t, void *buf, unsigned int buflen, u32 remote_key, u64 remote_offset, u32 remote_len) { - return smb_direct_rdma_xmit(SMB_DIRECT_TRANS(t), buf, buflen, + return smb_direct_rdma_xmit(smb_trans_direct_transfort(t), buf, buflen, remote_key, remote_offset, remote_len, true); } static void smb_direct_disconnect(struct ksmbd_transport *t) { - struct smb_direct_transport *st = SMB_DIRECT_TRANS(t); + struct smb_direct_transport *st = smb_trans_direct_transfort(t); ksmbd_debug(RDMA, "Disconnecting cm_id=%p\n", st->cm_id); @@ -1446,9 +1451,9 @@ static int smb_direct_cm_handler(struct rdma_cm_id *cm_id, break; } default: - ksmbd_err("Unexpected RDMA CM event. cm_id=%p, event=%s (%d)\n", - cm_id, rdma_event_msg(event->event), - event->event); + pr_err("Unexpected RDMA CM event. cm_id=%p, event=%s (%d)\n", + cm_id, rdma_event_msg(event->event), + event->event); break; } return 0; @@ -1558,7 +1563,7 @@ static int smb_direct_accept_client(struct smb_direct_transport *t) ret = rdma_accept(t->cm_id, &conn_param); if (ret) { - ksmbd_err("error at rdma_accept: %d\n", ret); + pr_err("error at rdma_accept: %d\n", ret); return ret; } @@ -1582,14 +1587,14 @@ static int smb_direct_negotiate(struct smb_direct_transport *t) ret = smb_direct_post_recv(t, recvmsg); if (ret) { - ksmbd_err("Can't post recv: %d\n", ret); + pr_err("Can't post recv: %d\n", ret); goto out; } t->negotiation_requested = false; ret = smb_direct_accept_client(t); if (ret) { - ksmbd_err("Can't accept client\n"); + pr_err("Can't accept client\n"); goto out; } @@ -1636,7 +1641,7 @@ static int smb_direct_init_params(struct smb_direct_transport *t, t->max_send_size = smb_direct_max_send_size; max_send_sges = DIV_ROUND_UP(t->max_send_size, PAGE_SIZE) + 2; if (max_send_sges > SMB_DIRECT_MAX_SEND_SGES) { - ksmbd_err("max_send_size %d is too large\n", t->max_send_size); + pr_err("max_send_size %d is too large\n", t->max_send_size); return -EINVAL; } @@ -1656,31 +1661,31 @@ static int smb_direct_init_params(struct smb_direct_transport *t, max_send_wrs = smb_direct_send_credit_target + max_rw_wrs; if (max_send_wrs > device->attrs.max_cqe || max_send_wrs > device->attrs.max_qp_wr) { - ksmbd_err("consider lowering send_credit_target = %d, or max_outstanding_rw_ops = %d\n", - smb_direct_send_credit_target, - smb_direct_max_outstanding_rw_ops); - ksmbd_err("Possible CQE overrun, device reporting max_cqe %d max_qp_wr %d\n", - device->attrs.max_cqe, device->attrs.max_qp_wr); + pr_err("consider lowering send_credit_target = %d, or max_outstanding_rw_ops = %d\n", + smb_direct_send_credit_target, + smb_direct_max_outstanding_rw_ops); + pr_err("Possible CQE overrun, device reporting max_cqe %d max_qp_wr %d\n", + device->attrs.max_cqe, device->attrs.max_qp_wr); return -EINVAL; } if (smb_direct_receive_credit_max > device->attrs.max_cqe || smb_direct_receive_credit_max > device->attrs.max_qp_wr) { - ksmbd_err("consider lowering receive_credit_max = %d\n", - smb_direct_receive_credit_max); - ksmbd_err("Possible CQE overrun, device reporting max_cpe %d max_qp_wr %d\n", - device->attrs.max_cqe, device->attrs.max_qp_wr); + pr_err("consider lowering receive_credit_max = %d\n", + smb_direct_receive_credit_max); + pr_err("Possible CQE overrun, device reporting max_cpe %d max_qp_wr %d\n", + device->attrs.max_cqe, device->attrs.max_qp_wr); return -EINVAL; } if (device->attrs.max_send_sge < SMB_DIRECT_MAX_SEND_SGES) { - ksmbd_err("warning: device max_send_sge = %d too small\n", - device->attrs.max_send_sge); + pr_err("warning: device max_send_sge = %d too small\n", + device->attrs.max_send_sge); return -EINVAL; } if (device->attrs.max_recv_sge < SMB_DIRECT_MAX_RECV_SGES) { - ksmbd_err("warning: device max_recv_sge = %d too small\n", - device->attrs.max_recv_sge); + pr_err("warning: device max_recv_sge = %d too small\n", + device->attrs.max_recv_sge); return -EINVAL; } @@ -1789,7 +1794,7 @@ static int smb_direct_create_qpair(struct smb_direct_transport *t, t->pd = ib_alloc_pd(t->cm_id->device, 0); if (IS_ERR(t->pd)) { - ksmbd_err("Can't create RDMA PD\n"); + pr_err("Can't create RDMA PD\n"); ret = PTR_ERR(t->pd); t->pd = NULL; return ret; @@ -1798,7 +1803,7 @@ static int smb_direct_create_qpair(struct smb_direct_transport *t, t->send_cq = ib_alloc_cq(t->cm_id->device, t, t->send_credit_target, 0, IB_POLL_WORKQUEUE); if (IS_ERR(t->send_cq)) { - ksmbd_err("Can't create RDMA send CQ\n"); + pr_err("Can't create RDMA send CQ\n"); ret = PTR_ERR(t->send_cq); t->send_cq = NULL; goto err; @@ -1808,7 +1813,7 @@ static int smb_direct_create_qpair(struct smb_direct_transport *t, cap->max_send_wr + cap->max_rdma_ctxs, 0, IB_POLL_WORKQUEUE); if (IS_ERR(t->recv_cq)) { - ksmbd_err("Can't create RDMA recv CQ\n"); + pr_err("Can't create RDMA recv CQ\n"); ret = PTR_ERR(t->recv_cq); t->recv_cq = NULL; goto err; @@ -1826,7 +1831,7 @@ static int smb_direct_create_qpair(struct smb_direct_transport *t, ret = rdma_create_qp(t->cm_id, t->pd, &qp_attr); if (ret) { - ksmbd_err("Can't create RDMA QP: %d\n", ret); + pr_err("Can't create RDMA QP: %d\n", ret); goto err; } @@ -1856,31 +1861,31 @@ err: static int smb_direct_prepare(struct ksmbd_transport *t) { - struct smb_direct_transport *st = SMB_DIRECT_TRANS(t); + struct smb_direct_transport *st = smb_trans_direct_transfort(t); int ret; struct ib_qp_cap qp_cap; ret = smb_direct_init_params(st, &qp_cap); if (ret) { - ksmbd_err("Can't configure RDMA parameters\n"); + pr_err("Can't configure RDMA parameters\n"); return ret; } ret = smb_direct_create_pools(st); if (ret) { - ksmbd_err("Can't init RDMA pool: %d\n", ret); + pr_err("Can't init RDMA pool: %d\n", ret); return ret; } ret = smb_direct_create_qpair(st, &qp_cap); if (ret) { - ksmbd_err("Can't accept RDMA client: %d\n", ret); + pr_err("Can't accept RDMA client: %d\n", ret); return ret; } ret = smb_direct_negotiate(st); if (ret) { - ksmbd_err("Can't negotiate: %d\n", ret); + pr_err("Can't negotiate: %d\n", ret); return ret; } @@ -1918,7 +1923,7 @@ static int smb_direct_handle_connect_request(struct rdma_cm_id *new_cm_id) if (IS_ERR(KSMBD_TRANS(t)->handler)) { int ret = PTR_ERR(KSMBD_TRANS(t)->handler); - ksmbd_err("Can't start thread\n"); + pr_err("Can't start thread\n"); free_transport(t); return ret; } @@ -1934,7 +1939,7 @@ static int smb_direct_listen_handler(struct rdma_cm_id *cm_id, int ret = smb_direct_handle_connect_request(cm_id); if (ret) { - ksmbd_err("Can't create transport: %d\n", ret); + pr_err("Can't create transport: %d\n", ret); return ret; } @@ -1943,8 +1948,8 @@ static int smb_direct_listen_handler(struct rdma_cm_id *cm_id, break; } default: - ksmbd_err("Unexpected listen event. cm_id=%p, event=%s (%d)\n", - cm_id, rdma_event_msg(event->event), event->event); + pr_err("Unexpected listen event. cm_id=%p, event=%s (%d)\n", + cm_id, rdma_event_msg(event->event), event->event); break; } return 0; @@ -1963,13 +1968,13 @@ static int smb_direct_listen(int port) cm_id = rdma_create_id(&init_net, smb_direct_listen_handler, &smb_direct_listener, RDMA_PS_TCP, IB_QPT_RC); if (IS_ERR(cm_id)) { - ksmbd_err("Can't create cm id: %ld\n", PTR_ERR(cm_id)); + pr_err("Can't create cm id: %ld\n", PTR_ERR(cm_id)); return PTR_ERR(cm_id); } ret = rdma_bind_addr(cm_id, (struct sockaddr *)&sin); if (ret) { - ksmbd_err("Can't bind: %d\n", ret); + pr_err("Can't bind: %d\n", ret); goto err; } @@ -1977,7 +1982,7 @@ static int smb_direct_listen(int port) ret = rdma_listen(cm_id, 10); if (ret) { - ksmbd_err("Can't listen: %d\n", ret); + pr_err("Can't listen: %d\n", ret); goto err; } return 0; @@ -2007,7 +2012,7 @@ int ksmbd_rdma_init(void) if (ret) { destroy_workqueue(smb_direct_wq); smb_direct_wq = NULL; - ksmbd_err("Can't listen: %d\n", ret); + pr_err("Can't listen: %d\n", ret); return ret; } diff --git a/fs/cifsd/transport_rdma.h b/fs/ksmbd/transport_rdma.h index da60fcec3ede..da60fcec3ede 100644 --- a/fs/cifsd/transport_rdma.h +++ b/fs/ksmbd/transport_rdma.h diff --git a/fs/cifsd/transport_tcp.c b/fs/ksmbd/transport_tcp.c index d6d5c0038dea..56ec11ff5a9f 100644 --- a/fs/cifsd/transport_tcp.c +++ b/fs/ksmbd/transport_tcp.c @@ -9,7 +9,6 @@ #include "smb_common.h" #include "server.h" #include "auth.h" -#include "buffer_pool.h" #include "connection.h" #include "transport_tcp.h" @@ -191,7 +190,7 @@ static int ksmbd_tcp_new_connection(struct socket *client_sk) csin = KSMBD_TCP_PEER_SOCKADDR(KSMBD_TRANS(t)->conn); if (kernel_getpeername(client_sk, csin) < 0) { - ksmbd_err("client ip resolution failed\n"); + pr_err("client ip resolution failed\n"); rc = -EINVAL; goto out_error; } @@ -201,7 +200,7 @@ static int ksmbd_tcp_new_connection(struct socket *client_sk) "ksmbd:%u", ksmbd_tcp_get_port(csin)); if (IS_ERR(KSMBD_TRANS(t)->handler)) { - ksmbd_err("cannot start conn thread\n"); + pr_err("cannot start conn thread\n"); rc = PTR_ERR(KSMBD_TRANS(t)->handler); free_transport(t); } @@ -381,7 +380,7 @@ static void tcp_destroy_socket(struct socket *ksmbd_socket) ret = kernel_sock_shutdown(ksmbd_socket, SHUT_RDWR); if (ret) - ksmbd_err("Failed to shutdown socket: %d\n", ret); + pr_err("Failed to shutdown socket: %d\n", ret); else sock_release(ksmbd_socket); } @@ -401,11 +400,11 @@ static int create_socket(struct interface *iface) ret = sock_create(PF_INET6, SOCK_STREAM, IPPROTO_TCP, &ksmbd_socket); if (ret) { - ksmbd_err("Can't create socket for ipv6, try ipv4: %d\n", ret); + pr_err("Can't create socket for ipv6, try ipv4: %d\n", ret); ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &ksmbd_socket); if (ret) { - ksmbd_err("Can't create socket for ipv4: %d\n", ret); + pr_err("Can't create socket for ipv4: %d\n", ret); goto out_error; } @@ -428,7 +427,7 @@ static int create_socket(struct interface *iface) KERNEL_SOCKPTR(iface->name), strlen(iface->name)); if (ret != -ENODEV && ret < 0) { - ksmbd_err("Failed to set SO_BINDTODEVICE: %d\n", ret); + pr_err("Failed to set SO_BINDTODEVICE: %d\n", ret); goto out_error; } @@ -439,7 +438,7 @@ static int create_socket(struct interface *iface) ret = kernel_bind(ksmbd_socket, (struct sockaddr *)&sin6, sizeof(sin6)); if (ret) { - ksmbd_err("Failed to bind socket: %d\n", ret); + pr_err("Failed to bind socket: %d\n", ret); goto out_error; } @@ -448,14 +447,14 @@ static int create_socket(struct interface *iface) ret = kernel_listen(ksmbd_socket, KSMBD_SOCKET_BACKLOG); if (ret) { - ksmbd_err("Port listen() error: %d\n", ret); + pr_err("Port listen() error: %d\n", ret); goto out_error; } iface->ksmbd_socket = ksmbd_socket; ret = ksmbd_tcp_run_kthread(iface); if (ret) { - ksmbd_err("Can't start ksmbd main kthread: %d\n", ret); + pr_err("Can't start ksmbd main kthread: %d\n", ret); goto out_error; } iface->state = IFACE_STATE_CONFIGURED; @@ -541,7 +540,7 @@ static void tcp_stop_kthread(struct task_struct *kthread) ret = kthread_stop(kthread); if (ret) - ksmbd_err("failed to stop forker thread\n"); + pr_err("failed to stop forker thread\n"); } void ksmbd_tcp_destroy(void) diff --git a/fs/cifsd/transport_tcp.h b/fs/ksmbd/transport_tcp.h index e338bebe322f..e338bebe322f 100644 --- a/fs/cifsd/transport_tcp.h +++ b/fs/ksmbd/transport_tcp.h diff --git a/fs/cifsd/unicode.c b/fs/ksmbd/unicode.c index a0db699ddafd..a0db699ddafd 100644 --- a/fs/cifsd/unicode.c +++ b/fs/ksmbd/unicode.c diff --git a/fs/cifsd/unicode.h b/fs/ksmbd/unicode.h index 5593024230ae..5593024230ae 100644 --- a/fs/cifsd/unicode.h +++ b/fs/ksmbd/unicode.h diff --git a/fs/cifsd/uniupr.h b/fs/ksmbd/uniupr.h index 26583b776897..26583b776897 100644 --- a/fs/cifsd/uniupr.h +++ b/fs/ksmbd/uniupr.h diff --git a/fs/cifsd/vfs.c b/fs/ksmbd/vfs.c index 9111b485d611..0f5a4fb8215f 100644 --- a/fs/cifsd/vfs.c +++ b/fs/ksmbd/vfs.c @@ -12,7 +12,6 @@ #include <linux/xattr.h> #include <linux/falloc.h> #include <linux/genhd.h> -#include <linux/blkdev.h> #include <linux/fsnotify.h> #include <linux/dcache.h> #include <linux/slab.h> @@ -23,7 +22,6 @@ #include "glob.h" #include "oplock.h" #include "connection.h" -#include "buffer_pool.h" #include "vfs.h" #include "vfs_cache.h" #include "smbacl.h" @@ -46,7 +44,7 @@ static char *extract_last_component(char *path) p++; } else { p = NULL; - ksmbd_err("Invalid path %s\n", path); + pr_err("Invalid path %s\n", path); } return p; } @@ -62,92 +60,92 @@ static void ksmbd_vfs_inherit_owner(struct ksmbd_work *work, i_uid_write(inode, i_uid_read(parent_inode)); } -int ksmbd_vfs_inode_permission(struct dentry *dentry, int acc_mode, bool delete) +/** + * ksmbd_vfs_lock_parent() - lock parent dentry if it is stable + * + * the parent dentry got by dget_parent or @parent could be + * unstable, we try to lock a parent inode and lookup the + * child dentry again. + * + * the reference count of @parent isn't incremented. + */ +int ksmbd_vfs_lock_parent(struct dentry *parent, struct dentry *child) { - int mask, ret = 0; - - mask = 0; - acc_mode &= O_ACCMODE; - - if (acc_mode == O_RDONLY) - mask = MAY_READ; - else if (acc_mode == O_WRONLY) - mask = MAY_WRITE; - else if (acc_mode == O_RDWR) - mask = MAY_READ | MAY_WRITE; + struct dentry *dentry; + int ret = 0; - if (inode_permission(&init_user_ns, d_inode(dentry), mask | MAY_OPEN)) - return -EACCES; + inode_lock_nested(d_inode(parent), I_MUTEX_PARENT); + dentry = lookup_one_len(child->d_name.name, parent, + child->d_name.len); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto out_err; + } - if (delete) { - struct dentry *child, *parent; + if (dentry != child) { + ret = -ESTALE; + dput(dentry); + goto out_err; + } - parent = dget_parent(dentry); - inode_lock_nested(d_inode(parent), I_MUTEX_PARENT); - child = lookup_one_len(dentry->d_name.name, parent, - dentry->d_name.len); - if (IS_ERR(child)) { - ret = PTR_ERR(child); - goto out_lock; - } + dput(dentry); + return 0; +out_err: + inode_unlock(d_inode(parent)); + return ret; +} - if (child != dentry) { - ret = -ESTALE; - dput(child); - goto out_lock; - } - dput(child); +int ksmbd_vfs_may_delete(struct user_namespace *user_ns, + struct dentry *dentry) +{ + struct dentry *parent; + int ret; - if (inode_permission(&init_user_ns, d_inode(parent), MAY_EXEC | MAY_WRITE)) { - ret = -EACCES; - goto out_lock; - } -out_lock: - inode_unlock(d_inode(parent)); + parent = dget_parent(dentry); + ret = ksmbd_vfs_lock_parent(parent, dentry); + if (ret) { dput(parent); + return ret; } + + ret = inode_permission(user_ns, d_inode(parent), + MAY_EXEC | MAY_WRITE); + + inode_unlock(d_inode(parent)); + dput(parent); return ret; } -int ksmbd_vfs_query_maximal_access(struct dentry *dentry, __le32 *daccess) +int ksmbd_vfs_query_maximal_access(struct user_namespace *user_ns, + struct dentry *dentry, __le32 *daccess) { - struct dentry *parent, *child; + struct dentry *parent; int ret = 0; *daccess = cpu_to_le32(FILE_READ_ATTRIBUTES | READ_CONTROL); - if (!inode_permission(&init_user_ns, d_inode(dentry), MAY_OPEN | MAY_WRITE)) + if (!inode_permission(user_ns, d_inode(dentry), MAY_OPEN | MAY_WRITE)) *daccess |= cpu_to_le32(WRITE_DAC | WRITE_OWNER | SYNCHRONIZE | FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES | FILE_DELETE_CHILD); - if (!inode_permission(&init_user_ns, d_inode(dentry), MAY_OPEN | MAY_READ)) + if (!inode_permission(user_ns, d_inode(dentry), MAY_OPEN | MAY_READ)) *daccess |= FILE_READ_DATA_LE | FILE_READ_EA_LE; - if (!inode_permission(&init_user_ns, d_inode(dentry), MAY_OPEN | MAY_EXEC)) + if (!inode_permission(user_ns, d_inode(dentry), MAY_OPEN | MAY_EXEC)) *daccess |= FILE_EXECUTE_LE; parent = dget_parent(dentry); - inode_lock_nested(d_inode(parent), I_MUTEX_PARENT); - child = lookup_one_len(dentry->d_name.name, parent, - dentry->d_name.len); - if (IS_ERR(child)) { - ret = PTR_ERR(child); - goto out_lock; - } - - if (child != dentry) { - ret = -ESTALE; - dput(child); - goto out_lock; + ret = ksmbd_vfs_lock_parent(parent, dentry); + if (ret) { + dput(parent); + return ret; } - dput(child); - if (!inode_permission(&init_user_ns, d_inode(parent), MAY_EXEC | MAY_WRITE)) + if (!inode_permission(user_ns, d_inode(parent), MAY_EXEC | MAY_WRITE)) *daccess |= FILE_DELETE_LE; -out_lock: inode_unlock(d_inode(parent)); dput(parent); return ret; @@ -171,18 +169,19 @@ int ksmbd_vfs_create(struct ksmbd_work *work, const char *name, umode_t mode) if (IS_ERR(dentry)) { err = PTR_ERR(dentry); if (err != -ENOENT) - ksmbd_err("path create failed for %s, err %d\n", - name, err); + pr_err("path create failed for %s, err %d\n", + name, err); return err; } mode |= S_IFREG; - err = vfs_create(&init_user_ns, d_inode(path.dentry), dentry, mode, true); + err = vfs_create(mnt_user_ns(path.mnt), d_inode(path.dentry), + dentry, mode, true); if (!err) { ksmbd_vfs_inherit_owner(work, d_inode(path.dentry), d_inode(dentry)); } else { - ksmbd_err("File(%s): creation failed (err:%d)\n", name, err); + pr_err("File(%s): creation failed (err:%d)\n", name, err); } done_path_create(&path, dentry); return err; @@ -212,7 +211,8 @@ int ksmbd_vfs_mkdir(struct ksmbd_work *work, const char *name, umode_t mode) } mode |= S_IFDIR; - err = vfs_mkdir(&init_user_ns, d_inode(path.dentry), dentry, mode); + err = vfs_mkdir(mnt_user_ns(path.mnt), d_inode(path.dentry), + dentry, mode); if (err) { goto out; } else if (d_unhashed(dentry)) { @@ -236,11 +236,12 @@ int ksmbd_vfs_mkdir(struct ksmbd_work *work, const char *name, umode_t mode) out: done_path_create(&path, dentry); if (err) - ksmbd_err("mkdir(%s): creation failed (err:%d)\n", name, err); + pr_err("mkdir(%s): creation failed (err:%d)\n", name, err); return err; } -static ssize_t ksmbd_vfs_getcasexattr(struct dentry *dentry, char *attr_name, +static ssize_t ksmbd_vfs_getcasexattr(struct user_namespace *user_ns, + struct dentry *dentry, char *attr_name, int attr_name_len, char **attr_value) { char *name, *xattr_list = NULL; @@ -256,11 +257,12 @@ static ssize_t ksmbd_vfs_getcasexattr(struct dentry *dentry, char *attr_name, if (strncasecmp(attr_name, name, attr_name_len)) continue; - value_len = ksmbd_vfs_getxattr(dentry, + value_len = ksmbd_vfs_getxattr(user_ns, + dentry, name, attr_value); if (value_len < 0) - ksmbd_err("failed to get xattr in file\n"); + pr_err("failed to get xattr in file\n"); break; } @@ -278,7 +280,8 @@ static int ksmbd_vfs_stream_read(struct ksmbd_file *fp, char *buf, loff_t *pos, ksmbd_debug(VFS, "read stream data pos : %llu, count : %zd\n", *pos, count); - v_len = ksmbd_vfs_getcasexattr(fp->filp->f_path.dentry, + v_len = ksmbd_vfs_getcasexattr(file_mnt_user_ns(fp->filp), + fp->filp->f_path.dentry, fp->stream.name, fp->stream.size, &stream_buf); @@ -325,7 +328,7 @@ static int check_lock_range(struct file *filp, loff_t start, loff_t end, if (flock->fl_end >= start && end >= flock->fl_start) { if (flock->fl_type == F_RDLCK) { if (type == WRITE) { - ksmbd_err("not allow write by shared lock\n"); + pr_err("not allow write by shared lock\n"); error = 1; goto out; } @@ -333,7 +336,7 @@ static int check_lock_range(struct file *filp, loff_t start, loff_t end, /* check owner in lock */ if (flock->fl_file != filp) { error = 1; - ksmbd_err("not allow rw access by exclusive lock from other opens\n"); + pr_err("not allow rw access by exclusive lock from other opens\n"); goto out; } } @@ -356,14 +359,11 @@ out: int ksmbd_vfs_read(struct ksmbd_work *work, struct ksmbd_file *fp, size_t count, loff_t *pos) { - struct file *filp; + struct file *filp = fp->filp; ssize_t nbytes = 0; - char *rbuf; - struct inode *inode; + char *rbuf = work->aux_payload_buf; + struct inode *inode = file_inode(filp); - rbuf = work->aux_payload_buf; - filp = fp->filp; - inode = file_inode(filp); if (S_ISDIR(inode->i_mode)) return -EISDIR; @@ -372,7 +372,8 @@ int ksmbd_vfs_read(struct ksmbd_work *work, struct ksmbd_file *fp, size_t count, if (work->conn->connection_type) { if (!(fp->daccess & (FILE_READ_DATA_LE | FILE_EXECUTE_LE))) { - ksmbd_err("no right to read(%s)\n", FP_FILENAME(fp)); + pr_err("no right to read(%pd)\n", + fp->filp->f_path.dentry); return -EACCES; } } @@ -385,15 +386,15 @@ int ksmbd_vfs_read(struct ksmbd_work *work, struct ksmbd_file *fp, size_t count, ret = check_lock_range(filp, *pos, *pos + count - 1, READ); if (ret) { - ksmbd_err("unable to read due to lock\n"); + pr_err("unable to read due to lock\n"); return -EAGAIN; } } nbytes = kernel_read(filp, rbuf, count, pos); if (nbytes < 0) { - ksmbd_err("smb read failed for (%s), err = %zd\n", - fp->filename, nbytes); + pr_err("smb read failed for (%s), err = %zd\n", + fp->filename, nbytes); return nbytes; } @@ -417,12 +418,13 @@ static int ksmbd_vfs_stream_write(struct ksmbd_file *fp, char *buf, loff_t *pos, count = (*pos + count) - XATTR_SIZE_MAX; } - v_len = ksmbd_vfs_getcasexattr(fp->filp->f_path.dentry, + v_len = ksmbd_vfs_getcasexattr(file_mnt_user_ns(fp->filp), + fp->filp->f_path.dentry, fp->stream.name, fp->stream.size, &stream_buf); if ((int)v_len < 0) { - ksmbd_err("not found stream in xattr : %zd\n", v_len); + pr_err("not found stream in xattr : %zd\n", v_len); err = (int)v_len; goto out; } @@ -442,7 +444,8 @@ static int ksmbd_vfs_stream_write(struct ksmbd_file *fp, char *buf, loff_t *pos, memcpy(&stream_buf[*pos], buf, count); - err = ksmbd_vfs_setxattr(fp->filp->f_path.dentry, + err = ksmbd_vfs_setxattr(file_mnt_user_ns(fp->filp), + fp->filp->f_path.dentry, fp->stream.name, (void *)stream_buf, size, @@ -480,7 +483,8 @@ int ksmbd_vfs_write(struct ksmbd_work *work, struct ksmbd_file *fp, if (sess->conn->connection_type) { if (!(fp->daccess & FILE_WRITE_DATA_LE)) { - ksmbd_err("no right to write(%s)\n", FP_FILENAME(fp)); + pr_err("no right to write(%pd)\n", + fp->filp->f_path.dentry); err = -EACCES; goto out; } @@ -498,7 +502,7 @@ int ksmbd_vfs_write(struct ksmbd_work *work, struct ksmbd_file *fp, if (!work->tcon->posix_extensions) { err = check_lock_range(filp, *pos, *pos + count - 1, WRITE); if (err) { - ksmbd_err("unable to write due to lock\n"); + pr_err("unable to write due to lock\n"); err = -EAGAIN; goto out; } @@ -519,8 +523,8 @@ int ksmbd_vfs_write(struct ksmbd_work *work, struct ksmbd_file *fp, if (sync) { err = vfs_fsync_range(filp, offset, offset + *written, 0); if (err < 0) - ksmbd_err("fsync failed for filename = %s, err = %d\n", - FP_FILENAME(fp), err); + pr_err("fsync failed for filename = %pd, err = %d\n", + fp->filp->f_path.dentry, err); } out: @@ -541,7 +545,7 @@ int ksmbd_vfs_getattr(struct path *path, struct kstat *stat) err = vfs_getattr(path, stat, STATX_BTIME, AT_STATX_SYNC_AS_STAT); if (err) - ksmbd_err("getattr failed, err %d\n", err); + pr_err("getattr failed, err %d\n", err); return err; } @@ -559,12 +563,12 @@ int ksmbd_vfs_fsync(struct ksmbd_work *work, u64 fid, u64 p_id) fp = ksmbd_lookup_fd_slow(work, fid, p_id); if (!fp) { - ksmbd_err("failed to get filp for fid %llu\n", fid); + pr_err("failed to get filp for fid %llu\n", fid); return -ENOENT; } err = vfs_fsync(fp->filp, 0); if (err < 0) - ksmbd_err("smb fsync failed, err = %d\n", err); + pr_err("smb fsync failed, err = %d\n", err); ksmbd_fd_put(work, fp); return err; } @@ -578,7 +582,7 @@ int ksmbd_vfs_fsync(struct ksmbd_work *work, u64 fid, u64 p_id) int ksmbd_vfs_remove_file(struct ksmbd_work *work, char *name) { struct path path; - struct dentry *dentry, *parent; + struct dentry *parent; int err; int flags = 0; @@ -597,35 +601,33 @@ int ksmbd_vfs_remove_file(struct ksmbd_work *work, char *name) } parent = dget_parent(path.dentry); - inode_lock_nested(d_inode(parent), I_MUTEX_PARENT); - dentry = lookup_one_len(path.dentry->d_name.name, parent, - strlen(path.dentry->d_name.name)); - if (IS_ERR(dentry)) { - err = PTR_ERR(dentry); - ksmbd_debug(VFS, "%s: lookup failed, err %d\n", - path.dentry->d_name.name, err); - goto out_err; + err = ksmbd_vfs_lock_parent(parent, path.dentry); + if (err) { + dput(parent); + path_put(&path); + ksmbd_revert_fsids(work); + return err; } - if (!d_inode(dentry) || !d_inode(dentry)->i_nlink) { - dput(dentry); + if (!d_inode(path.dentry)->i_nlink) { err = -ENOENT; goto out_err; } - if (S_ISDIR(d_inode(dentry)->i_mode)) { - err = vfs_rmdir(&init_user_ns, d_inode(parent), dentry); + if (S_ISDIR(d_inode(path.dentry)->i_mode)) { + err = vfs_rmdir(mnt_user_ns(path.mnt), d_inode(parent), + path.dentry); if (err && err != -ENOTEMPTY) ksmbd_debug(VFS, "%s: rmdir failed, err %d\n", name, err); } else { - err = vfs_unlink(&init_user_ns, d_inode(parent), dentry, NULL); + err = vfs_unlink(mnt_user_ns(path.mnt), d_inode(parent), + path.dentry, NULL); if (err) ksmbd_debug(VFS, "%s: unlink failed, err %d\n", name, err); } - dput(dentry); out_err: inode_unlock(d_inode(parent)); dput(parent); @@ -658,8 +660,8 @@ int ksmbd_vfs_link(struct ksmbd_work *work, const char *oldname, err = kern_path(oldname, flags, &oldpath); if (err) { - ksmbd_err("cannot get linux path for %s, err = %d\n", - oldname, err); + pr_err("cannot get linux path for %s, err = %d\n", + oldname, err); goto out1; } @@ -667,17 +669,18 @@ int ksmbd_vfs_link(struct ksmbd_work *work, const char *oldname, flags | LOOKUP_REVAL); if (IS_ERR(dentry)) { err = PTR_ERR(dentry); - ksmbd_err("path create err for %s, err %d\n", newname, err); + pr_err("path create err for %s, err %d\n", newname, err); goto out2; } err = -EXDEV; if (oldpath.mnt != newpath.mnt) { - ksmbd_err("vfs_link failed err %d\n", err); + pr_err("vfs_link failed err %d\n", err); goto out3; } - err = vfs_link(oldpath.dentry, &init_user_ns, d_inode(newpath.dentry), + err = vfs_link(oldpath.dentry, mnt_user_ns(newpath.mnt), + d_inode(newpath.dentry), dentry, NULL); if (err) ksmbd_debug(VFS, "vfs_link failed err %d\n", err); @@ -691,9 +694,34 @@ out1: return err; } +static int ksmbd_validate_entry_in_use(struct dentry *src_dent) +{ + struct dentry *dst_dent; + + spin_lock(&src_dent->d_lock); + list_for_each_entry(dst_dent, &src_dent->d_subdirs, d_child) { + struct ksmbd_file *child_fp; + + if (d_really_is_negative(dst_dent)) + continue; + + child_fp = ksmbd_lookup_fd_inode(d_inode(dst_dent)); + if (child_fp) { + spin_unlock(&src_dent->d_lock); + ksmbd_debug(VFS, "Forbid rename, sub file/dir is in use\n"); + return -EACCES; + } + } + spin_unlock(&src_dent->d_lock); + + return 0; +} + static int __ksmbd_vfs_rename(struct ksmbd_work *work, + struct user_namespace *src_user_ns, struct dentry *src_dent_parent, struct dentry *src_dent, + struct user_namespace *dst_user_ns, struct dentry *dst_dent_parent, struct dentry *trap_dent, char *dst_name) @@ -702,21 +730,9 @@ static int __ksmbd_vfs_rename(struct ksmbd_work *work, int err; if (!work->tcon->posix_extensions) { - spin_lock(&src_dent->d_lock); - list_for_each_entry(dst_dent, &src_dent->d_subdirs, d_child) { - struct ksmbd_file *child_fp; - - if (d_really_is_negative(dst_dent)) - continue; - - child_fp = ksmbd_lookup_fd_inode(d_inode(dst_dent)); - if (child_fp) { - spin_unlock(&src_dent->d_lock); - ksmbd_debug(VFS, "Forbid rename, sub file/dir is in use\n"); - return -EACCES; - } - } - spin_unlock(&src_dent->d_lock); + err = ksmbd_validate_entry_in_use(src_dent); + if (err) + return err; } if (d_really_is_negative(src_dent_parent)) @@ -734,24 +750,24 @@ static int __ksmbd_vfs_rename(struct ksmbd_work *work, dst_dent = lookup_one_len(dst_name, dst_dent_parent, strlen(dst_name)); err = PTR_ERR(dst_dent); if (IS_ERR(dst_dent)) { - ksmbd_err("lookup failed %s [%d]\n", dst_name, err); + pr_err("lookup failed %s [%d]\n", dst_name, err); goto out; } err = -ENOTEMPTY; if (dst_dent != trap_dent && !d_really_is_positive(dst_dent)) { struct renamedata rd = { - .old_mnt_userns = &init_user_ns, + .old_mnt_userns = src_user_ns, .old_dir = d_inode(src_dent_parent), .old_dentry = src_dent, - .new_mnt_userns = &init_user_ns, + .new_mnt_userns = dst_user_ns, .new_dir = d_inode(dst_dent_parent), .new_dentry = dst_dent, }; err = vfs_rename(&rd); } if (err) - ksmbd_err("vfs_rename failed err %d\n", err); + pr_err("vfs_rename failed err %d\n", err); if (dst_dent) dput(dst_dent); out: @@ -806,8 +822,10 @@ int ksmbd_vfs_fp_rename(struct ksmbd_work *work, struct ksmbd_file *fp, dput(src_child); err = __ksmbd_vfs_rename(work, + file_mnt_user_ns(fp->filp), src_dent_parent, src_dent, + mnt_user_ns(dst_path.mnt), dst_dent_parent, trap_dent, dst_name); @@ -839,14 +857,14 @@ int ksmbd_vfs_truncate(struct ksmbd_work *work, const char *name, if (name) { err = kern_path(name, 0, &path); if (err) { - ksmbd_err("cannot get linux path for %s, err %d\n", - name, err); + pr_err("cannot get linux path for %s, err %d\n", + name, err); return err; } err = vfs_truncate(&path, size); if (err) - ksmbd_err("truncate failed for %s err %d\n", - name, err); + pr_err("truncate failed for %s err %d\n", + name, err); path_put(&path); } else { struct file *filp; @@ -868,15 +886,15 @@ int ksmbd_vfs_truncate(struct ksmbd_work *work, const char *name, } if (err) { - ksmbd_err("failed due to lock\n"); + pr_err("failed due to lock\n"); return -EAGAIN; } } err = vfs_truncate(&filp->f_path, size); if (err) - ksmbd_err("truncate failed for filename : %s err %d\n", - fp->filename, err); + pr_err("truncate failed for filename : %s err %d\n", + fp->filename, err); } return err; @@ -914,27 +932,30 @@ ssize_t ksmbd_vfs_listxattr(struct dentry *dentry, char **list) return size; } -static ssize_t ksmbd_vfs_xattr_len(struct dentry *dentry, char *xattr_name) +static ssize_t ksmbd_vfs_xattr_len(struct user_namespace *user_ns, + struct dentry *dentry, char *xattr_name) { - return vfs_getxattr(&init_user_ns, dentry, xattr_name, NULL, 0); + return vfs_getxattr(user_ns, dentry, xattr_name, NULL, 0); } /** * ksmbd_vfs_getxattr() - vfs helper for smb get extended attributes value + * @user_ns: user namespace * @dentry: dentry of file for getting xattrs * @xattr_name: name of xattr name to query * @xattr_buf: destination buffer xattr value * * Return: read xattr value length on success, otherwise error */ -ssize_t ksmbd_vfs_getxattr(struct dentry *dentry, char *xattr_name, - char **xattr_buf) +ssize_t ksmbd_vfs_getxattr(struct user_namespace *user_ns, + struct dentry *dentry, + char *xattr_name, char **xattr_buf) { ssize_t xattr_len; char *buf; *xattr_buf = NULL; - xattr_len = ksmbd_vfs_xattr_len(dentry, xattr_name); + xattr_len = ksmbd_vfs_xattr_len(user_ns, dentry, xattr_name); if (xattr_len < 0) return xattr_len; @@ -942,7 +963,7 @@ ssize_t ksmbd_vfs_getxattr(struct dentry *dentry, char *xattr_name, if (!buf) return -ENOMEM; - xattr_len = vfs_getxattr(&init_user_ns, dentry, xattr_name, + xattr_len = vfs_getxattr(user_ns, dentry, xattr_name, (void *)buf, xattr_len); if (xattr_len > 0) *xattr_buf = buf; @@ -953,6 +974,7 @@ ssize_t ksmbd_vfs_getxattr(struct dentry *dentry, char *xattr_name, /** * ksmbd_vfs_setxattr() - vfs helper for smb set extended attributes value + * @user_ns: user namespace * @dentry: dentry to set XATTR at * @name: xattr name for setxattr * @value: xattr value to set @@ -961,12 +983,14 @@ ssize_t ksmbd_vfs_getxattr(struct dentry *dentry, char *xattr_name, * * Return: 0 on success, otherwise error */ -int ksmbd_vfs_setxattr(struct dentry *dentry, const char *attr_name, +int ksmbd_vfs_setxattr(struct user_namespace *user_ns, + struct dentry *dentry, const char *attr_name, const void *attr_value, size_t attr_size, int flags) { int err; - err = vfs_setxattr(&init_user_ns, dentry, + err = vfs_setxattr(user_ns, + dentry, attr_name, attr_value, attr_size, @@ -1004,32 +1028,6 @@ void ksmbd_vfs_set_fadvise(struct file *filp, __le32 option) } } -/** - * ksmbd_vfs_lock() - vfs helper for smb file locking - * @filp: the file to apply the lock to - * @cmd: type of locking operation (F_SETLK, F_GETLK, etc.) - * @flock: The lock to be applied - * - * Return: 0 on success, otherwise error - */ -int ksmbd_vfs_lock(struct file *filp, int cmd, struct file_lock *flock) -{ - ksmbd_debug(VFS, "calling vfs_lock_file\n"); - return vfs_lock_file(filp, cmd, flock, NULL); -} - -int ksmbd_vfs_readdir(struct file *file, struct ksmbd_readdir_data *rdata) -{ - return iterate_dir(file, &rdata->ctx); -} - -int ksmbd_vfs_alloc_size(struct ksmbd_work *work, struct ksmbd_file *fp, - loff_t len) -{ - smb_break_all_levII_oplock(work, fp, 1); - return vfs_fallocate(fp->filp, FALLOC_FL_KEEP_SIZE, 0, len); -} - int ksmbd_vfs_zero_data(struct ksmbd_work *work, struct ksmbd_file *fp, loff_t off, loff_t len) { @@ -1047,7 +1045,7 @@ int ksmbd_vfs_fqar_lseek(struct ksmbd_file *fp, loff_t start, loff_t length, int in_count, int *out_count) { struct file *f = fp->filp; - struct inode *inode = FP_INODE(fp); + struct inode *inode = file_inode(fp->filp); loff_t maxbytes = (u64)inode->i_sb->s_maxbytes, end; loff_t extent_start, extent_end; int ret = 0; @@ -1099,37 +1097,27 @@ int ksmbd_vfs_fqar_lseek(struct ksmbd_file *fp, loff_t start, loff_t length, return ret; } -int ksmbd_vfs_remove_xattr(struct dentry *dentry, char *attr_name) +int ksmbd_vfs_remove_xattr(struct user_namespace *user_ns, + struct dentry *dentry, char *attr_name) { - return vfs_removexattr(&init_user_ns, dentry, attr_name); + return vfs_removexattr(user_ns, dentry, attr_name); } -int ksmbd_vfs_unlink(struct dentry *dir, struct dentry *dentry) +int ksmbd_vfs_unlink(struct user_namespace *user_ns, + struct dentry *dir, struct dentry *dentry) { - struct dentry *child; int err = 0; - inode_lock_nested(d_inode(dir), I_MUTEX_PARENT); + err = ksmbd_vfs_lock_parent(dir, dentry); + if (err) + return err; dget(dentry); - child = lookup_one_len(dentry->d_name.name, dir, dentry->d_name.len); - if (IS_ERR(child)) { - err = PTR_ERR(child); - goto out; - } - - if (child != dentry) { - err = -ESTALE; - dput(child); - goto out; - } - dput(child); if (S_ISDIR(d_inode(dentry)->i_mode)) - err = vfs_rmdir(&init_user_ns, d_inode(dir), dentry); + err = vfs_rmdir(user_ns, d_inode(dir), dentry); else - err = vfs_unlink(&init_user_ns, d_inode(dir), dentry, NULL); + err = vfs_unlink(user_ns, d_inode(dir), dentry, NULL); -out: dput(dentry); inode_unlock(d_inode(dir)); if (err) @@ -1138,59 +1126,6 @@ out: return err; } -/* - * ksmbd_vfs_get_logical_sector_size() - get logical sector size from inode - * @inode: inode - * - * Return: logical sector size - */ -unsigned short ksmbd_vfs_logical_sector_size(struct inode *inode) -{ - struct request_queue *q; - unsigned short ret_val = 512; - - if (!inode->i_sb->s_bdev) - return ret_val; - - q = inode->i_sb->s_bdev->bd_disk->queue; - - if (q && q->limits.logical_block_size) - ret_val = q->limits.logical_block_size; - - return ret_val; -} - -/* - * ksmbd_vfs_get_smb2_sector_size() - get fs sector sizes - * @inode: inode - * @fs_ss: fs sector size struct - */ -void ksmbd_vfs_smb2_sector_size(struct inode *inode, - struct ksmbd_fs_sector_size *fs_ss) -{ - struct request_queue *q; - - fs_ss->logical_sector_size = 512; - fs_ss->physical_sector_size = 512; - fs_ss->optimal_io_size = 512; - - if (!inode->i_sb->s_bdev) - return; - - q = inode->i_sb->s_bdev->bd_disk->queue; - - if (q) { - if (q->limits.logical_block_size) - fs_ss->logical_sector_size = - q->limits.logical_block_size; - if (q->limits.physical_block_size) - fs_ss->physical_sector_size = - q->limits.physical_block_size; - if (q->limits.io_opt) - fs_ss->optimal_io_size = q->limits.io_opt; - } -} - static int __dir_empty(struct dir_context *ctx, const char *name, int namlen, loff_t offset, u64 ino, unsigned int d_type) { @@ -1220,7 +1155,7 @@ int ksmbd_vfs_empty_dir(struct ksmbd_file *fp) set_ctx_actor(&readdir_data.ctx, __dir_empty); readdir_data.dirent_count = 0; - err = ksmbd_vfs_readdir(fp->filp, &readdir_data); + err = iterate_dir(fp->filp, &readdir_data.ctx); if (readdir_data.dirent_count > 2) err = -ENOTEMPTY; else @@ -1270,7 +1205,7 @@ static int ksmbd_vfs_lookup_in_dir(struct path *dir, char *name, size_t namelen) if (IS_ERR(dfilp)) return PTR_ERR(dfilp); - ret = ksmbd_vfs_readdir(dfilp, &readdir_data); + ret = iterate_dir(dfilp, &readdir_data.ctx); if (readdir_data.dirent_count > 0) ret = 0; fput(dfilp); @@ -1355,7 +1290,8 @@ out: return err; } -int ksmbd_vfs_remove_acl_xattrs(struct dentry *dentry) +int ksmbd_vfs_remove_acl_xattrs(struct user_namespace *user_ns, + struct dentry *dentry) { char *name, *xattr_list = NULL; ssize_t xattr_list_len; @@ -1377,7 +1313,7 @@ int ksmbd_vfs_remove_acl_xattrs(struct dentry *dentry) sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1) || !strncmp(name, XATTR_NAME_POSIX_ACL_DEFAULT, sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1)) { - err = ksmbd_vfs_remove_xattr(dentry, name); + err = ksmbd_vfs_remove_xattr(user_ns, dentry, name); if (err) ksmbd_debug(SMB, "remove acl xattr failed : %s\n", name); @@ -1388,7 +1324,8 @@ out: return err; } -int ksmbd_vfs_remove_sd_xattrs(struct dentry *dentry) +int ksmbd_vfs_remove_sd_xattrs(struct user_namespace *user_ns, + struct dentry *dentry) { char *name, *xattr_list = NULL; ssize_t xattr_list_len; @@ -1407,7 +1344,7 @@ int ksmbd_vfs_remove_sd_xattrs(struct dentry *dentry) ksmbd_debug(SMB, "%s, len %zd\n", name, strlen(name)); if (!strncmp(name, XATTR_NAME_SD, XATTR_NAME_SD_LEN)) { - err = ksmbd_vfs_remove_xattr(dentry, name); + err = ksmbd_vfs_remove_xattr(user_ns, dentry, name); if (err) ksmbd_debug(SMB, "remove xattr failed : %s\n", name); } @@ -1417,7 +1354,8 @@ out: return err; } -static struct xattr_smb_acl *ksmbd_vfs_make_xattr_posix_acl(struct inode *inode, +static struct xattr_smb_acl *ksmbd_vfs_make_xattr_posix_acl(struct user_namespace *user_ns, + struct inode *inode, int acl_type) { struct xattr_smb_acl *smb_acl = NULL; @@ -1426,7 +1364,7 @@ static struct xattr_smb_acl *ksmbd_vfs_make_xattr_posix_acl(struct inode *inode, struct xattr_acl_entry *xa_entry; int i; - posix_acls = ksmbd_vfs_get_acl(inode, acl_type); + posix_acls = get_acl(inode, acl_type); if (!posix_acls) return NULL; @@ -1443,14 +1381,14 @@ static struct xattr_smb_acl *ksmbd_vfs_make_xattr_posix_acl(struct inode *inode, switch (pa_entry->e_tag) { case ACL_USER: xa_entry->type = SMB_ACL_USER; - xa_entry->uid = from_kuid(&init_user_ns, pa_entry->e_uid); + xa_entry->uid = from_kuid(user_ns, pa_entry->e_uid); break; case ACL_USER_OBJ: xa_entry->type = SMB_ACL_USER_OBJ; break; case ACL_GROUP: xa_entry->type = SMB_ACL_GROUP; - xa_entry->gid = from_kgid(&init_user_ns, pa_entry->e_gid); + xa_entry->gid = from_kgid(user_ns, pa_entry->e_gid); break; case ACL_GROUP_OBJ: xa_entry->type = SMB_ACL_GROUP_OBJ; @@ -1462,7 +1400,7 @@ static struct xattr_smb_acl *ksmbd_vfs_make_xattr_posix_acl(struct inode *inode, xa_entry->type = SMB_ACL_MASK; break; default: - ksmbd_err("unknown type : 0x%x\n", pa_entry->e_tag); + pr_err("unknown type : 0x%x\n", pa_entry->e_tag); goto out; } @@ -1478,7 +1416,9 @@ out: return smb_acl; } -int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn, struct dentry *dentry, +int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn, + struct user_namespace *user_ns, + struct dentry *dentry, struct smb_ntsd *pntsd, int len) { int rc; @@ -1506,38 +1446,41 @@ int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn, struct dentry *dentry, rc = ksmbd_gen_sd_hash(conn, acl.sd_buf, acl.sd_size, acl.hash); if (rc) { - ksmbd_err("failed to generate hash for ndr acl\n"); + pr_err("failed to generate hash for ndr acl\n"); return rc; } - smb_acl = ksmbd_vfs_make_xattr_posix_acl(inode, ACL_TYPE_ACCESS); + smb_acl = ksmbd_vfs_make_xattr_posix_acl(user_ns, inode, + ACL_TYPE_ACCESS); if (S_ISDIR(inode->i_mode)) - def_smb_acl = ksmbd_vfs_make_xattr_posix_acl(inode, + def_smb_acl = ksmbd_vfs_make_xattr_posix_acl(user_ns, inode, ACL_TYPE_DEFAULT); - rc = ndr_encode_posix_acl(&acl_ndr, inode, smb_acl, def_smb_acl); + rc = ndr_encode_posix_acl(&acl_ndr, user_ns, inode, + smb_acl, def_smb_acl); if (rc) { - ksmbd_err("failed to encode ndr to posix acl\n"); + pr_err("failed to encode ndr to posix acl\n"); goto out; } rc = ksmbd_gen_sd_hash(conn, acl_ndr.data, acl_ndr.offset, acl.posix_acl_hash); if (rc) { - ksmbd_err("failed to generate hash for ndr acl\n"); + pr_err("failed to generate hash for ndr acl\n"); goto out; } rc = ndr_encode_v4_ntacl(&sd_ndr, &acl); if (rc) { - ksmbd_err("failed to encode ndr to posix acl\n"); + pr_err("failed to encode ndr to posix acl\n"); goto out; } - rc = ksmbd_vfs_setxattr(dentry, XATTR_NAME_SD, sd_ndr.data, + rc = ksmbd_vfs_setxattr(user_ns, dentry, + XATTR_NAME_SD, sd_ndr.data, sd_ndr.offset, 0); if (rc < 0) - ksmbd_err("Failed to store XATTR ntacl :%d\n", rc); + pr_err("Failed to store XATTR ntacl :%d\n", rc); kfree(sd_ndr.data); out: @@ -1547,13 +1490,15 @@ out: return rc; } -int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn, struct dentry *dentry, +int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn, + struct user_namespace *user_ns, + struct dentry *dentry, struct smb_ntsd **pntsd) { int rc; struct ndr n; - rc = ksmbd_vfs_getxattr(dentry, XATTR_NAME_SD, &n.data); + rc = ksmbd_vfs_getxattr(user_ns, dentry, XATTR_NAME_SD, &n.data); if (rc > 0) { struct inode *inode = d_inode(dentry); struct ndr acl_ndr = {0}; @@ -1566,27 +1511,29 @@ int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn, struct dentry *dentry, if (rc) return rc; - smb_acl = ksmbd_vfs_make_xattr_posix_acl(inode, + smb_acl = ksmbd_vfs_make_xattr_posix_acl(user_ns, inode, ACL_TYPE_ACCESS); if (S_ISDIR(inode->i_mode)) - def_smb_acl = ksmbd_vfs_make_xattr_posix_acl(inode, + def_smb_acl = ksmbd_vfs_make_xattr_posix_acl(user_ns, + inode, ACL_TYPE_DEFAULT); - rc = ndr_encode_posix_acl(&acl_ndr, inode, smb_acl, def_smb_acl); + rc = ndr_encode_posix_acl(&acl_ndr, user_ns, inode, + smb_acl, def_smb_acl); if (rc) { - ksmbd_err("failed to encode ndr to posix acl\n"); + pr_err("failed to encode ndr to posix acl\n"); goto out; } rc = ksmbd_gen_sd_hash(conn, acl_ndr.data, acl_ndr.offset, cmp_hash); if (rc) { - ksmbd_err("failed to generate hash for ndr acl\n"); + pr_err("failed to generate hash for ndr acl\n"); goto out; } if (memcmp(cmp_hash, acl.posix_acl_hash, XATTR_SD_HASH_SIZE)) { - ksmbd_err("hash value diff\n"); + pr_err("hash value diff\n"); rc = -EINVAL; goto out; } @@ -1610,7 +1557,8 @@ out: return rc; } -int ksmbd_vfs_set_dos_attrib_xattr(struct dentry *dentry, +int ksmbd_vfs_set_dos_attrib_xattr(struct user_namespace *user_ns, + struct dentry *dentry, struct xattr_dos_attrib *da) { struct ndr n; @@ -1620,7 +1568,7 @@ int ksmbd_vfs_set_dos_attrib_xattr(struct dentry *dentry, if (err) return err; - err = ksmbd_vfs_setxattr(dentry, XATTR_NAME_DOS_ATTRIBUTE, + err = ksmbd_vfs_setxattr(user_ns, dentry, XATTR_NAME_DOS_ATTRIBUTE, (void *)n.data, n.offset, 0); if (err) ksmbd_debug(SMB, "failed to store dos attribute in xattr\n"); @@ -1629,13 +1577,14 @@ int ksmbd_vfs_set_dos_attrib_xattr(struct dentry *dentry, return err; } -int ksmbd_vfs_get_dos_attrib_xattr(struct dentry *dentry, +int ksmbd_vfs_get_dos_attrib_xattr(struct user_namespace *user_ns, + struct dentry *dentry, struct xattr_dos_attrib *da) { struct ndr n; int err; - err = ksmbd_vfs_getxattr(dentry, XATTR_NAME_DOS_ATTRIBUTE, + err = ksmbd_vfs_getxattr(user_ns, dentry, XATTR_NAME_DOS_ATTRIBUTE, (char **)&n.data); if (err > 0) { n.length = err; @@ -1649,34 +1598,6 @@ int ksmbd_vfs_get_dos_attrib_xattr(struct dentry *dentry, return err; } -struct posix_acl *ksmbd_vfs_posix_acl_alloc(int count, gfp_t flags) -{ -#if IS_ENABLED(CONFIG_FS_POSIX_ACL) - return posix_acl_alloc(count, flags); -#else - return NULL; -#endif -} - -struct posix_acl *ksmbd_vfs_get_acl(struct inode *inode, int type) -{ -#if IS_ENABLED(CONFIG_FS_POSIX_ACL) - return get_acl(inode, type); -#else - return NULL; -#endif -} - -int ksmbd_vfs_set_posix_acl(struct inode *inode, int type, - struct posix_acl *acl) -{ -#if IS_ENABLED(CONFIG_FS_POSIX_ACL) - return set_posix_acl(&init_user_ns, inode, type, acl); -#else - return -EOPNOTSUPP; -#endif -} - /** * ksmbd_vfs_init_kstat() - convert unix stat information to smb stat format * @p: destination buffer @@ -1709,13 +1630,15 @@ void *ksmbd_vfs_init_kstat(char **p, struct ksmbd_kstat *ksmbd_kstat) return info; } -int ksmbd_vfs_fill_dentry_attrs(struct ksmbd_work *work, struct dentry *dentry, +int ksmbd_vfs_fill_dentry_attrs(struct ksmbd_work *work, + struct user_namespace *user_ns, + struct dentry *dentry, struct ksmbd_kstat *ksmbd_kstat) { u64 time; int rc; - generic_fillattr(&init_user_ns, d_inode(dentry), ksmbd_kstat->kstat); + generic_fillattr(user_ns, d_inode(dentry), ksmbd_kstat->kstat); time = ksmbd_UnixTimeToNT(ksmbd_kstat->kstat->ctime); ksmbd_kstat->create_time = time; @@ -1733,7 +1656,7 @@ int ksmbd_vfs_fill_dentry_attrs(struct ksmbd_work *work, struct dentry *dentry, KSMBD_SHARE_FLAG_STORE_DOS_ATTRS)) { struct xattr_dos_attrib da; - rc = ksmbd_vfs_get_dos_attrib_xattr(dentry, &da); + rc = ksmbd_vfs_get_dos_attrib_xattr(user_ns, dentry, &da); if (rc > 0) { ksmbd_kstat->file_attributes = cpu_to_le32(da.attr); ksmbd_kstat->create_time = da.create_time; @@ -1745,7 +1668,8 @@ int ksmbd_vfs_fill_dentry_attrs(struct ksmbd_work *work, struct dentry *dentry, return 0; } -ssize_t ksmbd_vfs_casexattr_len(struct dentry *dentry, char *attr_name, +ssize_t ksmbd_vfs_casexattr_len(struct user_namespace *user_ns, + struct dentry *dentry, char *attr_name, int attr_name_len) { char *name, *xattr_list = NULL; @@ -1761,7 +1685,7 @@ ssize_t ksmbd_vfs_casexattr_len(struct dentry *dentry, char *attr_name, if (strncasecmp(attr_name, name, attr_name_len)) continue; - value_len = ksmbd_vfs_xattr_len(dentry, name); + value_len = ksmbd_vfs_xattr_len(user_ns, dentry, name); break; } @@ -1806,52 +1730,6 @@ int ksmbd_vfs_xattr_stream_name(char *stream_name, char **xattr_stream_name, return 0; } -int ksmbd_vfs_copy_file_range(struct file *file_in, loff_t pos_in, - struct file *file_out, loff_t pos_out, size_t len) -{ - struct inode *inode_in = file_inode(file_in); - struct inode *inode_out = file_inode(file_out); - int ret; - - ret = vfs_copy_file_range(file_in, pos_in, file_out, pos_out, len, 0); - /* do splice for the copy between different file systems */ - if (ret != -EXDEV) - return ret; - - if (S_ISDIR(inode_in->i_mode) || S_ISDIR(inode_out->i_mode)) - return -EISDIR; - if (!S_ISREG(inode_in->i_mode) || !S_ISREG(inode_out->i_mode)) - return -EINVAL; - - if (!(file_in->f_mode & FMODE_READ) || - !(file_out->f_mode & FMODE_WRITE)) - return -EBADF; - - if (len == 0) - return 0; - - file_start_write(file_out); - - /* - * skip the verification of the range of data. it will be done - * in do_splice_direct - */ - ret = do_splice_direct(file_in, &pos_in, file_out, &pos_out, - len > MAX_RW_COUNT ? MAX_RW_COUNT : len, 0); - if (ret > 0) { - fsnotify_access(file_in); - add_rchar(current, ret); - fsnotify_modify(file_out); - add_wchar(current, ret); - } - - inc_syscr(current); - inc_syscw(current); - - file_end_write(file_out); - return ret; -} - int ksmbd_vfs_copy_file_ranges(struct ksmbd_work *work, struct ksmbd_file *src_fp, struct ksmbd_file *dst_fp, @@ -1871,11 +1749,11 @@ int ksmbd_vfs_copy_file_ranges(struct ksmbd_work *work, *total_size_written = 0; if (!(src_fp->daccess & (FILE_READ_DATA_LE | FILE_EXECUTE_LE))) { - ksmbd_err("no right to read(%s)\n", FP_FILENAME(src_fp)); + pr_err("no right to read(%pd)\n", src_fp->filp->f_path.dentry); return -EACCES; } if (!(dst_fp->daccess & (FILE_WRITE_DATA_LE | FILE_APPEND_DATA_LE))) { - ksmbd_err("no right to write(%s)\n", FP_FILENAME(dst_fp)); + pr_err("no right to write(%pd)\n", dst_fp->filp->f_path.dentry); return -EACCES; } @@ -1909,8 +1787,8 @@ int ksmbd_vfs_copy_file_ranges(struct ksmbd_work *work, if (src_off + len > src_file_size) return -E2BIG; - ret = ksmbd_vfs_copy_file_range(src_fp->filp, src_off, - dst_fp->filp, dst_off, len); + ret = vfs_copy_file_range(src_fp->filp, src_off, + dst_fp->filp, dst_off, len, 0); if (ret < 0) return ret; @@ -1937,7 +1815,8 @@ void ksmbd_vfs_posix_lock_unblock(struct file_lock *flock) locks_delete_block(flock); } -int ksmbd_vfs_set_init_posix_acl(struct inode *inode) +int ksmbd_vfs_set_init_posix_acl(struct user_namespace *user_ns, + struct inode *inode) { struct posix_acl_state acl_state; struct posix_acl *acls; @@ -1960,19 +1839,20 @@ int ksmbd_vfs_set_init_posix_acl(struct inode *inode) acl_state.group.allow; acl_state.mask.allow = 0x07; - acls = ksmbd_vfs_posix_acl_alloc(6, GFP_KERNEL); + acls = posix_acl_alloc(6, GFP_KERNEL); if (!acls) { free_acl_state(&acl_state); return -ENOMEM; } posix_state_to_acl(&acl_state, acls->a_entries); - rc = ksmbd_vfs_set_posix_acl(inode, ACL_TYPE_ACCESS, acls); + rc = set_posix_acl(user_ns, inode, ACL_TYPE_ACCESS, acls); if (rc < 0) ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n", rc); else if (S_ISDIR(inode->i_mode)) { posix_state_to_acl(&acl_state, acls->a_entries); - rc = ksmbd_vfs_set_posix_acl(inode, ACL_TYPE_DEFAULT, acls); + rc = set_posix_acl(user_ns, inode, ACL_TYPE_DEFAULT, + acls); if (rc < 0) ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_DEFAULT) failed, rc : %d\n", rc); @@ -1982,13 +1862,14 @@ int ksmbd_vfs_set_init_posix_acl(struct inode *inode) return rc; } -int ksmbd_vfs_inherit_posix_acl(struct inode *inode, struct inode *parent_inode) +int ksmbd_vfs_inherit_posix_acl(struct user_namespace *user_ns, + struct inode *inode, struct inode *parent_inode) { struct posix_acl *acls; struct posix_acl_entry *pace; int rc, i; - acls = ksmbd_vfs_get_acl(parent_inode, ACL_TYPE_DEFAULT); + acls = get_acl(parent_inode, ACL_TYPE_DEFAULT); if (!acls) return -ENOENT; pace = acls->a_entries; @@ -2000,12 +1881,13 @@ int ksmbd_vfs_inherit_posix_acl(struct inode *inode, struct inode *parent_inode) } } - rc = ksmbd_vfs_set_posix_acl(inode, ACL_TYPE_ACCESS, acls); + rc = set_posix_acl(user_ns, inode, ACL_TYPE_ACCESS, acls); if (rc < 0) ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n", rc); if (S_ISDIR(inode->i_mode)) { - rc = ksmbd_vfs_set_posix_acl(inode, ACL_TYPE_DEFAULT, acls); + rc = set_posix_acl(user_ns, inode, ACL_TYPE_DEFAULT, + acls); if (rc < 0) ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_DEFAULT) failed, rc : %d\n", rc); diff --git a/fs/cifsd/vfs.h b/fs/ksmbd/vfs.h index 5db1e9e2a754..b255f90acf8f 100644 --- a/fs/cifsd/vfs.h +++ b/fs/ksmbd/vfs.h @@ -14,93 +14,16 @@ #include <linux/posix_acl.h> #include "smbacl.h" +#include "xattr.h" -/* STREAM XATTR PREFIX */ -#define STREAM_PREFIX "DosStream." -#define STREAM_PREFIX_LEN (sizeof(STREAM_PREFIX) - 1) -#define XATTR_NAME_STREAM (XATTR_USER_PREFIX STREAM_PREFIX) -#define XATTR_NAME_STREAM_LEN (sizeof(XATTR_NAME_STREAM) - 1) - -enum { - XATTR_DOSINFO_ATTRIB = 0x00000001, - XATTR_DOSINFO_EA_SIZE = 0x00000002, - XATTR_DOSINFO_SIZE = 0x00000004, - XATTR_DOSINFO_ALLOC_SIZE = 0x00000008, - XATTR_DOSINFO_CREATE_TIME = 0x00000010, - XATTR_DOSINFO_CHANGE_TIME = 0x00000020, - XATTR_DOSINFO_ITIME = 0x00000040 -}; - -struct xattr_dos_attrib { - __u16 version; - __u32 flags; - __u32 attr; - __u32 ea_size; - __u64 size; - __u64 alloc_size; - __u64 create_time; - __u64 change_time; - __u64 itime; -}; - -/* DOS ATTRIBUITE XATTR PREFIX */ -#define DOS_ATTRIBUTE_PREFIX "DOSATTRIB" -#define DOS_ATTRIBUTE_PREFIX_LEN (sizeof(DOS_ATTRIBUTE_PREFIX) - 1) -#define XATTR_NAME_DOS_ATTRIBUTE \ - (XATTR_USER_PREFIX DOS_ATTRIBUTE_PREFIX) -#define XATTR_NAME_DOS_ATTRIBUTE_LEN \ - (sizeof(XATTR_USER_PREFIX DOS_ATTRIBUTE_PREFIX) - 1) - -#define XATTR_SD_HASH_TYPE_SHA256 0x1 -#define XATTR_SD_HASH_SIZE 64 - -#define SMB_ACL_READ 4 -#define SMB_ACL_WRITE 2 -#define SMB_ACL_EXECUTE 1 - +/* + * Enumeration for stream type. + */ enum { - SMB_ACL_TAG_INVALID = 0, - SMB_ACL_USER, - SMB_ACL_USER_OBJ, - SMB_ACL_GROUP, - SMB_ACL_GROUP_OBJ, - SMB_ACL_OTHER, - SMB_ACL_MASK -}; - -struct xattr_acl_entry { - int type; - uid_t uid; - gid_t gid; - mode_t perm; -}; - -struct xattr_smb_acl { - int count; - int next; - struct xattr_acl_entry entries[0]; + DATA_STREAM = 1, /* type $DATA */ + DIR_STREAM /* type $INDEX_ALLOCATION */ }; -struct xattr_ntacl { - __u16 version; - void *sd_buf; - __u32 sd_size; - __u16 hash_type; - __u8 desc[10]; - __u16 desc_len; - __u64 current_time; - __u8 hash[XATTR_SD_HASH_SIZE]; - __u8 posix_acl_hash[XATTR_SD_HASH_SIZE]; -}; - -/* SECURITY DESCRIPTOR XATTR PREFIX */ -#define SD_PREFIX "NTACL" -#define SD_PREFIX_LEN (sizeof(SD_PREFIX) - 1) -#define XATTR_NAME_SD \ - (XATTR_SECURITY_PREFIX SD_PREFIX) -#define XATTR_NAME_SD_LEN \ - (sizeof(XATTR_SECURITY_PREFIX SD_PREFIX) - 1) - /* CreateOptions */ /* Flag is set, it must not be a file , valid for directory only */ #define FILE_DIRECTORY_FILE_LE cpu_to_le32(0x00000001) @@ -184,15 +107,10 @@ struct ksmbd_kstat { __le32 file_attributes; }; -struct ksmbd_fs_sector_size { - unsigned short logical_sector_size; - unsigned int physical_sector_size; - unsigned int optimal_io_size; -}; - -int ksmbd_vfs_inode_permission(struct dentry *dentry, int acc_mode, - bool delete); -int ksmbd_vfs_query_maximal_access(struct dentry *dentry, __le32 *daccess); +int ksmbd_vfs_lock_parent(struct dentry *parent, struct dentry *child); +int ksmbd_vfs_may_delete(struct user_namespace *user_ns, struct dentry *dentry); +int ksmbd_vfs_query_maximal_access(struct user_namespace *user_ns, + struct dentry *dentry, __le32 *daccess); int ksmbd_vfs_create(struct ksmbd_work *work, const char *name, umode_t mode); int ksmbd_vfs_mkdir(struct ksmbd_work *work, const char *name, umode_t mode); int ksmbd_vfs_read(struct ksmbd_work *work, struct ksmbd_file *fp, @@ -218,58 +136,62 @@ int ksmbd_vfs_copy_file_ranges(struct ksmbd_work *work, unsigned int *chunk_count_written, unsigned int *chunk_size_written, loff_t *total_size_written); -int ksmbd_vfs_copy_file_range(struct file *file_in, loff_t pos_in, - struct file *file_out, loff_t pos_out, - size_t len); ssize_t ksmbd_vfs_listxattr(struct dentry *dentry, char **list); -ssize_t ksmbd_vfs_getxattr(struct dentry *dentry, char *xattr_name, +ssize_t ksmbd_vfs_getxattr(struct user_namespace *user_ns, + struct dentry *dentry, + char *xattr_name, char **xattr_buf); -ssize_t ksmbd_vfs_casexattr_len(struct dentry *dentry, char *attr_name, +ssize_t ksmbd_vfs_casexattr_len(struct user_namespace *user_ns, + struct dentry *dentry, char *attr_name, int attr_name_len); -int ksmbd_vfs_setxattr(struct dentry *dentry, const char *attr_name, +int ksmbd_vfs_setxattr(struct user_namespace *user_ns, + struct dentry *dentry, const char *attr_name, const void *attr_value, size_t attr_size, int flags); int ksmbd_vfs_xattr_stream_name(char *stream_name, char **xattr_stream_name, size_t *xattr_stream_name_size, int s_type); -int ksmbd_vfs_remove_xattr(struct dentry *dentry, char *attr_name); +int ksmbd_vfs_remove_xattr(struct user_namespace *user_ns, + struct dentry *dentry, char *attr_name); int ksmbd_vfs_kern_path(char *name, unsigned int flags, struct path *path, bool caseless); int ksmbd_vfs_empty_dir(struct ksmbd_file *fp); void ksmbd_vfs_set_fadvise(struct file *filp, __le32 option); -int ksmbd_vfs_lock(struct file *filp, int cmd, struct file_lock *flock); -int ksmbd_vfs_readdir(struct file *file, struct ksmbd_readdir_data *rdata); -int ksmbd_vfs_alloc_size(struct ksmbd_work *work, struct ksmbd_file *fp, - loff_t len); int ksmbd_vfs_zero_data(struct ksmbd_work *work, struct ksmbd_file *fp, loff_t off, loff_t len); struct file_allocated_range_buffer; int ksmbd_vfs_fqar_lseek(struct ksmbd_file *fp, loff_t start, loff_t length, struct file_allocated_range_buffer *ranges, int in_count, int *out_count); -int ksmbd_vfs_unlink(struct dentry *dir, struct dentry *dentry); -unsigned short ksmbd_vfs_logical_sector_size(struct inode *inode); -void ksmbd_vfs_smb2_sector_size(struct inode *inode, - struct ksmbd_fs_sector_size *fs_ss); +int ksmbd_vfs_unlink(struct user_namespace *user_ns, + struct dentry *dir, struct dentry *dentry); void *ksmbd_vfs_init_kstat(char **p, struct ksmbd_kstat *ksmbd_kstat); -int ksmbd_vfs_fill_dentry_attrs(struct ksmbd_work *work, struct dentry *dentry, +int ksmbd_vfs_fill_dentry_attrs(struct ksmbd_work *work, + struct user_namespace *user_ns, + struct dentry *dentry, struct ksmbd_kstat *ksmbd_kstat); int ksmbd_vfs_posix_lock_wait(struct file_lock *flock); int ksmbd_vfs_posix_lock_wait_timeout(struct file_lock *flock, long timeout); void ksmbd_vfs_posix_lock_unblock(struct file_lock *flock); -int ksmbd_vfs_remove_acl_xattrs(struct dentry *dentry); -int ksmbd_vfs_remove_sd_xattrs(struct dentry *dentry); -int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn, struct dentry *dentry, +int ksmbd_vfs_remove_acl_xattrs(struct user_namespace *user_ns, + struct dentry *dentry); +int ksmbd_vfs_remove_sd_xattrs(struct user_namespace *user_ns, + struct dentry *dentry); +int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn, + struct user_namespace *user_ns, + struct dentry *dentry, struct smb_ntsd *pntsd, int len); -int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn, struct dentry *dentry, +int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn, + struct user_namespace *user_ns, + struct dentry *dentry, struct smb_ntsd **pntsd); -int ksmbd_vfs_set_dos_attrib_xattr(struct dentry *dentry, +int ksmbd_vfs_set_dos_attrib_xattr(struct user_namespace *user_ns, + struct dentry *dentry, struct xattr_dos_attrib *da); -int ksmbd_vfs_get_dos_attrib_xattr(struct dentry *dentry, +int ksmbd_vfs_get_dos_attrib_xattr(struct user_namespace *user_ns, + struct dentry *dentry, struct xattr_dos_attrib *da); -struct posix_acl *ksmbd_vfs_posix_acl_alloc(int count, gfp_t flags); -struct posix_acl *ksmbd_vfs_get_acl(struct inode *inode, int type); -int ksmbd_vfs_set_posix_acl(struct inode *inode, int type, - struct posix_acl *acl); -int ksmbd_vfs_set_init_posix_acl(struct inode *inode); -int ksmbd_vfs_inherit_posix_acl(struct inode *inode, +int ksmbd_vfs_set_init_posix_acl(struct user_namespace *user_ns, + struct inode *inode); +int ksmbd_vfs_inherit_posix_acl(struct user_namespace *user_ns, + struct inode *inode, struct inode *parent_inode); #endif /* __KSMBD_VFS_H__ */ diff --git a/fs/cifsd/vfs_cache.c b/fs/ksmbd/vfs_cache.c index 6ea09fe82814..1941ad3f5aa5 100644 --- a/fs/cifsd/vfs_cache.c +++ b/fs/ksmbd/vfs_cache.c @@ -10,7 +10,6 @@ #include "glob.h" #include "vfs_cache.h" -#include "buffer_pool.h" #include "oplock.h" #include "vfs.h" #include "connection.h" @@ -29,6 +28,7 @@ static DEFINE_RWLOCK(inode_hash_lock); static struct ksmbd_file_table global_ft; static atomic_long_t fd_limit; +static struct kmem_cache *filp_cache; void ksmbd_set_fd_limit(unsigned long limit) { @@ -83,7 +83,7 @@ static struct ksmbd_inode *__ksmbd_inode_lookup(struct inode *inode) static struct ksmbd_inode *ksmbd_inode_lookup(struct ksmbd_file *fp) { - return __ksmbd_inode_lookup(FP_INODE(fp)); + return __ksmbd_inode_lookup(file_inode(fp->filp)); } static struct ksmbd_inode *ksmbd_inode_lookup_by_vfsinode(struct inode *inode) @@ -156,7 +156,7 @@ static void ksmbd_inode_unhash(struct ksmbd_inode *ci) static int ksmbd_inode_init(struct ksmbd_inode *ci, struct ksmbd_file *fp) { - ci->m_inode = FP_INODE(fp); + ci->m_inode = file_inode(fp->filp); atomic_set(&ci->m_count, 1); atomic_set(&ci->op_count, 0); atomic_set(&ci->sop_count, 0); @@ -185,7 +185,7 @@ static struct ksmbd_inode *ksmbd_inode_get(struct ksmbd_file *fp) rc = ksmbd_inode_init(ci, fp); if (rc) { - ksmbd_err("inode initialized failed\n"); + pr_err("inode initialized failed\n"); kfree(ci); return NULL; } @@ -251,11 +251,12 @@ static void __ksmbd_inode_close(struct ksmbd_file *fp) filp = fp->filp; if (ksmbd_stream_fd(fp) && (ci->m_flags & S_DEL_ON_CLS_STREAM)) { ci->m_flags &= ~S_DEL_ON_CLS_STREAM; - err = ksmbd_vfs_remove_xattr(filp->f_path.dentry, + err = ksmbd_vfs_remove_xattr(file_mnt_user_ns(filp), + filp->f_path.dentry, fp->stream.name); if (err) - ksmbd_err("remove xattr failed : %s\n", - fp->stream.name); + pr_err("remove xattr failed : %s\n", + fp->stream.name); } if (atomic_dec_and_test(&ci->m_count)) { @@ -265,7 +266,7 @@ static void __ksmbd_inode_close(struct ksmbd_file *fp) dir = dentry->d_parent; ci->m_flags &= ~(S_DEL_ON_CLS | S_DEL_PENDING); write_unlock(&ci->m_lock); - ksmbd_vfs_unlink(dir, dentry); + ksmbd_vfs_unlink(file_mnt_user_ns(filp), dir, dentry); write_lock(&ci->m_lock); } write_unlock(&ci->m_lock); @@ -315,7 +316,7 @@ static void __ksmbd_close_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp) kfree(fp->filename); if (ksmbd_stream_fd(fp)) kfree(fp->stream.name); - ksmbd_free_file_struct(fp); + kmem_cache_free(filp_cache, fp); } static struct ksmbd_file *ksmbd_fp_get(struct ksmbd_file *fp) @@ -472,16 +473,14 @@ struct ksmbd_file *ksmbd_lookup_fd_inode(struct inode *inode) { struct ksmbd_file *lfp; struct ksmbd_inode *ci; - struct list_head *cur; ci = ksmbd_inode_lookup_by_vfsinode(inode); if (!ci) return NULL; read_lock(&ci->m_lock); - list_for_each(cur, &ci->m_fp_list) { - lfp = list_entry(cur, struct ksmbd_file, node); - if (inode == FP_INODE(lfp)) { + list_for_each_entry(lfp, &ci->m_fp_list, node) { + if (inode == file_inode(lfp->filp)) { atomic_dec(&ci->m_count); read_unlock(&ci->m_lock); return lfp; @@ -539,12 +538,12 @@ unsigned int ksmbd_open_durable_fd(struct ksmbd_file *fp) struct ksmbd_file *ksmbd_open_fd(struct ksmbd_work *work, struct file *filp) { - struct ksmbd_file *fp; + struct ksmbd_file *fp; int ret; - fp = ksmbd_alloc_file_struct(); + fp = kmem_cache_zalloc(filp_cache, GFP_KERNEL); if (!fp) { - ksmbd_err("Failed to allocate memory\n"); + pr_err("Failed to allocate memory\n"); return ERR_PTR(-ENOMEM); } @@ -561,19 +560,22 @@ struct ksmbd_file *ksmbd_open_fd(struct ksmbd_work *work, struct file *filp) fp->f_ci = ksmbd_inode_get(fp); if (!fp->f_ci) { - ksmbd_free_file_struct(fp); - return ERR_PTR(-ENOMEM); + ret = -ENOMEM; + goto err_out; } ret = __open_id(&work->sess->file_table, fp, OPEN_ID_TYPE_VOLATILE_ID); if (ret) { ksmbd_inode_put(fp->f_ci); - ksmbd_free_file_struct(fp); - return ERR_PTR(ret); + goto err_out; } atomic_inc(&work->conn->stats.open_files_count); return fp; + +err_out: + kmem_cache_free(filp_cache, fp); + return ERR_PTR(ret); } static int @@ -600,12 +602,14 @@ __close_file_table_ids(struct ksmbd_file_table *ft, return num; } -static bool tree_conn_fd_check(struct ksmbd_tree_connect *tcon, struct ksmbd_file *fp) +static bool tree_conn_fd_check(struct ksmbd_tree_connect *tcon, + struct ksmbd_file *fp) { return fp->tcon != tcon; } -static bool session_fd_check(struct ksmbd_tree_connect *tcon, struct ksmbd_file *fp) +static bool session_fd_check(struct ksmbd_tree_connect *tcon, + struct ksmbd_file *fp) { return false; } @@ -640,7 +644,7 @@ void ksmbd_free_global_file_table(void) idr_for_each_entry(global_ft.idr, fp, id) { __ksmbd_remove_durable_fd(fp); - ksmbd_free_file_struct(fp); + kmem_cache_free(filp_cache, fp); } ksmbd_destroy_file_table(&global_ft); @@ -683,3 +687,23 @@ void ksmbd_destroy_file_table(struct ksmbd_file_table *ft) kfree(ft->idr); ft->idr = NULL; } + +int ksmbd_init_file_cache(void) +{ + filp_cache = kmem_cache_create("ksmbd_file_cache", + sizeof(struct ksmbd_file), 0, + SLAB_HWCACHE_ALIGN, NULL); + if (!filp_cache) + goto out; + + return 0; + +out: + pr_err("failed to allocate file cache\n"); + return -ENOMEM; +} + +void ksmbd_exit_file_cache(void) +{ + kmem_cache_destroy(filp_cache); +} diff --git a/fs/cifsd/vfs_cache.h b/fs/ksmbd/vfs_cache.h index 635eedbd497c..543494f664cb 100644 --- a/fs/cifsd/vfs_cache.h +++ b/fs/ksmbd/vfs_cache.h @@ -25,15 +25,6 @@ #define KSMBD_NO_FID (UINT_MAX) #define SMB2_NO_FID (0xFFFFFFFFFFFFFFFFULL) -#define FP_FILENAME(fp) ((fp)->filp->f_path.dentry->d_name.name) -#define FP_INODE(fp) d_inode((fp)->filp->f_path.dentry) -#define PARENT_INODE(fp) d_inode((fp)->filp->f_path.dentry->d_parent) - -#define ATTR_FP(fp) ((fp)->attrib_only && \ - ((fp)->cdoption != FILE_OVERWRITE_IF_LE && \ - (fp)->cdoption != FILE_OVERWRITE_LE && \ - (fp)->cdoption != FILE_SUPERSEDE_LE)) - struct ksmbd_conn; struct ksmbd_session; @@ -182,4 +173,6 @@ void ksmbd_set_inode_pending_delete(struct ksmbd_file *fp); void ksmbd_clear_inode_pending_delete(struct ksmbd_file *fp); void ksmbd_fd_set_delete_on_close(struct ksmbd_file *fp, int file_info); +int ksmbd_init_file_cache(void); +void ksmbd_exit_file_cache(void); #endif /* __VFS_CACHE_H__ */ diff --git a/fs/ksmbd/xattr.h b/fs/ksmbd/xattr.h new file mode 100644 index 000000000000..8857c01093d9 --- /dev/null +++ b/fs/ksmbd/xattr.h @@ -0,0 +1,122 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2021 Samsung Electronics Co., Ltd. + */ + +#ifndef __XATTR_H__ +#define __XATTR_H__ + +/* + * These are on-disk structures to store additional metadata into xattr to + * reproduce windows filesystem semantics. And they are encoded with NDR to + * compatible with samba's xattr meta format. The compatibility with samba + * is important because it can lose the information(file attribute, + * creation time, acls) about the existing files when switching between + * ksmbd and samba. + */ + +/* + * Dos attribute flags used for what variable is valid. + */ +enum { + XATTR_DOSINFO_ATTRIB = 0x00000001, + XATTR_DOSINFO_EA_SIZE = 0x00000002, + XATTR_DOSINFO_SIZE = 0x00000004, + XATTR_DOSINFO_ALLOC_SIZE = 0x00000008, + XATTR_DOSINFO_CREATE_TIME = 0x00000010, + XATTR_DOSINFO_CHANGE_TIME = 0x00000020, + XATTR_DOSINFO_ITIME = 0x00000040 +}; + +/* + * Dos attribute structure which is compatible with samba's one. + * Storing it into the xattr named "DOSATTRIB" separately from inode + * allows ksmbd to faithfully reproduce windows filesystem semantics + * on top of a POSIX filesystem. + */ +struct xattr_dos_attrib { + __u16 version; /* version 3 or version 4 */ + __u32 flags; /* valid flags */ + __u32 attr; /* Dos attribute */ + __u32 ea_size; /* EA size */ + __u64 size; + __u64 alloc_size; + __u64 create_time; /* File creation time */ + __u64 change_time; /* File change time */ + __u64 itime; /* Invented/Initial time */ +}; + +/* + * Enumeration is used for computing posix acl hash. + */ +enum { + SMB_ACL_TAG_INVALID = 0, + SMB_ACL_USER, + SMB_ACL_USER_OBJ, + SMB_ACL_GROUP, + SMB_ACL_GROUP_OBJ, + SMB_ACL_OTHER, + SMB_ACL_MASK +}; + +#define SMB_ACL_READ 4 +#define SMB_ACL_WRITE 2 +#define SMB_ACL_EXECUTE 1 + +struct xattr_acl_entry { + int type; + uid_t uid; + gid_t gid; + mode_t perm; +}; + +/* + * xattr_smb_acl structure is used for computing posix acl hash. + */ +struct xattr_smb_acl { + int count; + int next; + struct xattr_acl_entry entries[0]; +}; + +/* 64bytes hash in xattr_ntacl is computed with sha256 */ +#define XATTR_SD_HASH_TYPE_SHA256 0x1 +#define XATTR_SD_HASH_SIZE 64 + +/* + * xattr_ntacl is used for storing ntacl and hashes. + * Hash is used for checking valid posix acl and ntacl in xattr. + */ +struct xattr_ntacl { + __u16 version; /* version 4*/ + void *sd_buf; + __u32 sd_size; + __u16 hash_type; /* hash type */ + __u8 desc[10]; /* posix_acl description */ + __u16 desc_len; + __u64 current_time; + __u8 hash[XATTR_SD_HASH_SIZE]; /* 64bytes hash for ntacl */ + __u8 posix_acl_hash[XATTR_SD_HASH_SIZE]; /* 64bytes hash for posix acl */ +}; + +/* DOS ATTRIBUITE XATTR PREFIX */ +#define DOS_ATTRIBUTE_PREFIX "DOSATTRIB" +#define DOS_ATTRIBUTE_PREFIX_LEN (sizeof(DOS_ATTRIBUTE_PREFIX) - 1) +#define XATTR_NAME_DOS_ATTRIBUTE (XATTR_USER_PREFIX DOS_ATTRIBUTE_PREFIX) +#define XATTR_NAME_DOS_ATTRIBUTE_LEN \ + (sizeof(XATTR_USER_PREFIX DOS_ATTRIBUTE_PREFIX) - 1) + +/* STREAM XATTR PREFIX */ +#define STREAM_PREFIX "DosStream." +#define STREAM_PREFIX_LEN (sizeof(STREAM_PREFIX) - 1) +#define XATTR_NAME_STREAM (XATTR_USER_PREFIX STREAM_PREFIX) +#define XATTR_NAME_STREAM_LEN (sizeof(XATTR_NAME_STREAM) - 1) + +/* SECURITY DESCRIPTOR(NTACL) XATTR PREFIX */ +#define SD_PREFIX "NTACL" +#define SD_PREFIX_LEN (sizeof(SD_PREFIX) - 1) +#define XATTR_NAME_SD (XATTR_SECURITY_PREFIX SD_PREFIX) +#define XATTR_NAME_SD_LEN \ + (sizeof(XATTR_SECURITY_PREFIX SD_PREFIX) - 1) + +#endif /* __XATTR_H__ */ |