mirror of
https://github.com/hardkernel/linux.git
synced 2026-03-25 12:00:22 +09:00
Merge 5.15.145 into android14-5.15-lts
Changes in 5.15.145 ksmbd: use ksmbd_req_buf_next() in ksmbd_verify_smb_message() ksmdb: use cmd helper variable in smb2_get_ksmbd_tcon() ksmbd: Remove redundant 'flush_workqueue()' calls ksmbd: remove md4 leftovers ksmbd: remove smb2_buf_length in smb2_hdr ksmbd: remove smb2_buf_length in smb2_transform_hdr ksmbd: change LeaseKey data type to u8 array ksmbd: use oid registry functions to decode OIDs ksmbd: Remove unused parameter from smb2_get_name() ksmbd: Remove unused fields from ksmbd_file struct definition ksmbd: set both ipv4 and ipv6 in FSCTL_QUERY_NETWORK_INTERFACE_INFO ksmbd: Fix buffer_check_err() kernel-doc comment ksmbd: Fix smb2_set_info_file() kernel-doc comment ksmbd: Delete an invalid argument description in smb2_populate_readdir_entry() ksmbd: Fix smb2_get_name() kernel-doc comment ksmbd: register ksmbd ib client with ib_register_client() ksmbd: set 445 port to smbdirect port by default ksmbd: smbd: call rdma_accept() under CM handler ksmbd: smbd: create MR pool ksmbd: smbd: change the default maximum read/write, receive size ksmbd: add smb-direct shutdown ksmbd: smbd: fix missing client's memory region invalidation ksmbd: smbd: validate buffer descriptor structures ksmbd: add support for key exchange ksmbd: use netif_is_bridge_port ksmbd: store fids as opaque u64 integers ksmbd: shorten experimental warning on loading the module ksmbd: Remove a redundant zeroing of memory ksmbd: replace usage of found with dedicated list iterator variable smb3: fix ksmbd bigendian bug in oplock break, and move its struct to smbfs_common ksmbd: remove filename in ksmbd_file ksmbd: validate length in smb2_write() ksmbd: smbd: change prototypes of RDMA read/write related functions ksmbd: smbd: introduce read/write credits for RDMA read/write ksmbd: smbd: simplify tracking pending packets ksmbd: smbd: change the return value of get_sg_list ksmbd: smbd: handle multiple Buffer descriptors ksmbd: fix wrong smbd max read/write size check ksmbd: Fix some kernel-doc comments ksmbd: smbd: fix connection dropped issue ksmbd: smbd: relax the count of sges required ksmbd: smbd: Remove useless license text when SPDX-License-Identifier is already used ksmbd: remove duplicate flag set in smb2_write ksmbd: remove unused ksmbd_share_configs_cleanup function ksmbd: use wait_event instead of schedule_timeout() ksmbd: request update to stale share config ksmbd: remove unnecessary generic_fillattr in smb2_open ksmbd: don't open-code file_path() ksmbd: don't open-code %pD ksmbd: constify struct path ksmbd: remove generic_fillattr use in smb2_open() ksmbd: casefold utf-8 share names and fix ascii lowercase conversion ksmbd: change security id to the one samba used for posix extension ksmbd: set file permission mode to match Samba server posix extension behavior ksmbd: fill sids in SMB_FIND_FILE_POSIX_INFO response ksmbd: fix encryption failure issue for session logoff response ksmbd: set NTLMSSP_NEGOTIATE_SEAL flag to challenge blob ksmbd: decrease the number of SMB3 smbdirect server SGEs ksmbd: reduce server smbdirect max send/receive segment sizes ksmbd: hide socket error message when ipv6 config is disable ksmbd: make utf-8 file name comparison work in __caseless_lookup() ksmbd: call ib_drain_qp when disconnected ksmbd: validate share name from share config response ksmbd: replace one-element arrays with flexible-array members ksmbd: set SMB2_SESSION_FLAG_ENCRYPT_DATA when enforcing data encryption for this share ksmbd: use F_SETLK when unlocking a file ksmbd: Fix resource leak in smb2_lock() ksmbd: Convert to use sysfs_emit()/sysfs_emit_at() APIs ksmbd: send proper error response in smb2_tree_connect() ksmbd: Implements sess->ksmbd_chann_list as xarray ksmbd: Implements sess->rpc_handle_list as xarray ksmbd: fix typo, syncronous->synchronous ksmbd: Remove duplicated codes ksmbd: update Kconfig to note Kerberos support and fix indentation ksmbd: Fix spelling mistake "excceed" -> "exceeded" ksmbd: Fix parameter name and comment mismatch ksmbd: fix possible memory leak in smb2_lock() ksmbd: fix wrong signingkey creation when encryption is AES256 ksmbd: remove unused is_char_allowed function ksmbd: delete asynchronous work from list ksmbd: fix slab-out-of-bounds in init_smb2_rsp_hdr ksmbd: avoid out of bounds access in decode_preauth_ctxt() ksmbd: set NegotiateContextCount once instead of every inc ksmbd: avoid duplicate negotiate ctx offset increments ksmbd: remove unused compression negotiate ctx packing fs: introduce lock_rename_child() helper ksmbd: fix racy issue from using ->d_parent and ->d_name ksmbd: fix racy issue from session setup and logoff ksmbd: destroy expired sessions ksmbd: block asynchronous requests when making a delay on session setup ksmbd: fix racy issue from smb2 close and logoff with multichannel ksmbd: fix racy issue under cocurrent smb2 tree disconnect ksmbd: fix uninitialized pointer read in ksmbd_vfs_rename() ksmbd: fix uninitialized pointer read in smb2_create_link() ksmbd: fix multiple out-of-bounds read during context decoding ksmbd: fix UAF issue from opinfo->conn ksmbd: call putname after using the last component ksmbd: fix out-of-bound read in deassemble_neg_contexts() ksmbd: fix out-of-bound read in parse_lease_state() ksmbd: fix posix_acls and acls dereferencing possible ERR_PTR() ksmbd: check the validation of pdu_size in ksmbd_conn_handler_loop ksmbd: validate smb request protocol id ksmbd: add mnt_want_write to ksmbd vfs functions ksmbd: remove unused ksmbd_tree_conn_share function ksmbd: use kzalloc() instead of __GFP_ZERO ksmbd: return a literal instead of 'err' in ksmbd_vfs_kern_path_locked() ksmbd: Change the return value of ksmbd_vfs_query_maximal_access to void ksmbd: use kvzalloc instead of kvmalloc ksmbd: Replace the ternary conditional operator with min() ksmbd: fix out of bounds read in smb2_sess_setup ksmbd: add missing compound request handing in some commands ksmbd: Use struct_size() helper in ksmbd_negotiate_smb_dialect() ksmbd: Replace one-element array with flexible-array member ksmbd: Fix unsigned expression compared with zero ksmbd: check if a mount point is crossed during path lookup ksmbd: validate session id and tree id in compound request ksmbd: fix out of bounds in init_smb2_rsp_hdr() ksmbd: switch to use kmemdup_nul() helper ksmbd: add support for read compound ksmbd: fix wrong interim response on compound ksmbd: fix `force create mode' and `force directory mode' ksmbd: reduce descriptor size if remaining bytes is less than request size ksmbd: Fix one kernel-doc comment ksmbd: fix slub overflow in ksmbd_decode_ntlmssp_auth_blob() ksmbd: add missing calling smb2_set_err_rsp() on error ksmbd: remove experimental warning ksmbd: remove unneeded mark_inode_dirty in set_info_sec() ksmbd: fix passing freed memory 'aux_payload_buf' ksmbd: return invalid parameter error response if smb2 request is invalid ksmbd: check iov vector index in ksmbd_conn_write() ksmbd: fix race condition between session lookup and expire ksmbd: fix race condition with fp ksmbd: fix race condition from parallel smb2 logoff requests ksmbd: fix race condition from parallel smb2 lock requests ksmbd: fix race condition between tree conn lookup and disconnect ksmbd: fix wrong error response status by using set_smb2_rsp_status() ksmbd: fix Null pointer dereferences in ksmbd_update_fstate() ksmbd: fix potential double free on smb2_read_pipe() error path ksmbd: Remove unused field in ksmbd_user struct ksmbd: reorganize ksmbd_iov_pin_rsp() ksmbd: fix kernel-doc comment of ksmbd_vfs_setxattr() ksmbd: fix recursive locking in vfs helpers ksmbd: fix missing RDMA-capable flag for IPoIB device in ksmbd_rdma_capable_netdev() ksmbd: add support for surrogate pair conversion ksmbd: no need to wait for binded connection termination at logoff ksmbd: fix kernel-doc comment of ksmbd_vfs_kern_path_locked() ksmbd: handle malformed smb1 message ksmbd: prevent memory leak on error return ksmbd: fix possible deadlock in smb2_open ksmbd: separately allocate ci per dentry ksmbd: move oplock handling after unlock parent dir ksmbd: release interim response after sending status pending response ksmbd: move setting SMB2_FLAGS_ASYNC_COMMAND and AsyncId ksmbd: don't update ->op_state as OPLOCK_STATE_NONE on error Revert "drm/bridge: lt9611uxc: fix the race in the error path" Revert "drm/bridge: lt9611uxc: Register and attach our DSI device at probe" Revert "drm/bridge: lt9611uxc: Switch to devm MIPI-DSI helpers" tracing/kprobes: Return EADDRNOTAVAIL when func matches several symbols kasan: disable kasan_non_canonical_hook() for HW tags Linux 5.15.145 Change-Id: I19d6ce051f291784e04d3ffbc5f67e706de2f151 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
2
Makefile
2
Makefile
@@ -1,7 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
VERSION = 5
|
||||
PATCHLEVEL = 15
|
||||
SUBLEVEL = 144
|
||||
SUBLEVEL = 145
|
||||
EXTRAVERSION =
|
||||
NAME = Trick or Treat
|
||||
|
||||
|
||||
@@ -258,18 +258,17 @@ static struct mipi_dsi_device *lt9611uxc_attach_dsi(struct lt9611uxc *lt9611uxc,
|
||||
const struct mipi_dsi_device_info info = { "lt9611uxc", 0, NULL };
|
||||
struct mipi_dsi_device *dsi;
|
||||
struct mipi_dsi_host *host;
|
||||
struct device *dev = lt9611uxc->dev;
|
||||
int ret;
|
||||
|
||||
host = of_find_mipi_dsi_host_by_node(dsi_node);
|
||||
if (!host) {
|
||||
dev_err(dev, "failed to find dsi host\n");
|
||||
dev_err(lt9611uxc->dev, "failed to find dsi host\n");
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
}
|
||||
|
||||
dsi = devm_mipi_dsi_device_register_full(dev, host, &info);
|
||||
dsi = mipi_dsi_device_register_full(host, &info);
|
||||
if (IS_ERR(dsi)) {
|
||||
dev_err(dev, "failed to create dsi device\n");
|
||||
dev_err(lt9611uxc->dev, "failed to create dsi device\n");
|
||||
return dsi;
|
||||
}
|
||||
|
||||
@@ -278,9 +277,10 @@ static struct mipi_dsi_device *lt9611uxc_attach_dsi(struct lt9611uxc *lt9611uxc,
|
||||
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
|
||||
MIPI_DSI_MODE_VIDEO_HSE;
|
||||
|
||||
ret = devm_mipi_dsi_attach(dev, dsi);
|
||||
ret = mipi_dsi_attach(dsi);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to attach dsi to host\n");
|
||||
dev_err(lt9611uxc->dev, "failed to attach dsi to host\n");
|
||||
mipi_dsi_device_unregister(dsi);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
@@ -355,6 +355,19 @@ static int lt9611uxc_connector_init(struct drm_bridge *bridge, struct lt9611uxc
|
||||
return drm_connector_attach_encoder(<9611uxc->connector, bridge->encoder);
|
||||
}
|
||||
|
||||
static void lt9611uxc_bridge_detach(struct drm_bridge *bridge)
|
||||
{
|
||||
struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
|
||||
|
||||
if (lt9611uxc->dsi1) {
|
||||
mipi_dsi_detach(lt9611uxc->dsi1);
|
||||
mipi_dsi_device_unregister(lt9611uxc->dsi1);
|
||||
}
|
||||
|
||||
mipi_dsi_detach(lt9611uxc->dsi0);
|
||||
mipi_dsi_device_unregister(lt9611uxc->dsi0);
|
||||
}
|
||||
|
||||
static int lt9611uxc_bridge_attach(struct drm_bridge *bridge,
|
||||
enum drm_bridge_attach_flags flags)
|
||||
{
|
||||
@@ -367,7 +380,27 @@ static int lt9611uxc_bridge_attach(struct drm_bridge *bridge,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Attach primary DSI */
|
||||
lt9611uxc->dsi0 = lt9611uxc_attach_dsi(lt9611uxc, lt9611uxc->dsi0_node);
|
||||
if (IS_ERR(lt9611uxc->dsi0))
|
||||
return PTR_ERR(lt9611uxc->dsi0);
|
||||
|
||||
/* Attach secondary DSI, if specified */
|
||||
if (lt9611uxc->dsi1_node) {
|
||||
lt9611uxc->dsi1 = lt9611uxc_attach_dsi(lt9611uxc, lt9611uxc->dsi1_node);
|
||||
if (IS_ERR(lt9611uxc->dsi1)) {
|
||||
ret = PTR_ERR(lt9611uxc->dsi1);
|
||||
goto err_unregister_dsi0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_unregister_dsi0:
|
||||
mipi_dsi_detach(lt9611uxc->dsi0);
|
||||
mipi_dsi_device_unregister(lt9611uxc->dsi0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static enum drm_mode_status
|
||||
@@ -511,6 +544,7 @@ static struct edid *lt9611uxc_bridge_get_edid(struct drm_bridge *bridge,
|
||||
|
||||
static const struct drm_bridge_funcs lt9611uxc_bridge_funcs = {
|
||||
.attach = lt9611uxc_bridge_attach,
|
||||
.detach = lt9611uxc_bridge_detach,
|
||||
.mode_valid = lt9611uxc_bridge_mode_valid,
|
||||
.mode_set = lt9611uxc_bridge_mode_set,
|
||||
.detect = lt9611uxc_bridge_detect,
|
||||
@@ -927,9 +961,9 @@ retry:
|
||||
init_waitqueue_head(<9611uxc->wq);
|
||||
INIT_WORK(<9611uxc->work, lt9611uxc_hpd_work);
|
||||
|
||||
ret = request_threaded_irq(client->irq, NULL,
|
||||
lt9611uxc_irq_thread_handler,
|
||||
IRQF_ONESHOT, "lt9611uxc", lt9611uxc);
|
||||
ret = devm_request_threaded_irq(dev, client->irq, NULL,
|
||||
lt9611uxc_irq_thread_handler,
|
||||
IRQF_ONESHOT, "lt9611uxc", lt9611uxc);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to request irq\n");
|
||||
goto err_disable_regulators;
|
||||
@@ -946,29 +980,8 @@ retry:
|
||||
|
||||
drm_bridge_add(<9611uxc->bridge);
|
||||
|
||||
/* Attach primary DSI */
|
||||
lt9611uxc->dsi0 = lt9611uxc_attach_dsi(lt9611uxc, lt9611uxc->dsi0_node);
|
||||
if (IS_ERR(lt9611uxc->dsi0)) {
|
||||
ret = PTR_ERR(lt9611uxc->dsi0);
|
||||
goto err_remove_bridge;
|
||||
}
|
||||
|
||||
/* Attach secondary DSI, if specified */
|
||||
if (lt9611uxc->dsi1_node) {
|
||||
lt9611uxc->dsi1 = lt9611uxc_attach_dsi(lt9611uxc, lt9611uxc->dsi1_node);
|
||||
if (IS_ERR(lt9611uxc->dsi1)) {
|
||||
ret = PTR_ERR(lt9611uxc->dsi1);
|
||||
goto err_remove_bridge;
|
||||
}
|
||||
}
|
||||
|
||||
return lt9611uxc_audio_init(dev, lt9611uxc);
|
||||
|
||||
err_remove_bridge:
|
||||
free_irq(client->irq, lt9611uxc);
|
||||
cancel_work_sync(<9611uxc->work);
|
||||
drm_bridge_remove(<9611uxc->bridge);
|
||||
|
||||
err_disable_regulators:
|
||||
regulator_bulk_disable(ARRAY_SIZE(lt9611uxc->supplies), lt9611uxc->supplies);
|
||||
|
||||
@@ -983,7 +996,7 @@ static int lt9611uxc_remove(struct i2c_client *client)
|
||||
{
|
||||
struct lt9611uxc *lt9611uxc = i2c_get_clientdata(client);
|
||||
|
||||
free_irq(client->irq, lt9611uxc);
|
||||
disable_irq(client->irq);
|
||||
cancel_work_sync(<9611uxc->work);
|
||||
lt9611uxc_audio_exit(lt9611uxc);
|
||||
drm_bridge_remove(<9611uxc->bridge);
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
config SMB_SERVER
|
||||
tristate "SMB3 server support (EXPERIMENTAL)"
|
||||
tristate "SMB3 server support"
|
||||
depends on INET
|
||||
depends on MULTIUSER
|
||||
depends on FILE_LOCKING
|
||||
select NLS
|
||||
select NLS_UTF8
|
||||
select CRYPTO
|
||||
select CRYPTO_MD4
|
||||
select CRYPTO_MD5
|
||||
select CRYPTO_HMAC
|
||||
select CRYPTO_ECB
|
||||
@@ -34,14 +33,16 @@ config SMB_SERVER
|
||||
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
|
||||
available via the README file
|
||||
(https://github.com/cifsd-team/ksmbd-tools/blob/master/README).
|
||||
|
||||
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
|
||||
establishment via NTLM or NTLMv2.
|
||||
establishment via Kerberos or NTLMv2.
|
||||
|
||||
if SMB_SERVER
|
||||
|
||||
config SMB_SERVER_SMBDIRECT
|
||||
bool "Support for SMB Direct protocol"
|
||||
@@ -55,6 +56,8 @@ config SMB_SERVER_SMBDIRECT
|
||||
SMB Direct allows transferring SMB packets over RDMA. If unsure,
|
||||
say N.
|
||||
|
||||
endif
|
||||
|
||||
config SMB_SERVER_CHECK_CAP_NET_ADMIN
|
||||
bool "Enable check network administration capability"
|
||||
depends on SMB_SERVER
|
||||
|
||||
173
fs/ksmbd/asn1.c
173
fs/ksmbd/asn1.c
@@ -21,101 +21,11 @@
|
||||
#include "ksmbd_spnego_negtokeninit.asn1.h"
|
||||
#include "ksmbd_spnego_negtokentarg.asn1.h"
|
||||
|
||||
#define SPNEGO_OID_LEN 7
|
||||
#define NTLMSSP_OID_LEN 10
|
||||
#define KRB5_OID_LEN 7
|
||||
#define KRB5U2U_OID_LEN 8
|
||||
#define MSKRB5_OID_LEN 7
|
||||
static unsigned long SPNEGO_OID[7] = { 1, 3, 6, 1, 5, 5, 2 };
|
||||
static unsigned long NTLMSSP_OID[10] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 10 };
|
||||
static unsigned long KRB5_OID[7] = { 1, 2, 840, 113554, 1, 2, 2 };
|
||||
static unsigned long KRB5U2U_OID[8] = { 1, 2, 840, 113554, 1, 2, 2, 3 };
|
||||
static unsigned long MSKRB5_OID[7] = { 1, 2, 840, 48018, 1, 2, 2 };
|
||||
|
||||
static char NTLMSSP_OID_STR[NTLMSSP_OID_LEN] = { 0x2b, 0x06, 0x01, 0x04, 0x01,
|
||||
0x82, 0x37, 0x02, 0x02, 0x0a };
|
||||
|
||||
static bool
|
||||
asn1_subid_decode(const unsigned char **begin, const unsigned char *end,
|
||||
unsigned long *subid)
|
||||
{
|
||||
const unsigned char *ptr = *begin;
|
||||
unsigned char ch;
|
||||
|
||||
*subid = 0;
|
||||
|
||||
do {
|
||||
if (ptr >= end)
|
||||
return false;
|
||||
|
||||
ch = *ptr++;
|
||||
*subid <<= 7;
|
||||
*subid |= ch & 0x7F;
|
||||
} while ((ch & 0x80) == 0x80);
|
||||
|
||||
*begin = ptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool asn1_oid_decode(const unsigned char *value, size_t vlen,
|
||||
unsigned long **oid, size_t *oidlen)
|
||||
{
|
||||
const unsigned char *iptr = value, *end = value + vlen;
|
||||
unsigned long *optr;
|
||||
unsigned long subid;
|
||||
|
||||
vlen += 1;
|
||||
if (vlen < 2 || vlen > UINT_MAX / sizeof(unsigned long))
|
||||
goto fail_nullify;
|
||||
|
||||
*oid = kmalloc(vlen * sizeof(unsigned long), GFP_KERNEL);
|
||||
if (!*oid)
|
||||
return false;
|
||||
|
||||
optr = *oid;
|
||||
|
||||
if (!asn1_subid_decode(&iptr, end, &subid))
|
||||
goto fail;
|
||||
|
||||
if (subid < 40) {
|
||||
optr[0] = 0;
|
||||
optr[1] = subid;
|
||||
} else if (subid < 80) {
|
||||
optr[0] = 1;
|
||||
optr[1] = subid - 40;
|
||||
} else {
|
||||
optr[0] = 2;
|
||||
optr[1] = subid - 80;
|
||||
}
|
||||
|
||||
*oidlen = 2;
|
||||
optr += 2;
|
||||
|
||||
while (iptr < end) {
|
||||
if (++(*oidlen) > vlen)
|
||||
goto fail;
|
||||
|
||||
if (!asn1_subid_decode(&iptr, end, optr++))
|
||||
goto fail;
|
||||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
kfree(*oid);
|
||||
fail_nullify:
|
||||
*oid = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool oid_eq(unsigned long *oid1, unsigned int oid1len,
|
||||
unsigned long *oid2, unsigned int oid2len)
|
||||
{
|
||||
if (oid1len != oid2len)
|
||||
return false;
|
||||
|
||||
return memcmp(oid1, oid2, oid1len) == 0;
|
||||
}
|
||||
|
||||
int
|
||||
ksmbd_decode_negTokenInit(unsigned char *security_blob, int length,
|
||||
struct ksmbd_conn *conn)
|
||||
@@ -252,26 +162,18 @@ int build_spnego_ntlmssp_auth_blob(unsigned char **pbuffer, u16 *buflen,
|
||||
int ksmbd_gssapi_this_mech(void *context, size_t hdrlen, unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
unsigned long *oid;
|
||||
size_t oidlen;
|
||||
int err = 0;
|
||||
enum OID oid;
|
||||
|
||||
if (!asn1_oid_decode(value, vlen, &oid, &oidlen)) {
|
||||
err = -EBADMSG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!oid_eq(oid, oidlen, SPNEGO_OID, SPNEGO_OID_LEN))
|
||||
err = -EBADMSG;
|
||||
kfree(oid);
|
||||
out:
|
||||
if (err) {
|
||||
oid = look_up_OID(value, vlen);
|
||||
if (oid != OID_spnego) {
|
||||
char buf[50];
|
||||
|
||||
sprint_oid(value, vlen, buf, sizeof(buf));
|
||||
ksmbd_debug(AUTH, "Unexpected OID: %s\n", buf);
|
||||
return -EBADMSG;
|
||||
}
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ksmbd_neg_token_init_mech_type(void *context, size_t hdrlen,
|
||||
@@ -279,65 +181,56 @@ int ksmbd_neg_token_init_mech_type(void *context, size_t hdrlen,
|
||||
size_t vlen)
|
||||
{
|
||||
struct ksmbd_conn *conn = context;
|
||||
unsigned long *oid;
|
||||
size_t oidlen;
|
||||
enum OID oid;
|
||||
int mech_type;
|
||||
char buf[50];
|
||||
|
||||
if (!asn1_oid_decode(value, vlen, &oid, &oidlen))
|
||||
goto fail;
|
||||
|
||||
if (oid_eq(oid, oidlen, NTLMSSP_OID, NTLMSSP_OID_LEN))
|
||||
oid = look_up_OID(value, vlen);
|
||||
if (oid == OID_ntlmssp) {
|
||||
mech_type = KSMBD_AUTH_NTLMSSP;
|
||||
else if (oid_eq(oid, oidlen, MSKRB5_OID, MSKRB5_OID_LEN))
|
||||
} else if (oid == OID_mskrb5) {
|
||||
mech_type = KSMBD_AUTH_MSKRB5;
|
||||
else if (oid_eq(oid, oidlen, KRB5_OID, KRB5_OID_LEN))
|
||||
} else if (oid == OID_krb5) {
|
||||
mech_type = KSMBD_AUTH_KRB5;
|
||||
else if (oid_eq(oid, oidlen, KRB5U2U_OID, KRB5U2U_OID_LEN))
|
||||
} else if (oid == OID_krb5u2u) {
|
||||
mech_type = KSMBD_AUTH_KRB5U2U;
|
||||
else
|
||||
goto fail;
|
||||
} else {
|
||||
char buf[50];
|
||||
|
||||
sprint_oid(value, vlen, buf, sizeof(buf));
|
||||
ksmbd_debug(AUTH, "Unexpected OID: %s\n", buf);
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
conn->auth_mechs |= mech_type;
|
||||
if (conn->preferred_auth_mech == 0)
|
||||
conn->preferred_auth_mech = mech_type;
|
||||
|
||||
kfree(oid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fail:
|
||||
kfree(oid);
|
||||
sprint_oid(value, vlen, buf, sizeof(buf));
|
||||
ksmbd_debug(AUTH, "Unexpected OID: %s\n", buf);
|
||||
return -EBADMSG;
|
||||
static int ksmbd_neg_token_alloc(void *context, size_t hdrlen,
|
||||
unsigned char tag, const void *value,
|
||||
size_t vlen)
|
||||
{
|
||||
struct ksmbd_conn *conn = context;
|
||||
|
||||
conn->mechToken = kmemdup_nul(value, vlen, GFP_KERNEL);
|
||||
if (!conn->mechToken)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ksmbd_neg_token_init_mech_token(void *context, size_t hdrlen,
|
||||
unsigned char tag, const void *value,
|
||||
size_t vlen)
|
||||
{
|
||||
struct ksmbd_conn *conn = context;
|
||||
|
||||
conn->mechToken = kmalloc(vlen + 1, GFP_KERNEL);
|
||||
if (!conn->mechToken)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(conn->mechToken, value, vlen);
|
||||
conn->mechToken[vlen] = '\0';
|
||||
return 0;
|
||||
return ksmbd_neg_token_alloc(context, hdrlen, tag, value, vlen);
|
||||
}
|
||||
|
||||
int ksmbd_neg_token_targ_resp_token(void *context, size_t hdrlen,
|
||||
unsigned char tag, const void *value,
|
||||
size_t vlen)
|
||||
{
|
||||
struct ksmbd_conn *conn = context;
|
||||
|
||||
conn->mechToken = kmalloc(vlen + 1, GFP_KERNEL);
|
||||
if (!conn->mechToken)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(conn->mechToken, value, vlen);
|
||||
conn->mechToken[vlen] = '\0';
|
||||
return 0;
|
||||
return ksmbd_neg_token_alloc(context, hdrlen, tag, value, vlen);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "mgmt/user_config.h"
|
||||
#include "crypto_ctx.h"
|
||||
#include "transport_ipc.h"
|
||||
#include "../smbfs_common/arc4.h"
|
||||
|
||||
/*
|
||||
* Fixed format data defining GSS header and fixed string
|
||||
@@ -342,6 +343,32 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
|
||||
nt_len - CIFS_ENCPWD_SIZE,
|
||||
domain_name, conn->ntlmssp.cryptkey);
|
||||
kfree(domain_name);
|
||||
|
||||
/* The recovered secondary session key */
|
||||
if (conn->ntlmssp.client_flags & NTLMSSP_NEGOTIATE_KEY_XCH) {
|
||||
struct arc4_ctx *ctx_arc4;
|
||||
unsigned int sess_key_off, sess_key_len;
|
||||
|
||||
sess_key_off = le32_to_cpu(authblob->SessionKey.BufferOffset);
|
||||
sess_key_len = le16_to_cpu(authblob->SessionKey.Length);
|
||||
|
||||
if (blob_len < (u64)sess_key_off + sess_key_len)
|
||||
return -EINVAL;
|
||||
|
||||
if (sess_key_len > CIFS_KEY_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
ctx_arc4 = kmalloc(sizeof(*ctx_arc4), GFP_KERNEL);
|
||||
if (!ctx_arc4)
|
||||
return -ENOMEM;
|
||||
|
||||
cifs_arc4_setkey(ctx_arc4, sess->sess_key,
|
||||
SMB2_NTLMV2_SESSKEY_SIZE);
|
||||
cifs_arc4_crypt(ctx_arc4, sess->sess_key,
|
||||
(char *)authblob + sess_key_off, sess_key_len);
|
||||
kfree_sensitive(ctx_arc4);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -404,6 +431,9 @@ ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob,
|
||||
NTLMSSP_NEGOTIATE_56);
|
||||
}
|
||||
|
||||
if (cflags & NTLMSSP_NEGOTIATE_SEAL && smb3_encryption_negotiated(conn))
|
||||
flags |= NTLMSSP_NEGOTIATE_SEAL;
|
||||
|
||||
if (cflags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN)
|
||||
flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
|
||||
|
||||
@@ -414,6 +444,9 @@ ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob,
|
||||
(cflags & NTLMSSP_NEGOTIATE_EXTENDED_SEC))
|
||||
flags |= NTLMSSP_NEGOTIATE_EXTENDED_SEC;
|
||||
|
||||
if (cflags & NTLMSSP_NEGOTIATE_KEY_XCH)
|
||||
flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
|
||||
|
||||
chgblob->NegotiateFlags = cpu_to_le32(flags);
|
||||
len = strlen(ksmbd_netbios_name());
|
||||
name = kmalloc(2 + UNICODE_LEN(len), GFP_KERNEL);
|
||||
@@ -700,8 +733,9 @@ static int generate_key(struct ksmbd_conn *conn, struct ksmbd_session *sess,
|
||||
goto smb3signkey_ret;
|
||||
}
|
||||
|
||||
if (conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM ||
|
||||
conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM)
|
||||
if (key_size == SMB3_ENC_DEC_KEY_SIZE &&
|
||||
(conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM ||
|
||||
conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM))
|
||||
rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), L256, 4);
|
||||
else
|
||||
rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), L128, 4);
|
||||
@@ -884,9 +918,9 @@ int ksmbd_gen_preauth_integrity_hash(struct ksmbd_conn *conn, char *buf,
|
||||
__u8 *pi_hash)
|
||||
{
|
||||
int rc;
|
||||
struct smb2_hdr *rcv_hdr = (struct smb2_hdr *)buf;
|
||||
struct smb2_hdr *rcv_hdr = smb2_get_msg(buf);
|
||||
char *all_bytes_msg = (char *)&rcv_hdr->ProtocolId;
|
||||
int msg_size = be32_to_cpu(rcv_hdr->smb2_buf_length);
|
||||
int msg_size = get_rfc1002_len(buf);
|
||||
struct ksmbd_crypto_ctx *ctx = NULL;
|
||||
|
||||
if (conn->preauth_info->Preauth_HashId !=
|
||||
@@ -961,13 +995,16 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ksmbd_get_encryption_key(struct ksmbd_conn *conn, __u64 ses_id,
|
||||
static int ksmbd_get_encryption_key(struct ksmbd_work *work, __u64 ses_id,
|
||||
int enc, u8 *key)
|
||||
{
|
||||
struct ksmbd_session *sess;
|
||||
u8 *ses_enc_key;
|
||||
|
||||
sess = ksmbd_session_lookup_all(conn, ses_id);
|
||||
if (enc)
|
||||
sess = work->sess;
|
||||
else
|
||||
sess = ksmbd_session_lookup_all(work->conn, ses_id);
|
||||
if (!sess)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -994,12 +1031,16 @@ static struct scatterlist *ksmbd_init_sg(struct kvec *iov, unsigned int nvec,
|
||||
u8 *sign)
|
||||
{
|
||||
struct scatterlist *sg;
|
||||
unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 24;
|
||||
int i, nr_entries[3] = {0}, total_entries = 0, sg_idx = 0;
|
||||
unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
|
||||
int i, *nr_entries, total_entries = 0, sg_idx = 0;
|
||||
|
||||
if (!nvec)
|
||||
return NULL;
|
||||
|
||||
nr_entries = kcalloc(nvec, sizeof(int), GFP_KERNEL);
|
||||
if (!nr_entries)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < nvec - 1; i++) {
|
||||
unsigned long kaddr = (unsigned long)iov[i + 1].iov_base;
|
||||
|
||||
@@ -1017,8 +1058,10 @@ static struct scatterlist *ksmbd_init_sg(struct kvec *iov, unsigned int nvec,
|
||||
total_entries += 2;
|
||||
|
||||
sg = kmalloc_array(total_entries, sizeof(struct scatterlist), GFP_KERNEL);
|
||||
if (!sg)
|
||||
if (!sg) {
|
||||
kfree(nr_entries);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sg_init_table(sg, total_entries);
|
||||
smb2_sg_set_buf(&sg[sg_idx++], iov[0].iov_base + 24, assoc_data_len);
|
||||
@@ -1052,15 +1095,16 @@ static struct scatterlist *ksmbd_init_sg(struct kvec *iov, unsigned int nvec,
|
||||
}
|
||||
}
|
||||
smb2_sg_set_buf(&sg[sg_idx], sign, SMB2_SIGNATURE_SIZE);
|
||||
kfree(nr_entries);
|
||||
return sg;
|
||||
}
|
||||
|
||||
int ksmbd_crypt_message(struct ksmbd_conn *conn, struct kvec *iov,
|
||||
int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov,
|
||||
unsigned int nvec, int enc)
|
||||
{
|
||||
struct smb2_transform_hdr *tr_hdr =
|
||||
(struct smb2_transform_hdr *)iov[0].iov_base;
|
||||
unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 24;
|
||||
struct ksmbd_conn *conn = work->conn;
|
||||
struct smb2_transform_hdr *tr_hdr = smb2_get_msg(iov[0].iov_base);
|
||||
unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
|
||||
int rc;
|
||||
struct scatterlist *sg;
|
||||
u8 sign[SMB2_SIGNATURE_SIZE] = {};
|
||||
@@ -1072,7 +1116,7 @@ int ksmbd_crypt_message(struct ksmbd_conn *conn, struct kvec *iov,
|
||||
unsigned int crypt_len = le32_to_cpu(tr_hdr->OriginalMessageSize);
|
||||
struct ksmbd_crypto_ctx *ctx;
|
||||
|
||||
rc = ksmbd_get_encryption_key(conn,
|
||||
rc = ksmbd_get_encryption_key(work,
|
||||
le64_to_cpu(tr_hdr->SessionId),
|
||||
enc,
|
||||
key);
|
||||
|
||||
@@ -33,9 +33,10 @@
|
||||
|
||||
struct ksmbd_session;
|
||||
struct ksmbd_conn;
|
||||
struct ksmbd_work;
|
||||
struct kvec;
|
||||
|
||||
int ksmbd_crypt_message(struct ksmbd_conn *conn, struct kvec *iov,
|
||||
int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov,
|
||||
unsigned int nvec, int enc);
|
||||
void ksmbd_copy_gss_neg_header(void *buf);
|
||||
int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
|
||||
|
||||
@@ -20,7 +20,7 @@ static DEFINE_MUTEX(init_lock);
|
||||
static struct ksmbd_conn_ops default_conn_ops;
|
||||
|
||||
LIST_HEAD(conn_list);
|
||||
DEFINE_RWLOCK(conn_list_lock);
|
||||
DECLARE_RWSEM(conn_list_lock);
|
||||
|
||||
/**
|
||||
* ksmbd_conn_free() - free resources of the connection instance
|
||||
@@ -32,9 +32,9 @@ DEFINE_RWLOCK(conn_list_lock);
|
||||
*/
|
||||
void ksmbd_conn_free(struct ksmbd_conn *conn)
|
||||
{
|
||||
write_lock(&conn_list_lock);
|
||||
down_write(&conn_list_lock);
|
||||
list_del(&conn->conns_list);
|
||||
write_unlock(&conn_list_lock);
|
||||
up_write(&conn_list_lock);
|
||||
|
||||
xa_destroy(&conn->sessions);
|
||||
kvfree(conn->request_buf);
|
||||
@@ -56,16 +56,23 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
|
||||
return NULL;
|
||||
|
||||
conn->need_neg = true;
|
||||
conn->status = KSMBD_SESS_NEW;
|
||||
ksmbd_conn_set_new(conn);
|
||||
conn->local_nls = load_nls("utf8");
|
||||
if (!conn->local_nls)
|
||||
conn->local_nls = load_nls_default();
|
||||
if (IS_ENABLED(CONFIG_UNICODE))
|
||||
conn->um = utf8_load("12.1.0");
|
||||
else
|
||||
conn->um = ERR_PTR(-EOPNOTSUPP);
|
||||
if (IS_ERR(conn->um))
|
||||
conn->um = NULL;
|
||||
atomic_set(&conn->req_running, 0);
|
||||
atomic_set(&conn->r_count, 0);
|
||||
conn->total_credits = 1;
|
||||
conn->outstanding_credits = 0;
|
||||
|
||||
init_waitqueue_head(&conn->req_running_q);
|
||||
init_waitqueue_head(&conn->r_count_q);
|
||||
INIT_LIST_HEAD(&conn->conns_list);
|
||||
INIT_LIST_HEAD(&conn->requests);
|
||||
INIT_LIST_HEAD(&conn->async_requests);
|
||||
@@ -77,9 +84,11 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
|
||||
spin_lock_init(&conn->llist_lock);
|
||||
INIT_LIST_HEAD(&conn->lock_list);
|
||||
|
||||
write_lock(&conn_list_lock);
|
||||
init_rwsem(&conn->session_lock);
|
||||
|
||||
down_write(&conn_list_lock);
|
||||
list_add(&conn->conns_list, &conn_list);
|
||||
write_unlock(&conn_list_lock);
|
||||
up_write(&conn_list_lock);
|
||||
return conn;
|
||||
}
|
||||
|
||||
@@ -88,7 +97,7 @@ bool ksmbd_conn_lookup_dialect(struct ksmbd_conn *c)
|
||||
struct ksmbd_conn *t;
|
||||
bool ret = false;
|
||||
|
||||
read_lock(&conn_list_lock);
|
||||
down_read(&conn_list_lock);
|
||||
list_for_each_entry(t, &conn_list, conns_list) {
|
||||
if (memcmp(t->ClientGUID, c->ClientGUID, SMB2_CLIENT_GUID_SIZE))
|
||||
continue;
|
||||
@@ -96,7 +105,7 @@ bool ksmbd_conn_lookup_dialect(struct ksmbd_conn *c)
|
||||
ret = true;
|
||||
break;
|
||||
}
|
||||
read_unlock(&conn_list_lock);
|
||||
up_read(&conn_list_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -105,10 +114,8 @@ void ksmbd_conn_enqueue_request(struct ksmbd_work *work)
|
||||
struct ksmbd_conn *conn = work->conn;
|
||||
struct list_head *requests_queue = NULL;
|
||||
|
||||
if (conn->ops->get_cmd_val(work) != SMB2_CANCEL_HE) {
|
||||
if (conn->ops->get_cmd_val(work) != SMB2_CANCEL_HE)
|
||||
requests_queue = &conn->requests;
|
||||
work->syncronous = true;
|
||||
}
|
||||
|
||||
if (requests_queue) {
|
||||
atomic_inc(&conn->req_running);
|
||||
@@ -118,41 +125,47 @@ void ksmbd_conn_enqueue_request(struct ksmbd_work *work)
|
||||
}
|
||||
}
|
||||
|
||||
int ksmbd_conn_try_dequeue_request(struct ksmbd_work *work)
|
||||
void ksmbd_conn_try_dequeue_request(struct ksmbd_work *work)
|
||||
{
|
||||
struct ksmbd_conn *conn = work->conn;
|
||||
int ret = 1;
|
||||
|
||||
if (list_empty(&work->request_entry) &&
|
||||
list_empty(&work->async_request_entry))
|
||||
return 0;
|
||||
return;
|
||||
|
||||
if (!work->multiRsp)
|
||||
atomic_dec(&conn->req_running);
|
||||
atomic_dec(&conn->req_running);
|
||||
spin_lock(&conn->request_lock);
|
||||
if (!work->multiRsp) {
|
||||
list_del_init(&work->request_entry);
|
||||
if (work->syncronous == false)
|
||||
list_del_init(&work->async_request_entry);
|
||||
ret = 0;
|
||||
}
|
||||
list_del_init(&work->request_entry);
|
||||
spin_unlock(&conn->request_lock);
|
||||
if (work->asynchronous)
|
||||
release_async_work(work);
|
||||
|
||||
wake_up_all(&conn->req_running_q);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ksmbd_conn_lock(struct ksmbd_conn *conn)
|
||||
void ksmbd_conn_lock(struct ksmbd_conn *conn)
|
||||
{
|
||||
mutex_lock(&conn->srv_mutex);
|
||||
}
|
||||
|
||||
static void ksmbd_conn_unlock(struct ksmbd_conn *conn)
|
||||
void ksmbd_conn_unlock(struct ksmbd_conn *conn)
|
||||
{
|
||||
mutex_unlock(&conn->srv_mutex);
|
||||
}
|
||||
|
||||
void ksmbd_conn_wait_idle(struct ksmbd_conn *conn)
|
||||
void ksmbd_all_conn_set_status(u64 sess_id, u32 status)
|
||||
{
|
||||
struct ksmbd_conn *conn;
|
||||
|
||||
down_read(&conn_list_lock);
|
||||
list_for_each_entry(conn, &conn_list, conns_list) {
|
||||
if (conn->binding || xa_load(&conn->sessions, sess_id))
|
||||
WRITE_ONCE(conn->status, status);
|
||||
}
|
||||
up_read(&conn_list_lock);
|
||||
}
|
||||
|
||||
void ksmbd_conn_wait_idle(struct ksmbd_conn *conn, u64 sess_id)
|
||||
{
|
||||
wait_event(conn->req_running_q, atomic_read(&conn->req_running) < 2);
|
||||
}
|
||||
@@ -160,43 +173,25 @@ void ksmbd_conn_wait_idle(struct ksmbd_conn *conn)
|
||||
int ksmbd_conn_write(struct ksmbd_work *work)
|
||||
{
|
||||
struct ksmbd_conn *conn = work->conn;
|
||||
struct smb_hdr *rsp_hdr = work->response_buf;
|
||||
size_t len = 0;
|
||||
int sent;
|
||||
struct kvec iov[3];
|
||||
int iov_idx = 0;
|
||||
|
||||
ksmbd_conn_try_dequeue_request(work);
|
||||
if (!rsp_hdr) {
|
||||
if (!work->response_buf) {
|
||||
pr_err("NULL response header\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (work->tr_buf) {
|
||||
iov[iov_idx] = (struct kvec) { work->tr_buf,
|
||||
sizeof(struct smb2_transform_hdr) };
|
||||
len += iov[iov_idx++].iov_len;
|
||||
}
|
||||
if (work->send_no_response)
|
||||
return 0;
|
||||
|
||||
if (work->aux_payload_sz) {
|
||||
iov[iov_idx] = (struct kvec) { rsp_hdr, work->resp_hdr_sz };
|
||||
len += iov[iov_idx++].iov_len;
|
||||
iov[iov_idx] = (struct kvec) { work->aux_payload_buf, work->aux_payload_sz };
|
||||
len += iov[iov_idx++].iov_len;
|
||||
} else {
|
||||
if (work->tr_buf)
|
||||
iov[iov_idx].iov_len = work->resp_hdr_sz;
|
||||
else
|
||||
iov[iov_idx].iov_len = get_rfc1002_len(rsp_hdr) + 4;
|
||||
iov[iov_idx].iov_base = rsp_hdr;
|
||||
len += iov[iov_idx++].iov_len;
|
||||
}
|
||||
if (!work->iov_idx)
|
||||
return -EINVAL;
|
||||
|
||||
ksmbd_conn_lock(conn);
|
||||
sent = conn->transport->ops->writev(conn->transport, &iov[0],
|
||||
iov_idx, len,
|
||||
work->need_invalidate_rkey,
|
||||
work->remote_key);
|
||||
sent = conn->transport->ops->writev(conn->transport, work->iov,
|
||||
work->iov_cnt,
|
||||
get_rfc1002_len(work->iov[0].iov_base) + 4,
|
||||
work->need_invalidate_rkey,
|
||||
work->remote_key);
|
||||
ksmbd_conn_unlock(conn);
|
||||
|
||||
if (sent < 0) {
|
||||
@@ -207,31 +202,31 @@ int ksmbd_conn_write(struct ksmbd_work *work)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ksmbd_conn_rdma_read(struct ksmbd_conn *conn, void *buf,
|
||||
unsigned int buflen, u32 remote_key, u64 remote_offset,
|
||||
u32 remote_len)
|
||||
int ksmbd_conn_rdma_read(struct ksmbd_conn *conn,
|
||||
void *buf, unsigned int buflen,
|
||||
struct smb2_buffer_desc_v1 *desc,
|
||||
unsigned int desc_len)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (conn->transport->ops->rdma_read)
|
||||
ret = conn->transport->ops->rdma_read(conn->transport,
|
||||
buf, buflen,
|
||||
remote_key, remote_offset,
|
||||
remote_len);
|
||||
desc, desc_len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ksmbd_conn_rdma_write(struct ksmbd_conn *conn, void *buf,
|
||||
unsigned int buflen, u32 remote_key,
|
||||
u64 remote_offset, u32 remote_len)
|
||||
int ksmbd_conn_rdma_write(struct ksmbd_conn *conn,
|
||||
void *buf, unsigned int buflen,
|
||||
struct smb2_buffer_desc_v1 *desc,
|
||||
unsigned int desc_len)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (conn->transport->ops->rdma_write)
|
||||
ret = conn->transport->ops->rdma_write(conn->transport,
|
||||
buf, buflen,
|
||||
remote_key, remote_offset,
|
||||
remote_len);
|
||||
desc, desc_len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -240,7 +235,7 @@ bool ksmbd_conn_alive(struct ksmbd_conn *conn)
|
||||
if (!ksmbd_server_running())
|
||||
return false;
|
||||
|
||||
if (conn->status == KSMBD_SESS_EXITING)
|
||||
if (ksmbd_conn_exiting(conn))
|
||||
return false;
|
||||
|
||||
if (kthread_should_stop())
|
||||
@@ -263,6 +258,9 @@ bool ksmbd_conn_alive(struct ksmbd_conn *conn)
|
||||
return true;
|
||||
}
|
||||
|
||||
#define SMB1_MIN_SUPPORTED_HEADER_SIZE (sizeof(struct smb_hdr))
|
||||
#define SMB2_MIN_SUPPORTED_HEADER_SIZE (sizeof(struct smb2_hdr) + 4)
|
||||
|
||||
/**
|
||||
* ksmbd_conn_handler_loop() - session thread to listen on new smb requests
|
||||
* @p: connection instance
|
||||
@@ -300,16 +298,16 @@ int ksmbd_conn_handler_loop(void *p)
|
||||
pdu_size = get_rfc1002_len(hdr_buf);
|
||||
ksmbd_debug(CONN, "RFC1002 header %u bytes\n", pdu_size);
|
||||
|
||||
if (conn->status == KSMBD_SESS_GOOD)
|
||||
if (ksmbd_conn_good(conn))
|
||||
max_allowed_pdu_size =
|
||||
SMB3_MAX_MSGSIZE + conn->vals->max_write_size;
|
||||
else
|
||||
max_allowed_pdu_size = SMB3_MAX_MSGSIZE;
|
||||
|
||||
if (pdu_size > max_allowed_pdu_size) {
|
||||
pr_err_ratelimited("PDU length(%u) excceed maximum allowed pdu size(%u) on connection(%d)\n",
|
||||
pr_err_ratelimited("PDU length(%u) exceeded maximum allowed pdu size(%u) on connection(%d)\n",
|
||||
pdu_size, max_allowed_pdu_size,
|
||||
conn->status);
|
||||
READ_ONCE(conn->status));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -319,6 +317,9 @@ int ksmbd_conn_handler_loop(void *p)
|
||||
if (pdu_size > MAX_STREAM_PROT_LEN)
|
||||
break;
|
||||
|
||||
if (pdu_size < SMB1_MIN_SUPPORTED_HEADER_SIZE)
|
||||
break;
|
||||
|
||||
/* 4 for rfc1002 length field */
|
||||
/* 1 for implied bcc[0] */
|
||||
size = pdu_size + 4 + 1;
|
||||
@@ -327,8 +328,6 @@ int ksmbd_conn_handler_loop(void *p)
|
||||
break;
|
||||
|
||||
memcpy(conn->request_buf, hdr_buf, sizeof(hdr_buf));
|
||||
if (!ksmbd_smb_request(conn))
|
||||
break;
|
||||
|
||||
/*
|
||||
* We already read 4 bytes to find out PDU size, now
|
||||
@@ -346,6 +345,15 @@ int ksmbd_conn_handler_loop(void *p)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ksmbd_smb_request(conn))
|
||||
break;
|
||||
|
||||
if (((struct smb2_hdr *)smb2_get_msg(conn->request_buf))->ProtocolId ==
|
||||
SMB2_PROTO_NUMBER) {
|
||||
if (pdu_size < SMB2_MIN_SUPPORTED_HEADER_SIZE)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!default_conn_ops.process_fn) {
|
||||
pr_err("No connection request callback\n");
|
||||
break;
|
||||
@@ -358,10 +366,12 @@ int ksmbd_conn_handler_loop(void *p)
|
||||
}
|
||||
|
||||
out:
|
||||
ksmbd_conn_set_releasing(conn);
|
||||
/* Wait till all reference dropped to the Server object*/
|
||||
while (atomic_read(&conn->r_count) > 0)
|
||||
schedule_timeout(HZ);
|
||||
wait_event(conn->r_count_q, atomic_read(&conn->r_count) == 0);
|
||||
|
||||
if (IS_ENABLED(CONFIG_UNICODE))
|
||||
utf8_unload(conn->um);
|
||||
unload_nls(conn->local_nls);
|
||||
if (default_conn_ops.terminate_fn)
|
||||
default_conn_ops.terminate_fn(conn);
|
||||
@@ -400,19 +410,26 @@ out:
|
||||
static void stop_sessions(void)
|
||||
{
|
||||
struct ksmbd_conn *conn;
|
||||
struct ksmbd_transport *t;
|
||||
|
||||
again:
|
||||
read_lock(&conn_list_lock);
|
||||
down_read(&conn_list_lock);
|
||||
list_for_each_entry(conn, &conn_list, conns_list) {
|
||||
struct task_struct *task;
|
||||
|
||||
task = conn->transport->handler;
|
||||
t = conn->transport;
|
||||
task = t->handler;
|
||||
if (task)
|
||||
ksmbd_debug(CONN, "Stop session handler %s/%d\n",
|
||||
task->comm, task_pid_nr(task));
|
||||
conn->status = KSMBD_SESS_EXITING;
|
||||
ksmbd_conn_set_exiting(conn);
|
||||
if (t->ops->shutdown) {
|
||||
up_read(&conn_list_lock);
|
||||
t->ops->shutdown(t);
|
||||
down_read(&conn_list_lock);
|
||||
}
|
||||
}
|
||||
read_unlock(&conn_list_lock);
|
||||
up_read(&conn_list_lock);
|
||||
|
||||
if (!list_empty(&conn_list)) {
|
||||
schedule_timeout_interruptible(HZ / 10); /* 100ms */
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <net/request_sock.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/nls.h>
|
||||
#include <linux/unicode.h>
|
||||
|
||||
#include "smb_common.h"
|
||||
#include "ksmbd_work.h"
|
||||
@@ -25,7 +26,8 @@ enum {
|
||||
KSMBD_SESS_GOOD,
|
||||
KSMBD_SESS_EXITING,
|
||||
KSMBD_SESS_NEED_RECONNECT,
|
||||
KSMBD_SESS_NEED_NEGOTIATE
|
||||
KSMBD_SESS_NEED_NEGOTIATE,
|
||||
KSMBD_SESS_RELEASING
|
||||
};
|
||||
|
||||
struct ksmbd_stats {
|
||||
@@ -46,7 +48,9 @@ struct ksmbd_conn {
|
||||
char *request_buf;
|
||||
struct ksmbd_transport *transport;
|
||||
struct nls_table *local_nls;
|
||||
struct unicode_map *um;
|
||||
struct list_head conns_list;
|
||||
struct rw_semaphore session_lock;
|
||||
/* smb session 1 per user */
|
||||
struct xarray sessions;
|
||||
unsigned long last_active;
|
||||
@@ -58,6 +62,7 @@ struct ksmbd_conn {
|
||||
unsigned int outstanding_credits;
|
||||
spinlock_t credits_lock;
|
||||
wait_queue_head_t req_running_q;
|
||||
wait_queue_head_t r_count_q;
|
||||
/* Lock to protect requests list*/
|
||||
spinlock_t request_lock;
|
||||
struct list_head requests;
|
||||
@@ -110,16 +115,20 @@ struct ksmbd_conn_ops {
|
||||
struct ksmbd_transport_ops {
|
||||
int (*prepare)(struct ksmbd_transport *t);
|
||||
void (*disconnect)(struct ksmbd_transport *t);
|
||||
void (*shutdown)(struct ksmbd_transport *t);
|
||||
int (*read)(struct ksmbd_transport *t, char *buf,
|
||||
unsigned int size, int max_retries);
|
||||
int (*writev)(struct ksmbd_transport *t, struct kvec *iovs, int niov,
|
||||
int size, bool need_invalidate_rkey,
|
||||
unsigned int remote_key);
|
||||
int (*rdma_read)(struct ksmbd_transport *t, void *buf, unsigned int len,
|
||||
u32 remote_key, u64 remote_offset, u32 remote_len);
|
||||
int (*rdma_write)(struct ksmbd_transport *t, void *buf,
|
||||
unsigned int len, u32 remote_key, u64 remote_offset,
|
||||
u32 remote_len);
|
||||
int (*rdma_read)(struct ksmbd_transport *t,
|
||||
void *buf, unsigned int len,
|
||||
struct smb2_buffer_desc_v1 *desc,
|
||||
unsigned int desc_len);
|
||||
int (*rdma_write)(struct ksmbd_transport *t,
|
||||
void *buf, unsigned int len,
|
||||
struct smb2_buffer_desc_v1 *desc,
|
||||
unsigned int desc_len);
|
||||
};
|
||||
|
||||
struct ksmbd_transport {
|
||||
@@ -133,26 +142,30 @@ struct ksmbd_transport {
|
||||
#define KSMBD_TCP_PEER_SOCKADDR(c) ((struct sockaddr *)&((c)->peer_addr))
|
||||
|
||||
extern struct list_head conn_list;
|
||||
extern rwlock_t conn_list_lock;
|
||||
extern struct rw_semaphore conn_list_lock;
|
||||
|
||||
bool ksmbd_conn_alive(struct ksmbd_conn *conn);
|
||||
void ksmbd_conn_wait_idle(struct ksmbd_conn *conn);
|
||||
void ksmbd_conn_wait_idle(struct ksmbd_conn *conn, u64 sess_id);
|
||||
struct ksmbd_conn *ksmbd_conn_alloc(void);
|
||||
void ksmbd_conn_free(struct ksmbd_conn *conn);
|
||||
bool ksmbd_conn_lookup_dialect(struct ksmbd_conn *c);
|
||||
int ksmbd_conn_write(struct ksmbd_work *work);
|
||||
int ksmbd_conn_rdma_read(struct ksmbd_conn *conn, void *buf,
|
||||
unsigned int buflen, u32 remote_key, u64 remote_offset,
|
||||
u32 remote_len);
|
||||
int ksmbd_conn_rdma_write(struct ksmbd_conn *conn, void *buf,
|
||||
unsigned int buflen, u32 remote_key, u64 remote_offset,
|
||||
u32 remote_len);
|
||||
int ksmbd_conn_rdma_read(struct ksmbd_conn *conn,
|
||||
void *buf, unsigned int buflen,
|
||||
struct smb2_buffer_desc_v1 *desc,
|
||||
unsigned int desc_len);
|
||||
int ksmbd_conn_rdma_write(struct ksmbd_conn *conn,
|
||||
void *buf, unsigned int buflen,
|
||||
struct smb2_buffer_desc_v1 *desc,
|
||||
unsigned int desc_len);
|
||||
void ksmbd_conn_enqueue_request(struct ksmbd_work *work);
|
||||
int ksmbd_conn_try_dequeue_request(struct ksmbd_work *work);
|
||||
void ksmbd_conn_try_dequeue_request(struct ksmbd_work *work);
|
||||
void ksmbd_conn_init_server_callbacks(struct ksmbd_conn_ops *ops);
|
||||
int ksmbd_conn_handler_loop(void *p);
|
||||
int ksmbd_conn_transport_init(void);
|
||||
void ksmbd_conn_transport_destroy(void);
|
||||
void ksmbd_conn_lock(struct ksmbd_conn *conn);
|
||||
void ksmbd_conn_unlock(struct ksmbd_conn *conn);
|
||||
|
||||
/*
|
||||
* WARNING
|
||||
@@ -160,43 +173,60 @@ void ksmbd_conn_transport_destroy(void);
|
||||
* This is a hack. We will move status to a proper place once we land
|
||||
* a multi-sessions support.
|
||||
*/
|
||||
static inline bool ksmbd_conn_good(struct ksmbd_work *work)
|
||||
static inline bool ksmbd_conn_good(struct ksmbd_conn *conn)
|
||||
{
|
||||
return work->conn->status == KSMBD_SESS_GOOD;
|
||||
return READ_ONCE(conn->status) == KSMBD_SESS_GOOD;
|
||||
}
|
||||
|
||||
static inline bool ksmbd_conn_need_negotiate(struct ksmbd_work *work)
|
||||
static inline bool ksmbd_conn_need_negotiate(struct ksmbd_conn *conn)
|
||||
{
|
||||
return work->conn->status == KSMBD_SESS_NEED_NEGOTIATE;
|
||||
return READ_ONCE(conn->status) == KSMBD_SESS_NEED_NEGOTIATE;
|
||||
}
|
||||
|
||||
static inline bool ksmbd_conn_need_reconnect(struct ksmbd_work *work)
|
||||
static inline bool ksmbd_conn_need_reconnect(struct ksmbd_conn *conn)
|
||||
{
|
||||
return work->conn->status == KSMBD_SESS_NEED_RECONNECT;
|
||||
return READ_ONCE(conn->status) == KSMBD_SESS_NEED_RECONNECT;
|
||||
}
|
||||
|
||||
static inline bool ksmbd_conn_exiting(struct ksmbd_work *work)
|
||||
static inline bool ksmbd_conn_exiting(struct ksmbd_conn *conn)
|
||||
{
|
||||
return work->conn->status == KSMBD_SESS_EXITING;
|
||||
return READ_ONCE(conn->status) == KSMBD_SESS_EXITING;
|
||||
}
|
||||
|
||||
static inline void ksmbd_conn_set_good(struct ksmbd_work *work)
|
||||
static inline bool ksmbd_conn_releasing(struct ksmbd_conn *conn)
|
||||
{
|
||||
work->conn->status = KSMBD_SESS_GOOD;
|
||||
return READ_ONCE(conn->status) == KSMBD_SESS_RELEASING;
|
||||
}
|
||||
|
||||
static inline void ksmbd_conn_set_need_negotiate(struct ksmbd_work *work)
|
||||
static inline void ksmbd_conn_set_new(struct ksmbd_conn *conn)
|
||||
{
|
||||
work->conn->status = KSMBD_SESS_NEED_NEGOTIATE;
|
||||
WRITE_ONCE(conn->status, KSMBD_SESS_NEW);
|
||||
}
|
||||
|
||||
static inline void ksmbd_conn_set_need_reconnect(struct ksmbd_work *work)
|
||||
static inline void ksmbd_conn_set_good(struct ksmbd_conn *conn)
|
||||
{
|
||||
work->conn->status = KSMBD_SESS_NEED_RECONNECT;
|
||||
WRITE_ONCE(conn->status, KSMBD_SESS_GOOD);
|
||||
}
|
||||
|
||||
static inline void ksmbd_conn_set_exiting(struct ksmbd_work *work)
|
||||
static inline void ksmbd_conn_set_need_negotiate(struct ksmbd_conn *conn)
|
||||
{
|
||||
work->conn->status = KSMBD_SESS_EXITING;
|
||||
WRITE_ONCE(conn->status, KSMBD_SESS_NEED_NEGOTIATE);
|
||||
}
|
||||
|
||||
static inline void ksmbd_conn_set_need_reconnect(struct ksmbd_conn *conn)
|
||||
{
|
||||
WRITE_ONCE(conn->status, KSMBD_SESS_NEED_RECONNECT);
|
||||
}
|
||||
|
||||
static inline void ksmbd_conn_set_exiting(struct ksmbd_conn *conn)
|
||||
{
|
||||
WRITE_ONCE(conn->status, KSMBD_SESS_EXITING);
|
||||
}
|
||||
|
||||
static inline void ksmbd_conn_set_releasing(struct ksmbd_conn *conn)
|
||||
{
|
||||
WRITE_ONCE(conn->status, KSMBD_SESS_RELEASING);
|
||||
}
|
||||
|
||||
void ksmbd_all_conn_set_status(u64 sess_id, u32 status);
|
||||
#endif /* __CONNECTION_H__ */
|
||||
|
||||
@@ -74,6 +74,7 @@ struct ksmbd_heartbeat {
|
||||
#define KSMBD_GLOBAL_FLAG_SMB2_LEASES BIT(0)
|
||||
#define KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION BIT(1)
|
||||
#define KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL BIT(2)
|
||||
#define KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION_OFF BIT(3)
|
||||
|
||||
/*
|
||||
* IPC request for ksmbd server startup
|
||||
@@ -164,7 +165,8 @@ struct ksmbd_share_config_response {
|
||||
__u16 force_directory_mode;
|
||||
__u16 force_uid;
|
||||
__u16 force_gid;
|
||||
__u32 reserved[128]; /* Reserved room */
|
||||
__s8 share_name[KSMBD_REQ_MAX_SHARE_NAME];
|
||||
__u32 reserved[112]; /* Reserved room */
|
||||
__u32 veto_list_sz;
|
||||
__s8 ____payload[];
|
||||
};
|
||||
@@ -350,6 +352,8 @@ enum KSMBD_TREE_CONN_STATUS {
|
||||
#define KSMBD_SHARE_FLAG_STREAMS BIT(11)
|
||||
#define KSMBD_SHARE_FLAG_FOLLOW_SYMLINKS BIT(12)
|
||||
#define KSMBD_SHARE_FLAG_ACL_XATTR BIT(13)
|
||||
#define KSMBD_SHARE_FLAG_UPDATE BIT(14)
|
||||
#define KSMBD_SHARE_FLAG_CROSSMNT BIT(15)
|
||||
|
||||
/*
|
||||
* Tree connect request flags.
|
||||
@@ -365,6 +369,7 @@ enum KSMBD_TREE_CONN_STATUS {
|
||||
#define KSMBD_TREE_CONN_FLAG_READ_ONLY BIT(1)
|
||||
#define KSMBD_TREE_CONN_FLAG_WRITABLE BIT(2)
|
||||
#define KSMBD_TREE_CONN_FLAG_ADMIN_ACCOUNT BIT(3)
|
||||
#define KSMBD_TREE_CONN_FLAG_UPDATE BIT(4)
|
||||
|
||||
/*
|
||||
* RPC over IPC.
|
||||
|
||||
@@ -27,18 +27,38 @@ struct ksmbd_work *ksmbd_alloc_work_struct(void)
|
||||
INIT_LIST_HEAD(&work->async_request_entry);
|
||||
INIT_LIST_HEAD(&work->fp_entry);
|
||||
INIT_LIST_HEAD(&work->interim_entry);
|
||||
INIT_LIST_HEAD(&work->aux_read_list);
|
||||
work->iov_alloc_cnt = 4;
|
||||
work->iov = kcalloc(work->iov_alloc_cnt, sizeof(struct kvec),
|
||||
GFP_KERNEL);
|
||||
if (!work->iov) {
|
||||
kmem_cache_free(work_cache, work);
|
||||
work = NULL;
|
||||
}
|
||||
}
|
||||
return work;
|
||||
}
|
||||
|
||||
void ksmbd_free_work_struct(struct ksmbd_work *work)
|
||||
{
|
||||
struct aux_read *ar, *tmp;
|
||||
|
||||
WARN_ON(work->saved_cred != NULL);
|
||||
|
||||
kvfree(work->response_buf);
|
||||
kvfree(work->aux_payload_buf);
|
||||
|
||||
list_for_each_entry_safe(ar, tmp, &work->aux_read_list, entry) {
|
||||
kvfree(ar->buf);
|
||||
list_del(&ar->entry);
|
||||
kfree(ar);
|
||||
}
|
||||
|
||||
kfree(work->tr_buf);
|
||||
kvfree(work->request_buf);
|
||||
kfree(work->iov);
|
||||
if (!list_empty(&work->interim_entry))
|
||||
list_del(&work->interim_entry);
|
||||
|
||||
if (work->async_id)
|
||||
ksmbd_release_id(&work->conn->async_ida, work->async_id);
|
||||
kmem_cache_free(work_cache, work);
|
||||
@@ -69,7 +89,6 @@ int ksmbd_workqueue_init(void)
|
||||
|
||||
void ksmbd_workqueue_destroy(void)
|
||||
{
|
||||
flush_workqueue(ksmbd_wq);
|
||||
destroy_workqueue(ksmbd_wq);
|
||||
ksmbd_wq = NULL;
|
||||
}
|
||||
@@ -78,3 +97,81 @@ bool ksmbd_queue_work(struct ksmbd_work *work)
|
||||
{
|
||||
return queue_work(ksmbd_wq, &work->work);
|
||||
}
|
||||
|
||||
static inline void __ksmbd_iov_pin(struct ksmbd_work *work, void *ib,
|
||||
unsigned int ib_len)
|
||||
{
|
||||
work->iov[++work->iov_idx].iov_base = ib;
|
||||
work->iov[work->iov_idx].iov_len = ib_len;
|
||||
work->iov_cnt++;
|
||||
}
|
||||
|
||||
static int __ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len,
|
||||
void *aux_buf, unsigned int aux_size)
|
||||
{
|
||||
struct aux_read *ar = NULL;
|
||||
int need_iov_cnt = 1;
|
||||
|
||||
if (aux_size) {
|
||||
need_iov_cnt++;
|
||||
ar = kmalloc(sizeof(struct aux_read), GFP_KERNEL);
|
||||
if (!ar)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (work->iov_alloc_cnt < work->iov_cnt + need_iov_cnt) {
|
||||
struct kvec *new;
|
||||
|
||||
work->iov_alloc_cnt += 4;
|
||||
new = krealloc(work->iov,
|
||||
sizeof(struct kvec) * work->iov_alloc_cnt,
|
||||
GFP_KERNEL | __GFP_ZERO);
|
||||
if (!new) {
|
||||
kfree(ar);
|
||||
work->iov_alloc_cnt -= 4;
|
||||
return -ENOMEM;
|
||||
}
|
||||
work->iov = new;
|
||||
}
|
||||
|
||||
/* Plus rfc_length size on first iov */
|
||||
if (!work->iov_idx) {
|
||||
work->iov[work->iov_idx].iov_base = work->response_buf;
|
||||
*(__be32 *)work->iov[0].iov_base = 0;
|
||||
work->iov[work->iov_idx].iov_len = 4;
|
||||
work->iov_cnt++;
|
||||
}
|
||||
|
||||
__ksmbd_iov_pin(work, ib, len);
|
||||
inc_rfc1001_len(work->iov[0].iov_base, len);
|
||||
|
||||
if (aux_size) {
|
||||
__ksmbd_iov_pin(work, aux_buf, aux_size);
|
||||
inc_rfc1001_len(work->iov[0].iov_base, aux_size);
|
||||
|
||||
ar->buf = aux_buf;
|
||||
list_add(&ar->entry, &work->aux_read_list);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len)
|
||||
{
|
||||
return __ksmbd_iov_pin_rsp(work, ib, len, NULL, 0);
|
||||
}
|
||||
|
||||
int ksmbd_iov_pin_rsp_read(struct ksmbd_work *work, void *ib, int len,
|
||||
void *aux_buf, unsigned int aux_size)
|
||||
{
|
||||
return __ksmbd_iov_pin_rsp(work, ib, len, aux_buf, aux_size);
|
||||
}
|
||||
|
||||
int allocate_interim_rsp_buf(struct ksmbd_work *work)
|
||||
{
|
||||
work->response_buf = kzalloc(MAX_CIFS_SMALL_BUFFER_SIZE, GFP_KERNEL);
|
||||
if (!work->response_buf)
|
||||
return -ENOMEM;
|
||||
work->response_sz = MAX_CIFS_SMALL_BUFFER_SIZE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,11 @@ enum {
|
||||
KSMBD_WORK_CLOSED,
|
||||
};
|
||||
|
||||
struct aux_read {
|
||||
void *buf;
|
||||
struct list_head entry;
|
||||
};
|
||||
|
||||
/* one of these for every pending CIFS request at the connection */
|
||||
struct ksmbd_work {
|
||||
/* Server corresponding to this mid */
|
||||
@@ -31,13 +36,19 @@ struct ksmbd_work {
|
||||
/* Response buffer */
|
||||
void *response_buf;
|
||||
|
||||
/* Read data buffer */
|
||||
void *aux_payload_buf;
|
||||
struct list_head aux_read_list;
|
||||
|
||||
struct kvec *iov;
|
||||
int iov_alloc_cnt;
|
||||
int iov_cnt;
|
||||
int iov_idx;
|
||||
|
||||
/* Next cmd hdr in compound req buf*/
|
||||
int next_smb2_rcv_hdr_off;
|
||||
/* Next cmd hdr in compound rsp buf*/
|
||||
int next_smb2_rsp_hdr_off;
|
||||
/* Current cmd hdr in compound rsp buf*/
|
||||
int curr_smb2_rsp_hdr_off;
|
||||
|
||||
/*
|
||||
* Current Local FID assigned compound response if SMB2 CREATE
|
||||
@@ -53,22 +64,17 @@ struct ksmbd_work {
|
||||
unsigned int credits_granted;
|
||||
|
||||
/* response smb header size */
|
||||
unsigned int resp_hdr_sz;
|
||||
unsigned int response_sz;
|
||||
/* Read data count */
|
||||
unsigned int aux_payload_sz;
|
||||
|
||||
void *tr_buf;
|
||||
|
||||
unsigned char state;
|
||||
/* Multiple responses for one request e.g. SMB ECHO */
|
||||
bool multiRsp:1;
|
||||
/* No response for cancelled request */
|
||||
bool send_no_response:1;
|
||||
/* Request is encrypted */
|
||||
bool encrypted:1;
|
||||
/* Is this SYNC or ASYNC ksmbd_work */
|
||||
bool syncronous:1;
|
||||
bool asynchronous:1;
|
||||
bool need_invalidate_rkey:1;
|
||||
|
||||
unsigned int remote_key;
|
||||
@@ -92,7 +98,16 @@ struct ksmbd_work {
|
||||
*/
|
||||
static inline void *ksmbd_resp_buf_next(struct ksmbd_work *work)
|
||||
{
|
||||
return work->response_buf + work->next_smb2_rsp_hdr_off;
|
||||
return work->response_buf + work->next_smb2_rsp_hdr_off + 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* ksmbd_resp_buf_curr - Get current buffer on compound response.
|
||||
* @work: smb work containing response buffer
|
||||
*/
|
||||
static inline void *ksmbd_resp_buf_curr(struct ksmbd_work *work)
|
||||
{
|
||||
return work->response_buf + work->curr_smb2_rsp_hdr_off + 4;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,7 +116,7 @@ static inline void *ksmbd_resp_buf_next(struct ksmbd_work *work)
|
||||
*/
|
||||
static inline void *ksmbd_req_buf_next(struct ksmbd_work *work)
|
||||
{
|
||||
return work->request_buf + work->next_smb2_rcv_hdr_off;
|
||||
return work->request_buf + work->next_smb2_rcv_hdr_off + 4;
|
||||
}
|
||||
|
||||
struct ksmbd_work *ksmbd_alloc_work_struct(void);
|
||||
@@ -113,5 +128,8 @@ int ksmbd_work_pool_init(void);
|
||||
int ksmbd_workqueue_init(void);
|
||||
void ksmbd_workqueue_destroy(void);
|
||||
bool ksmbd_queue_work(struct ksmbd_work *work);
|
||||
|
||||
int ksmbd_iov_pin_rsp_read(struct ksmbd_work *work, void *ib, int len,
|
||||
void *aux_buf, unsigned int aux_size);
|
||||
int ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len);
|
||||
int allocate_interim_rsp_buf(struct ksmbd_work *work);
|
||||
#endif /* __KSMBD_WORK_H__ */
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "user_config.h"
|
||||
#include "user_session.h"
|
||||
#include "../transport_ipc.h"
|
||||
#include "../misc.h"
|
||||
|
||||
#define SHARE_HASH_BITS 3
|
||||
static DEFINE_HASHTABLE(shares_table, SHARE_HASH_BITS);
|
||||
@@ -26,7 +27,7 @@ struct ksmbd_veto_pattern {
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
static unsigned int share_name_hash(char *name)
|
||||
static unsigned int share_name_hash(const char *name)
|
||||
{
|
||||
return jhash(name, strlen(name), 0);
|
||||
}
|
||||
@@ -51,12 +52,16 @@ static void kill_share(struct ksmbd_share_config *share)
|
||||
kfree(share);
|
||||
}
|
||||
|
||||
void __ksmbd_share_config_put(struct ksmbd_share_config *share)
|
||||
void ksmbd_share_config_del(struct ksmbd_share_config *share)
|
||||
{
|
||||
down_write(&shares_table_lock);
|
||||
hash_del(&share->hlist);
|
||||
up_write(&shares_table_lock);
|
||||
}
|
||||
|
||||
void __ksmbd_share_config_put(struct ksmbd_share_config *share)
|
||||
{
|
||||
ksmbd_share_config_del(share);
|
||||
kill_share(share);
|
||||
}
|
||||
|
||||
@@ -68,7 +73,7 @@ __get_share_config(struct ksmbd_share_config *share)
|
||||
return share;
|
||||
}
|
||||
|
||||
static struct ksmbd_share_config *__share_lookup(char *name)
|
||||
static struct ksmbd_share_config *__share_lookup(const char *name)
|
||||
{
|
||||
struct ksmbd_share_config *share;
|
||||
unsigned int key = share_name_hash(name);
|
||||
@@ -115,7 +120,8 @@ static int parse_veto_list(struct ksmbd_share_config *share,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ksmbd_share_config *share_config_request(char *name)
|
||||
static struct ksmbd_share_config *share_config_request(struct unicode_map *um,
|
||||
const char *name)
|
||||
{
|
||||
struct ksmbd_share_config_response *resp;
|
||||
struct ksmbd_share_config *share = NULL;
|
||||
@@ -129,6 +135,19 @@ static struct ksmbd_share_config *share_config_request(char *name)
|
||||
if (resp->flags == KSMBD_SHARE_FLAG_INVALID)
|
||||
goto out;
|
||||
|
||||
if (*resp->share_name) {
|
||||
char *cf_resp_name;
|
||||
bool equal;
|
||||
|
||||
cf_resp_name = ksmbd_casefold_sharename(um, resp->share_name);
|
||||
if (IS_ERR(cf_resp_name))
|
||||
goto out;
|
||||
equal = !strcmp(cf_resp_name, name);
|
||||
kfree(cf_resp_name);
|
||||
if (!equal)
|
||||
goto out;
|
||||
}
|
||||
|
||||
share = kzalloc(sizeof(struct ksmbd_share_config), GFP_KERNEL);
|
||||
if (!share)
|
||||
goto out;
|
||||
@@ -186,20 +205,11 @@ out:
|
||||
return share;
|
||||
}
|
||||
|
||||
static void strtolower(char *share_name)
|
||||
{
|
||||
while (*share_name) {
|
||||
*share_name = tolower(*share_name);
|
||||
share_name++;
|
||||
}
|
||||
}
|
||||
|
||||
struct ksmbd_share_config *ksmbd_share_config_get(char *name)
|
||||
struct ksmbd_share_config *ksmbd_share_config_get(struct unicode_map *um,
|
||||
const char *name)
|
||||
{
|
||||
struct ksmbd_share_config *share;
|
||||
|
||||
strtolower(name);
|
||||
|
||||
down_read(&shares_table_lock);
|
||||
share = __share_lookup(name);
|
||||
if (share)
|
||||
@@ -208,7 +218,7 @@ struct ksmbd_share_config *ksmbd_share_config_get(char *name)
|
||||
|
||||
if (share)
|
||||
return share;
|
||||
return share_config_request(name);
|
||||
return share_config_request(um, name);
|
||||
}
|
||||
|
||||
bool ksmbd_share_veto_filename(struct ksmbd_share_config *share,
|
||||
@@ -222,17 +232,3 @@ bool ksmbd_share_veto_filename(struct ksmbd_share_config *share,
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ksmbd_share_configs_cleanup(void)
|
||||
{
|
||||
struct ksmbd_share_config *share;
|
||||
struct hlist_node *tmp;
|
||||
int i;
|
||||
|
||||
down_write(&shares_table_lock);
|
||||
hash_for_each_safe(shares_table, i, tmp, share, hlist) {
|
||||
hash_del(&share->hlist);
|
||||
kill_share(share);
|
||||
}
|
||||
up_write(&shares_table_lock);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/hashtable.h>
|
||||
#include <linux/path.h>
|
||||
#include <linux/unicode.h>
|
||||
|
||||
struct ksmbd_share_config {
|
||||
char *name;
|
||||
@@ -33,29 +34,22 @@ struct ksmbd_share_config {
|
||||
#define KSMBD_SHARE_INVALID_UID ((__u16)-1)
|
||||
#define KSMBD_SHARE_INVALID_GID ((__u16)-1)
|
||||
|
||||
static inline int share_config_create_mode(struct ksmbd_share_config *share,
|
||||
umode_t posix_mode)
|
||||
static inline umode_t
|
||||
share_config_create_mode(struct ksmbd_share_config *share,
|
||||
umode_t posix_mode)
|
||||
{
|
||||
if (!share->force_create_mode) {
|
||||
if (!posix_mode)
|
||||
return share->create_mask;
|
||||
else
|
||||
return posix_mode & share->create_mask;
|
||||
}
|
||||
return share->force_create_mode & share->create_mask;
|
||||
umode_t mode = (posix_mode ?: (umode_t)-1) & share->create_mask;
|
||||
|
||||
return mode | share->force_create_mode;
|
||||
}
|
||||
|
||||
static inline int share_config_directory_mode(struct ksmbd_share_config *share,
|
||||
umode_t posix_mode)
|
||||
static inline umode_t
|
||||
share_config_directory_mode(struct ksmbd_share_config *share,
|
||||
umode_t posix_mode)
|
||||
{
|
||||
if (!share->force_directory_mode) {
|
||||
if (!posix_mode)
|
||||
return share->directory_mask;
|
||||
else
|
||||
return posix_mode & share->directory_mask;
|
||||
}
|
||||
umode_t mode = (posix_mode ?: (umode_t)-1) & share->directory_mask;
|
||||
|
||||
return share->force_directory_mode & share->directory_mask;
|
||||
return mode | share->force_directory_mode;
|
||||
}
|
||||
|
||||
static inline int test_share_config_flag(struct ksmbd_share_config *share,
|
||||
@@ -64,6 +58,7 @@ static inline int test_share_config_flag(struct ksmbd_share_config *share,
|
||||
return share->flags & flag;
|
||||
}
|
||||
|
||||
void ksmbd_share_config_del(struct ksmbd_share_config *share);
|
||||
void __ksmbd_share_config_put(struct ksmbd_share_config *share);
|
||||
|
||||
static inline void ksmbd_share_config_put(struct ksmbd_share_config *share)
|
||||
@@ -73,9 +68,8 @@ static inline void ksmbd_share_config_put(struct ksmbd_share_config *share)
|
||||
__ksmbd_share_config_put(share);
|
||||
}
|
||||
|
||||
struct ksmbd_share_config *ksmbd_share_config_get(char *name);
|
||||
struct ksmbd_share_config *ksmbd_share_config_get(struct unicode_map *um,
|
||||
const char *name);
|
||||
bool ksmbd_share_veto_filename(struct ksmbd_share_config *share,
|
||||
const char *filename);
|
||||
void ksmbd_share_configs_cleanup(void);
|
||||
|
||||
#endif /* __SHARE_CONFIG_MANAGEMENT_H__ */
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
struct ksmbd_tree_conn_status
|
||||
ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess,
|
||||
char *share_name)
|
||||
const char *share_name)
|
||||
{
|
||||
struct ksmbd_tree_conn_status status = {-ENOENT, NULL};
|
||||
struct ksmbd_tree_connect_response *resp = NULL;
|
||||
@@ -26,7 +26,7 @@ ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess,
|
||||
struct sockaddr *peer_addr;
|
||||
int ret;
|
||||
|
||||
sc = ksmbd_share_config_get(share_name);
|
||||
sc = ksmbd_share_config_get(conn->um, share_name);
|
||||
if (!sc)
|
||||
return status;
|
||||
|
||||
@@ -57,9 +57,26 @@ ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess,
|
||||
goto out_error;
|
||||
|
||||
tree_conn->flags = resp->connection_flags;
|
||||
if (test_tree_conn_flag(tree_conn, KSMBD_TREE_CONN_FLAG_UPDATE)) {
|
||||
struct ksmbd_share_config *new_sc;
|
||||
|
||||
ksmbd_share_config_del(sc);
|
||||
new_sc = ksmbd_share_config_get(conn->um, share_name);
|
||||
if (!new_sc) {
|
||||
pr_err("Failed to update stale share config\n");
|
||||
status.ret = -ESTALE;
|
||||
goto out_error;
|
||||
}
|
||||
ksmbd_share_config_put(sc);
|
||||
sc = new_sc;
|
||||
}
|
||||
|
||||
tree_conn->user = sess->user;
|
||||
tree_conn->share_conf = sc;
|
||||
tree_conn->t_state = TREE_NEW;
|
||||
status.tree_conn = tree_conn;
|
||||
atomic_set(&tree_conn->refcount, 1);
|
||||
init_waitqueue_head(&tree_conn->refcount_q);
|
||||
|
||||
ret = xa_err(xa_store(&sess->tree_conns, tree_conn->id, tree_conn,
|
||||
GFP_KERNEL));
|
||||
@@ -79,14 +96,33 @@ out_error:
|
||||
return status;
|
||||
}
|
||||
|
||||
void ksmbd_tree_connect_put(struct ksmbd_tree_connect *tcon)
|
||||
{
|
||||
/*
|
||||
* Checking waitqueue to releasing tree connect on
|
||||
* tree disconnect. waitqueue_active is safe because it
|
||||
* uses atomic operation for condition.
|
||||
*/
|
||||
if (!atomic_dec_return(&tcon->refcount) &&
|
||||
waitqueue_active(&tcon->refcount_q))
|
||||
wake_up(&tcon->refcount_q);
|
||||
}
|
||||
|
||||
int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess,
|
||||
struct ksmbd_tree_connect *tree_conn)
|
||||
{
|
||||
int ret;
|
||||
|
||||
write_lock(&sess->tree_conns_lock);
|
||||
xa_erase(&sess->tree_conns, tree_conn->id);
|
||||
write_unlock(&sess->tree_conns_lock);
|
||||
|
||||
if (!atomic_dec_and_test(&tree_conn->refcount))
|
||||
wait_event(tree_conn->refcount_q,
|
||||
atomic_read(&tree_conn->refcount) == 0);
|
||||
|
||||
ret = ksmbd_ipc_tree_disconnect_request(sess->id, tree_conn->id);
|
||||
ksmbd_release_tree_conn_id(sess, tree_conn->id);
|
||||
xa_erase(&sess->tree_conns, tree_conn->id);
|
||||
ksmbd_share_config_put(tree_conn->share_conf);
|
||||
kfree(tree_conn);
|
||||
return ret;
|
||||
@@ -95,18 +131,19 @@ int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess,
|
||||
struct ksmbd_tree_connect *ksmbd_tree_conn_lookup(struct ksmbd_session *sess,
|
||||
unsigned int id)
|
||||
{
|
||||
return xa_load(&sess->tree_conns, id);
|
||||
}
|
||||
struct ksmbd_tree_connect *tcon;
|
||||
|
||||
struct ksmbd_share_config *ksmbd_tree_conn_share(struct ksmbd_session *sess,
|
||||
unsigned int id)
|
||||
{
|
||||
struct ksmbd_tree_connect *tc;
|
||||
read_lock(&sess->tree_conns_lock);
|
||||
tcon = xa_load(&sess->tree_conns, id);
|
||||
if (tcon) {
|
||||
if (tcon->t_state != TREE_CONNECTED)
|
||||
tcon = NULL;
|
||||
else if (!atomic_inc_not_zero(&tcon->refcount))
|
||||
tcon = NULL;
|
||||
}
|
||||
read_unlock(&sess->tree_conns_lock);
|
||||
|
||||
tc = ksmbd_tree_conn_lookup(sess, id);
|
||||
if (tc)
|
||||
return tc->share_conf;
|
||||
return NULL;
|
||||
return tcon;
|
||||
}
|
||||
|
||||
int ksmbd_tree_conn_session_logoff(struct ksmbd_session *sess)
|
||||
@@ -115,8 +152,21 @@ int ksmbd_tree_conn_session_logoff(struct ksmbd_session *sess)
|
||||
struct ksmbd_tree_connect *tc;
|
||||
unsigned long id;
|
||||
|
||||
xa_for_each(&sess->tree_conns, id, tc)
|
||||
if (!sess)
|
||||
return -EINVAL;
|
||||
|
||||
xa_for_each(&sess->tree_conns, id, tc) {
|
||||
write_lock(&sess->tree_conns_lock);
|
||||
if (tc->t_state == TREE_DISCONNECTED) {
|
||||
write_unlock(&sess->tree_conns_lock);
|
||||
ret = -ENOENT;
|
||||
continue;
|
||||
}
|
||||
tc->t_state = TREE_DISCONNECTED;
|
||||
write_unlock(&sess->tree_conns_lock);
|
||||
|
||||
ret |= ksmbd_tree_conn_disconnect(sess, tc);
|
||||
}
|
||||
xa_destroy(&sess->tree_conns);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,12 @@ struct ksmbd_share_config;
|
||||
struct ksmbd_user;
|
||||
struct ksmbd_conn;
|
||||
|
||||
enum {
|
||||
TREE_NEW = 0,
|
||||
TREE_CONNECTED,
|
||||
TREE_DISCONNECTED
|
||||
};
|
||||
|
||||
struct ksmbd_tree_connect {
|
||||
int id;
|
||||
|
||||
@@ -25,6 +31,9 @@ struct ksmbd_tree_connect {
|
||||
|
||||
int maximal_access;
|
||||
bool posix_extensions;
|
||||
atomic_t refcount;
|
||||
wait_queue_head_t refcount_q;
|
||||
unsigned int t_state;
|
||||
};
|
||||
|
||||
struct ksmbd_tree_conn_status {
|
||||
@@ -42,7 +51,8 @@ struct ksmbd_session;
|
||||
|
||||
struct ksmbd_tree_conn_status
|
||||
ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess,
|
||||
char *share_name);
|
||||
const char *share_name);
|
||||
void ksmbd_tree_connect_put(struct ksmbd_tree_connect *tcon);
|
||||
|
||||
int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess,
|
||||
struct ksmbd_tree_connect *tree_conn);
|
||||
@@ -50,9 +60,6 @@ int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess,
|
||||
struct ksmbd_tree_connect *ksmbd_tree_conn_lookup(struct ksmbd_session *sess,
|
||||
unsigned int id);
|
||||
|
||||
struct ksmbd_share_config *ksmbd_tree_conn_share(struct ksmbd_session *sess,
|
||||
unsigned int id);
|
||||
|
||||
int ksmbd_tree_conn_session_logoff(struct ksmbd_session *sess);
|
||||
|
||||
#endif /* __TREE_CONNECT_MANAGEMENT_H__ */
|
||||
|
||||
@@ -18,7 +18,6 @@ struct ksmbd_user {
|
||||
|
||||
size_t passkey_sz;
|
||||
char *passkey;
|
||||
unsigned int failed_login_count;
|
||||
};
|
||||
|
||||
static inline bool user_guest(struct ksmbd_user *user)
|
||||
|
||||
@@ -25,20 +25,19 @@ static DECLARE_RWSEM(sessions_table_lock);
|
||||
struct ksmbd_session_rpc {
|
||||
int id;
|
||||
unsigned int method;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
static void free_channel_list(struct ksmbd_session *sess)
|
||||
{
|
||||
struct channel *chann, *tmp;
|
||||
struct channel *chann;
|
||||
unsigned long index;
|
||||
|
||||
write_lock(&sess->chann_lock);
|
||||
list_for_each_entry_safe(chann, tmp, &sess->ksmbd_chann_list,
|
||||
chann_list) {
|
||||
list_del(&chann->chann_list);
|
||||
xa_for_each(&sess->ksmbd_chann_list, index, chann) {
|
||||
xa_erase(&sess->ksmbd_chann_list, index);
|
||||
kfree(chann);
|
||||
}
|
||||
write_unlock(&sess->chann_lock);
|
||||
|
||||
xa_destroy(&sess->ksmbd_chann_list);
|
||||
}
|
||||
|
||||
static void __session_rpc_close(struct ksmbd_session *sess,
|
||||
@@ -58,15 +57,14 @@ static void __session_rpc_close(struct ksmbd_session *sess,
|
||||
static void ksmbd_session_rpc_clear_list(struct ksmbd_session *sess)
|
||||
{
|
||||
struct ksmbd_session_rpc *entry;
|
||||
long index;
|
||||
|
||||
while (!list_empty(&sess->rpc_handle_list)) {
|
||||
entry = list_entry(sess->rpc_handle_list.next,
|
||||
struct ksmbd_session_rpc,
|
||||
list);
|
||||
|
||||
list_del(&entry->list);
|
||||
xa_for_each(&sess->rpc_handle_list, index, entry) {
|
||||
xa_erase(&sess->rpc_handle_list, index);
|
||||
__session_rpc_close(sess, entry);
|
||||
}
|
||||
|
||||
xa_destroy(&sess->rpc_handle_list);
|
||||
}
|
||||
|
||||
static int __rpc_method(char *rpc_name)
|
||||
@@ -102,13 +100,13 @@ int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name)
|
||||
|
||||
entry = kzalloc(sizeof(struct ksmbd_session_rpc), GFP_KERNEL);
|
||||
if (!entry)
|
||||
return -EINVAL;
|
||||
return -ENOMEM;
|
||||
|
||||
list_add(&entry->list, &sess->rpc_handle_list);
|
||||
entry->method = method;
|
||||
entry->id = ksmbd_ipc_id_alloc();
|
||||
if (entry->id < 0)
|
||||
goto free_entry;
|
||||
xa_store(&sess->rpc_handle_list, entry->id, entry, GFP_KERNEL);
|
||||
|
||||
resp = ksmbd_rpc_open(sess, entry->id);
|
||||
if (!resp)
|
||||
@@ -117,9 +115,9 @@ int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name)
|
||||
kvfree(resp);
|
||||
return entry->id;
|
||||
free_id:
|
||||
xa_erase(&sess->rpc_handle_list, entry->id);
|
||||
ksmbd_rpc_id_free(entry->id);
|
||||
free_entry:
|
||||
list_del(&entry->list);
|
||||
kfree(entry);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -128,24 +126,17 @@ void ksmbd_session_rpc_close(struct ksmbd_session *sess, int id)
|
||||
{
|
||||
struct ksmbd_session_rpc *entry;
|
||||
|
||||
list_for_each_entry(entry, &sess->rpc_handle_list, list) {
|
||||
if (entry->id == id) {
|
||||
list_del(&entry->list);
|
||||
__session_rpc_close(sess, entry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
entry = xa_erase(&sess->rpc_handle_list, id);
|
||||
if (entry)
|
||||
__session_rpc_close(sess, entry);
|
||||
}
|
||||
|
||||
int ksmbd_session_rpc_method(struct ksmbd_session *sess, int id)
|
||||
{
|
||||
struct ksmbd_session_rpc *entry;
|
||||
|
||||
list_for_each_entry(entry, &sess->rpc_handle_list, list) {
|
||||
if (entry->id == id)
|
||||
return entry->method;
|
||||
}
|
||||
return 0;
|
||||
entry = xa_load(&sess->rpc_handle_list, id);
|
||||
return entry ? entry->method : 0;
|
||||
}
|
||||
|
||||
void ksmbd_session_destroy(struct ksmbd_session *sess)
|
||||
@@ -153,10 +144,6 @@ void ksmbd_session_destroy(struct ksmbd_session *sess)
|
||||
if (!sess)
|
||||
return;
|
||||
|
||||
down_write(&sessions_table_lock);
|
||||
hash_del(&sess->hlist);
|
||||
up_write(&sessions_table_lock);
|
||||
|
||||
if (sess->user)
|
||||
ksmbd_free_user(sess->user);
|
||||
|
||||
@@ -174,76 +161,105 @@ static struct ksmbd_session *__session_lookup(unsigned long long id)
|
||||
struct ksmbd_session *sess;
|
||||
|
||||
hash_for_each_possible(sessions_table, sess, hlist, id) {
|
||||
if (id == sess->id)
|
||||
if (id == sess->id) {
|
||||
sess->last_active = jiffies;
|
||||
return sess;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ksmbd_expire_session(struct ksmbd_conn *conn)
|
||||
{
|
||||
unsigned long id;
|
||||
struct ksmbd_session *sess;
|
||||
|
||||
down_write(&conn->session_lock);
|
||||
xa_for_each(&conn->sessions, id, sess) {
|
||||
if (sess->state != SMB2_SESSION_VALID ||
|
||||
time_after(jiffies,
|
||||
sess->last_active + SMB2_SESSION_TIMEOUT)) {
|
||||
xa_erase(&conn->sessions, sess->id);
|
||||
hash_del(&sess->hlist);
|
||||
ksmbd_session_destroy(sess);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
up_write(&conn->session_lock);
|
||||
}
|
||||
|
||||
int ksmbd_session_register(struct ksmbd_conn *conn,
|
||||
struct ksmbd_session *sess)
|
||||
{
|
||||
sess->dialect = conn->dialect;
|
||||
memcpy(sess->ClientGUID, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE);
|
||||
ksmbd_expire_session(conn);
|
||||
return xa_err(xa_store(&conn->sessions, sess->id, sess, GFP_KERNEL));
|
||||
}
|
||||
|
||||
static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess)
|
||||
{
|
||||
struct channel *chann, *tmp;
|
||||
struct channel *chann;
|
||||
|
||||
write_lock(&sess->chann_lock);
|
||||
list_for_each_entry_safe(chann, tmp, &sess->ksmbd_chann_list,
|
||||
chann_list) {
|
||||
if (chann->conn == conn) {
|
||||
list_del(&chann->chann_list);
|
||||
kfree(chann);
|
||||
write_unlock(&sess->chann_lock);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
write_unlock(&sess->chann_lock);
|
||||
chann = xa_erase(&sess->ksmbd_chann_list, (long)conn);
|
||||
if (!chann)
|
||||
return -ENOENT;
|
||||
|
||||
return -ENOENT;
|
||||
kfree(chann);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
|
||||
{
|
||||
struct ksmbd_session *sess;
|
||||
unsigned long id;
|
||||
|
||||
down_write(&sessions_table_lock);
|
||||
if (conn->binding) {
|
||||
int bkt;
|
||||
struct hlist_node *tmp;
|
||||
|
||||
down_write(&sessions_table_lock);
|
||||
hash_for_each(sessions_table, bkt, sess, hlist) {
|
||||
if (!ksmbd_chann_del(conn, sess)) {
|
||||
up_write(&sessions_table_lock);
|
||||
goto sess_destroy;
|
||||
hash_for_each_safe(sessions_table, bkt, tmp, sess, hlist) {
|
||||
if (!ksmbd_chann_del(conn, sess) &&
|
||||
xa_empty(&sess->ksmbd_chann_list)) {
|
||||
hash_del(&sess->hlist);
|
||||
ksmbd_session_destroy(sess);
|
||||
}
|
||||
}
|
||||
up_write(&sessions_table_lock);
|
||||
} else {
|
||||
unsigned long id;
|
||||
}
|
||||
up_write(&sessions_table_lock);
|
||||
|
||||
xa_for_each(&conn->sessions, id, sess) {
|
||||
if (!ksmbd_chann_del(conn, sess))
|
||||
goto sess_destroy;
|
||||
down_write(&conn->session_lock);
|
||||
xa_for_each(&conn->sessions, id, sess) {
|
||||
unsigned long chann_id;
|
||||
struct channel *chann;
|
||||
|
||||
xa_for_each(&sess->ksmbd_chann_list, chann_id, chann) {
|
||||
if (chann->conn != conn)
|
||||
ksmbd_conn_set_exiting(chann->conn);
|
||||
}
|
||||
|
||||
ksmbd_chann_del(conn, sess);
|
||||
if (xa_empty(&sess->ksmbd_chann_list)) {
|
||||
xa_erase(&conn->sessions, sess->id);
|
||||
hash_del(&sess->hlist);
|
||||
ksmbd_session_destroy(sess);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
sess_destroy:
|
||||
if (list_empty(&sess->ksmbd_chann_list)) {
|
||||
xa_erase(&conn->sessions, sess->id);
|
||||
ksmbd_session_destroy(sess);
|
||||
}
|
||||
up_write(&conn->session_lock);
|
||||
}
|
||||
|
||||
struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
|
||||
unsigned long long id)
|
||||
{
|
||||
return xa_load(&conn->sessions, id);
|
||||
struct ksmbd_session *sess;
|
||||
|
||||
down_read(&conn->session_lock);
|
||||
sess = xa_load(&conn->sessions, id);
|
||||
if (sess)
|
||||
sess->last_active = jiffies;
|
||||
up_read(&conn->session_lock);
|
||||
return sess;
|
||||
}
|
||||
|
||||
struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id)
|
||||
@@ -252,6 +268,8 @@ struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id)
|
||||
|
||||
down_read(&sessions_table_lock);
|
||||
sess = __session_lookup(id);
|
||||
if (sess)
|
||||
sess->last_active = jiffies;
|
||||
up_read(&sessions_table_lock);
|
||||
|
||||
return sess;
|
||||
@@ -320,6 +338,9 @@ static struct ksmbd_session *__session_create(int protocol)
|
||||
struct ksmbd_session *sess;
|
||||
int ret;
|
||||
|
||||
if (protocol != CIFDS_SESSION_FLAG_SMB2)
|
||||
return NULL;
|
||||
|
||||
sess = kzalloc(sizeof(struct ksmbd_session), GFP_KERNEL);
|
||||
if (!sess)
|
||||
return NULL;
|
||||
@@ -327,32 +348,25 @@ static struct ksmbd_session *__session_create(int protocol)
|
||||
if (ksmbd_init_file_table(&sess->file_table))
|
||||
goto error;
|
||||
|
||||
sess->last_active = jiffies;
|
||||
sess->state = SMB2_SESSION_IN_PROGRESS;
|
||||
set_session_flag(sess, protocol);
|
||||
xa_init(&sess->tree_conns);
|
||||
INIT_LIST_HEAD(&sess->ksmbd_chann_list);
|
||||
INIT_LIST_HEAD(&sess->rpc_handle_list);
|
||||
xa_init(&sess->ksmbd_chann_list);
|
||||
xa_init(&sess->rpc_handle_list);
|
||||
sess->sequence_number = 1;
|
||||
rwlock_init(&sess->chann_lock);
|
||||
|
||||
switch (protocol) {
|
||||
case CIFDS_SESSION_FLAG_SMB2:
|
||||
ret = __init_smb2_session(sess);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
rwlock_init(&sess->tree_conns_lock);
|
||||
|
||||
ret = __init_smb2_session(sess);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
ida_init(&sess->tree_conn_ida);
|
||||
|
||||
if (protocol == CIFDS_SESSION_FLAG_SMB2) {
|
||||
down_write(&sessions_table_lock);
|
||||
hash_add(sessions_table, &sess->hlist, sess->id);
|
||||
up_write(&sessions_table_lock);
|
||||
}
|
||||
down_write(&sessions_table_lock);
|
||||
hash_add(sessions_table, &sess->hlist, sess->id);
|
||||
up_write(&sessions_table_lock);
|
||||
|
||||
return sess;
|
||||
|
||||
error:
|
||||
|
||||
@@ -21,7 +21,6 @@ struct ksmbd_file_table;
|
||||
struct channel {
|
||||
__u8 smb3signingkey[SMB3_SIGN_KEY_SIZE];
|
||||
struct ksmbd_conn *conn;
|
||||
struct list_head chann_list;
|
||||
};
|
||||
|
||||
struct preauth_session {
|
||||
@@ -50,17 +49,18 @@ struct ksmbd_session {
|
||||
char sess_key[CIFS_KEY_SIZE];
|
||||
|
||||
struct hlist_node hlist;
|
||||
rwlock_t chann_lock;
|
||||
struct list_head ksmbd_chann_list;
|
||||
struct xarray ksmbd_chann_list;
|
||||
struct xarray tree_conns;
|
||||
struct ida tree_conn_ida;
|
||||
struct list_head rpc_handle_list;
|
||||
struct xarray rpc_handle_list;
|
||||
|
||||
__u8 smb3encryptionkey[SMB3_ENC_DEC_KEY_SIZE];
|
||||
__u8 smb3decryptionkey[SMB3_ENC_DEC_KEY_SIZE];
|
||||
__u8 smb3signingkey[SMB3_SIGN_KEY_SIZE];
|
||||
|
||||
struct ksmbd_file_table file_table;
|
||||
unsigned long last_active;
|
||||
rwlock_t tree_conns_lock;
|
||||
};
|
||||
|
||||
static inline int test_session_flag(struct ksmbd_session *sess, int bit)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/xattr.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/unicode.h>
|
||||
|
||||
#include "misc.h"
|
||||
#include "smb_common.h"
|
||||
@@ -20,7 +21,7 @@
|
||||
* wildcard '*' and '?'
|
||||
* TODO : implement consideration about DOS_DOT, DOS_QM and DOS_STAR
|
||||
*
|
||||
* @string: string to compare with a pattern
|
||||
* @str: string to compare with a pattern
|
||||
* @len: string length
|
||||
* @pattern: pattern string which might include wildcard '*' and '?'
|
||||
*
|
||||
@@ -152,25 +153,47 @@ out:
|
||||
/**
|
||||
* convert_to_nt_pathname() - extract and return windows path string
|
||||
* whose share directory prefix was removed from file path
|
||||
* @filename : unix filename
|
||||
* @sharepath: share path string
|
||||
* @share: ksmbd_share_config pointer
|
||||
* @path: path to report
|
||||
*
|
||||
* Return : windows path string or error
|
||||
*/
|
||||
|
||||
char *convert_to_nt_pathname(char *filename)
|
||||
char *convert_to_nt_pathname(struct ksmbd_share_config *share,
|
||||
const struct path *path)
|
||||
{
|
||||
char *ab_pathname;
|
||||
char *pathname, *ab_pathname, *nt_pathname;
|
||||
int share_path_len = share->path_sz;
|
||||
|
||||
if (strlen(filename) == 0)
|
||||
filename = "\\";
|
||||
pathname = kmalloc(PATH_MAX, GFP_KERNEL);
|
||||
if (!pathname)
|
||||
return ERR_PTR(-EACCES);
|
||||
|
||||
ab_pathname = kstrdup(filename, GFP_KERNEL);
|
||||
if (!ab_pathname)
|
||||
return NULL;
|
||||
ab_pathname = d_path(path, pathname, PATH_MAX);
|
||||
if (IS_ERR(ab_pathname)) {
|
||||
nt_pathname = ERR_PTR(-EACCES);
|
||||
goto free_pathname;
|
||||
}
|
||||
|
||||
ksmbd_conv_path_to_windows(ab_pathname);
|
||||
return ab_pathname;
|
||||
if (strncmp(ab_pathname, share->path, share_path_len)) {
|
||||
nt_pathname = ERR_PTR(-EACCES);
|
||||
goto free_pathname;
|
||||
}
|
||||
|
||||
nt_pathname = kzalloc(strlen(&ab_pathname[share_path_len]) + 2, GFP_KERNEL);
|
||||
if (!nt_pathname) {
|
||||
nt_pathname = ERR_PTR(-ENOMEM);
|
||||
goto free_pathname;
|
||||
}
|
||||
if (ab_pathname[share_path_len] == '\0')
|
||||
strcpy(nt_pathname, "/");
|
||||
strcat(nt_pathname, &ab_pathname[share_path_len]);
|
||||
|
||||
ksmbd_conv_path_to_windows(nt_pathname);
|
||||
|
||||
free_pathname:
|
||||
kfree(pathname);
|
||||
return nt_pathname;
|
||||
}
|
||||
|
||||
int get_nlink(struct kstat *st)
|
||||
@@ -204,32 +227,59 @@ void ksmbd_conv_path_to_windows(char *path)
|
||||
strreplace(path, '/', '\\');
|
||||
}
|
||||
|
||||
char *ksmbd_casefold_sharename(struct unicode_map *um, const char *name)
|
||||
{
|
||||
char *cf_name;
|
||||
int cf_len;
|
||||
|
||||
cf_name = kzalloc(KSMBD_REQ_MAX_SHARE_NAME, GFP_KERNEL);
|
||||
if (!cf_name)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
if (IS_ENABLED(CONFIG_UNICODE) && um) {
|
||||
const struct qstr q_name = {.name = name, .len = strlen(name)};
|
||||
|
||||
cf_len = utf8_casefold(um, &q_name, cf_name,
|
||||
KSMBD_REQ_MAX_SHARE_NAME);
|
||||
if (cf_len < 0)
|
||||
goto out_ascii;
|
||||
|
||||
return cf_name;
|
||||
}
|
||||
|
||||
out_ascii:
|
||||
cf_len = strscpy(cf_name, name, KSMBD_REQ_MAX_SHARE_NAME);
|
||||
if (cf_len < 0) {
|
||||
kfree(cf_name);
|
||||
return ERR_PTR(-E2BIG);
|
||||
}
|
||||
|
||||
for (; *cf_name; ++cf_name)
|
||||
*cf_name = isascii(*cf_name) ? tolower(*cf_name) : *cf_name;
|
||||
return cf_name - cf_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* ksmbd_extract_sharename() - get share name from tree connect request
|
||||
* @treename: buffer containing tree name and share name
|
||||
*
|
||||
* Return: share name on success, otherwise error
|
||||
*/
|
||||
char *ksmbd_extract_sharename(char *treename)
|
||||
char *ksmbd_extract_sharename(struct unicode_map *um, const char *treename)
|
||||
{
|
||||
char *name = treename;
|
||||
char *dst;
|
||||
char *pos = strrchr(name, '\\');
|
||||
const char *name = treename, *pos = strrchr(name, '\\');
|
||||
|
||||
if (pos)
|
||||
name = (pos + 1);
|
||||
|
||||
/* caller has to free the memory */
|
||||
dst = kstrdup(name, GFP_KERNEL);
|
||||
if (!dst)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
return dst;
|
||||
return ksmbd_casefold_sharename(um, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* convert_to_unix_name() - convert windows name to unix format
|
||||
* @path: name to be converted
|
||||
* @tid: tree id of mathing share
|
||||
* @share: ksmbd_share_config pointer
|
||||
* @name: file name that is relative to share
|
||||
*
|
||||
* Return: converted name on success, otherwise NULL
|
||||
*/
|
||||
|
||||
@@ -14,12 +14,14 @@ struct ksmbd_file;
|
||||
int match_pattern(const char *str, size_t len, const char *pattern);
|
||||
int ksmbd_validate_filename(char *filename);
|
||||
int parse_stream_name(char *filename, char **stream_name, int *s_type);
|
||||
char *convert_to_nt_pathname(char *filename);
|
||||
char *convert_to_nt_pathname(struct ksmbd_share_config *share,
|
||||
const struct path *path);
|
||||
int get_nlink(struct kstat *st);
|
||||
void ksmbd_conv_path_to_unix(char *path);
|
||||
void ksmbd_strip_last_slash(char *path);
|
||||
void ksmbd_conv_path_to_windows(char *path);
|
||||
char *ksmbd_extract_sharename(char *treename);
|
||||
char *ksmbd_casefold_sharename(struct unicode_map *um, const char *name);
|
||||
char *ksmbd_extract_sharename(struct unicode_map *um, const char *treename);
|
||||
char *convert_to_unix_name(struct ksmbd_share_config *share, const char *name);
|
||||
|
||||
#define KSMBD_DIR_INFO_ALIGNMENT 8
|
||||
|
||||
@@ -157,13 +157,42 @@ static struct oplock_info *opinfo_get_list(struct ksmbd_inode *ci)
|
||||
rcu_read_lock();
|
||||
opinfo = list_first_or_null_rcu(&ci->m_op_list, struct oplock_info,
|
||||
op_entry);
|
||||
if (opinfo && !atomic_inc_not_zero(&opinfo->refcount))
|
||||
opinfo = NULL;
|
||||
if (opinfo) {
|
||||
if (!atomic_inc_not_zero(&opinfo->refcount))
|
||||
opinfo = NULL;
|
||||
else {
|
||||
atomic_inc(&opinfo->conn->r_count);
|
||||
if (ksmbd_conn_releasing(opinfo->conn)) {
|
||||
atomic_dec(&opinfo->conn->r_count);
|
||||
atomic_dec(&opinfo->refcount);
|
||||
opinfo = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
return opinfo;
|
||||
}
|
||||
|
||||
static void opinfo_conn_put(struct oplock_info *opinfo)
|
||||
{
|
||||
struct ksmbd_conn *conn;
|
||||
|
||||
if (!opinfo)
|
||||
return;
|
||||
|
||||
conn = opinfo->conn;
|
||||
/*
|
||||
* Checking waitqueue to dropping pending requests on
|
||||
* disconnection. waitqueue_active is safe because it
|
||||
* uses atomic operation for condition.
|
||||
*/
|
||||
if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q))
|
||||
wake_up(&conn->r_count_q);
|
||||
opinfo_put(opinfo);
|
||||
}
|
||||
|
||||
void opinfo_put(struct oplock_info *opinfo)
|
||||
{
|
||||
if (!atomic_dec_and_test(&opinfo->refcount))
|
||||
@@ -587,15 +616,6 @@ static int oplock_break_pending(struct oplock_info *opinfo, int req_op_level)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int allocate_oplock_break_buf(struct ksmbd_work *work)
|
||||
{
|
||||
work->response_buf = kzalloc(MAX_CIFS_SMALL_BUFFER_SIZE, GFP_KERNEL);
|
||||
if (!work->response_buf)
|
||||
return -ENOMEM;
|
||||
work->response_sz = MAX_CIFS_SMALL_BUFFER_SIZE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* __smb2_oplock_break_noti() - send smb2 oplock break cmd from conn
|
||||
* to client
|
||||
@@ -610,30 +630,22 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
|
||||
{
|
||||
struct smb2_oplock_break *rsp = NULL;
|
||||
struct ksmbd_work *work = container_of(wk, struct ksmbd_work, work);
|
||||
struct ksmbd_conn *conn = work->conn;
|
||||
struct oplock_break_info *br_info = work->request_buf;
|
||||
struct smb2_hdr *rsp_hdr;
|
||||
struct ksmbd_file *fp;
|
||||
|
||||
fp = ksmbd_lookup_durable_fd(br_info->fid);
|
||||
if (!fp) {
|
||||
atomic_dec(&conn->r_count);
|
||||
ksmbd_free_work_struct(work);
|
||||
return;
|
||||
}
|
||||
if (!fp)
|
||||
goto out;
|
||||
|
||||
if (allocate_oplock_break_buf(work)) {
|
||||
if (allocate_interim_rsp_buf(work)) {
|
||||
pr_err("smb2_allocate_rsp_buf failed! ");
|
||||
atomic_dec(&conn->r_count);
|
||||
ksmbd_fd_put(work, fp);
|
||||
ksmbd_free_work_struct(work);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rsp_hdr = work->response_buf;
|
||||
rsp_hdr = smb2_get_msg(work->response_buf);
|
||||
memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2);
|
||||
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);
|
||||
@@ -646,7 +658,7 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
|
||||
rsp_hdr->SessionId = 0;
|
||||
memset(rsp_hdr->Signature, 0, 16);
|
||||
|
||||
rsp = work->response_buf;
|
||||
rsp = smb2_get_msg(work->response_buf);
|
||||
|
||||
rsp->StructureSize = cpu_to_le16(24);
|
||||
if (!br_info->open_trunc &&
|
||||
@@ -657,19 +669,22 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
|
||||
rsp->OplockLevel = SMB2_OPLOCK_LEVEL_NONE;
|
||||
rsp->Reserved = 0;
|
||||
rsp->Reserved2 = 0;
|
||||
rsp->PersistentFid = cpu_to_le64(fp->persistent_id);
|
||||
rsp->VolatileFid = cpu_to_le64(fp->volatile_id);
|
||||
rsp->PersistentFid = fp->persistent_id;
|
||||
rsp->VolatileFid = fp->volatile_id;
|
||||
|
||||
inc_rfc1001_len(rsp, 24);
|
||||
ksmbd_fd_put(work, fp);
|
||||
if (ksmbd_iov_pin_rsp(work, (void *)rsp,
|
||||
sizeof(struct smb2_oplock_break)))
|
||||
goto out;
|
||||
|
||||
ksmbd_debug(OPLOCK,
|
||||
"sending oplock break v_id %llu p_id = %llu lock level = %d\n",
|
||||
rsp->VolatileFid, rsp->PersistentFid, rsp->OplockLevel);
|
||||
|
||||
ksmbd_fd_put(work, fp);
|
||||
ksmbd_conn_write(work);
|
||||
|
||||
out:
|
||||
ksmbd_free_work_struct(work);
|
||||
atomic_dec(&conn->r_count);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -703,7 +718,6 @@ static int smb2_oplock_break_noti(struct oplock_info *opinfo)
|
||||
work->conn = conn;
|
||||
work->sess = opinfo->sess;
|
||||
|
||||
atomic_inc(&conn->r_count);
|
||||
if (opinfo->op_state == OPLOCK_ACK_WAIT) {
|
||||
INIT_WORK(&work->work, __smb2_oplock_break_noti);
|
||||
ksmbd_queue_work(work);
|
||||
@@ -727,20 +741,15 @@ static void __smb2_lease_break_noti(struct work_struct *wk)
|
||||
struct smb2_lease_break *rsp = NULL;
|
||||
struct ksmbd_work *work = container_of(wk, struct ksmbd_work, work);
|
||||
struct lease_break_info *br_info = work->request_buf;
|
||||
struct ksmbd_conn *conn = work->conn;
|
||||
struct smb2_hdr *rsp_hdr;
|
||||
|
||||
if (allocate_oplock_break_buf(work)) {
|
||||
if (allocate_interim_rsp_buf(work)) {
|
||||
ksmbd_debug(OPLOCK, "smb2_allocate_rsp_buf failed! ");
|
||||
ksmbd_free_work_struct(work);
|
||||
atomic_dec(&conn->r_count);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rsp_hdr = work->response_buf;
|
||||
rsp_hdr = smb2_get_msg(work->response_buf);
|
||||
memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2);
|
||||
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);
|
||||
@@ -753,7 +762,7 @@ static void __smb2_lease_break_noti(struct work_struct *wk)
|
||||
rsp_hdr->SessionId = 0;
|
||||
memset(rsp_hdr->Signature, 0, 16);
|
||||
|
||||
rsp = work->response_buf;
|
||||
rsp = smb2_get_msg(work->response_buf);
|
||||
rsp->StructureSize = cpu_to_le16(44);
|
||||
rsp->Epoch = br_info->epoch;
|
||||
rsp->Flags = 0;
|
||||
@@ -769,11 +778,14 @@ static void __smb2_lease_break_noti(struct work_struct *wk)
|
||||
rsp->AccessMaskHint = 0;
|
||||
rsp->ShareMaskHint = 0;
|
||||
|
||||
inc_rfc1001_len(rsp, 44);
|
||||
if (ksmbd_iov_pin_rsp(work, (void *)rsp,
|
||||
sizeof(struct smb2_lease_break)))
|
||||
goto out;
|
||||
|
||||
ksmbd_conn_write(work);
|
||||
|
||||
out:
|
||||
ksmbd_free_work_struct(work);
|
||||
atomic_dec(&conn->r_count);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -813,7 +825,6 @@ static int smb2_lease_break_noti(struct oplock_info *opinfo)
|
||||
work->conn = conn;
|
||||
work->sess = opinfo->sess;
|
||||
|
||||
atomic_inc(&conn->r_count);
|
||||
if (opinfo->op_state == OPLOCK_ACK_WAIT) {
|
||||
list_for_each_safe(tmp, t, &opinfo->interim_list) {
|
||||
struct ksmbd_work *in_work;
|
||||
@@ -822,7 +833,8 @@ static int smb2_lease_break_noti(struct oplock_info *opinfo)
|
||||
interim_entry);
|
||||
setup_async_work(in_work, NULL, NULL);
|
||||
smb2_send_interim_resp(in_work, STATUS_PENDING);
|
||||
list_del(&in_work->interim_entry);
|
||||
list_del_init(&in_work->interim_entry);
|
||||
release_async_work(in_work);
|
||||
}
|
||||
INIT_WORK(&work->work, __smb2_lease_break_noti);
|
||||
ksmbd_queue_work(work);
|
||||
@@ -1135,8 +1147,10 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,
|
||||
}
|
||||
prev_opinfo = opinfo_get_list(ci);
|
||||
if (!prev_opinfo ||
|
||||
(prev_opinfo->level == SMB2_OPLOCK_LEVEL_NONE && lctx))
|
||||
(prev_opinfo->level == SMB2_OPLOCK_LEVEL_NONE && lctx)) {
|
||||
opinfo_conn_put(prev_opinfo);
|
||||
goto set_lev;
|
||||
}
|
||||
prev_op_has_lease = prev_opinfo->is_lease;
|
||||
if (prev_op_has_lease)
|
||||
prev_op_state = prev_opinfo->o_lease->state;
|
||||
@@ -1144,19 +1158,19 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,
|
||||
if (share_ret < 0 &&
|
||||
prev_opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
|
||||
err = share_ret;
|
||||
opinfo_put(prev_opinfo);
|
||||
opinfo_conn_put(prev_opinfo);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (prev_opinfo->level != SMB2_OPLOCK_LEVEL_BATCH &&
|
||||
prev_opinfo->level != SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
|
||||
opinfo_put(prev_opinfo);
|
||||
opinfo_conn_put(prev_opinfo);
|
||||
goto op_break_not_needed;
|
||||
}
|
||||
|
||||
list_add(&work->interim_entry, &prev_opinfo->interim_list);
|
||||
err = oplock_break(prev_opinfo, SMB2_OPLOCK_LEVEL_II);
|
||||
opinfo_put(prev_opinfo);
|
||||
opinfo_conn_put(prev_opinfo);
|
||||
if (err == -ENOENT)
|
||||
goto set_lev;
|
||||
/* Check all oplock was freed by close */
|
||||
@@ -1219,14 +1233,14 @@ static void smb_break_all_write_oplock(struct ksmbd_work *work,
|
||||
return;
|
||||
if (brk_opinfo->level != SMB2_OPLOCK_LEVEL_BATCH &&
|
||||
brk_opinfo->level != SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
|
||||
opinfo_put(brk_opinfo);
|
||||
opinfo_conn_put(brk_opinfo);
|
||||
return;
|
||||
}
|
||||
|
||||
brk_opinfo->open_trunc = is_trunc;
|
||||
list_add(&work->interim_entry, &brk_opinfo->interim_list);
|
||||
oplock_break(brk_opinfo, SMB2_OPLOCK_LEVEL_II);
|
||||
opinfo_put(brk_opinfo);
|
||||
opinfo_conn_put(brk_opinfo);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1254,6 +1268,13 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,
|
||||
list_for_each_entry_rcu(brk_op, &ci->m_op_list, op_entry) {
|
||||
if (!atomic_inc_not_zero(&brk_op->refcount))
|
||||
continue;
|
||||
|
||||
atomic_inc(&brk_op->conn->r_count);
|
||||
if (ksmbd_conn_releasing(brk_op->conn)) {
|
||||
atomic_dec(&brk_op->conn->r_count);
|
||||
continue;
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
if (brk_op->is_lease && (brk_op->o_lease->state &
|
||||
(~(SMB2_LEASE_READ_CACHING_LE |
|
||||
@@ -1283,7 +1304,7 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,
|
||||
brk_op->open_trunc = is_trunc;
|
||||
oplock_break(brk_op, SMB2_OPLOCK_LEVEL_NONE);
|
||||
next:
|
||||
opinfo_put(brk_op);
|
||||
opinfo_conn_put(brk_op);
|
||||
rcu_read_lock();
|
||||
}
|
||||
rcu_read_unlock();
|
||||
@@ -1336,19 +1357,16 @@ __u8 smb2_map_lease_to_oplock(__le32 lease_state)
|
||||
*/
|
||||
void create_lease_buf(u8 *rbuf, struct lease *lease)
|
||||
{
|
||||
char *LeaseKey = (char *)&lease->lease_key;
|
||||
|
||||
if (lease->version == 2) {
|
||||
struct create_lease_v2 *buf = (struct create_lease_v2 *)rbuf;
|
||||
char *ParentLeaseKey = (char *)&lease->parent_lease_key;
|
||||
|
||||
memset(buf, 0, sizeof(struct create_lease_v2));
|
||||
buf->lcontext.LeaseKeyLow = *((__le64 *)LeaseKey);
|
||||
buf->lcontext.LeaseKeyHigh = *((__le64 *)(LeaseKey + 8));
|
||||
memcpy(buf->lcontext.LeaseKey, lease->lease_key,
|
||||
SMB2_LEASE_KEY_SIZE);
|
||||
buf->lcontext.LeaseFlags = lease->flags;
|
||||
buf->lcontext.LeaseState = lease->state;
|
||||
buf->lcontext.ParentLeaseKeyLow = *((__le64 *)ParentLeaseKey);
|
||||
buf->lcontext.ParentLeaseKeyHigh = *((__le64 *)(ParentLeaseKey + 8));
|
||||
memcpy(buf->lcontext.ParentLeaseKey, lease->parent_lease_key,
|
||||
SMB2_LEASE_KEY_SIZE);
|
||||
buf->ccontext.DataOffset = cpu_to_le16(offsetof
|
||||
(struct create_lease_v2, lcontext));
|
||||
buf->ccontext.DataLength = cpu_to_le32(sizeof(struct lease_context_v2));
|
||||
@@ -1363,8 +1381,7 @@ void create_lease_buf(u8 *rbuf, struct lease *lease)
|
||||
struct create_lease *buf = (struct create_lease *)rbuf;
|
||||
|
||||
memset(buf, 0, sizeof(struct create_lease));
|
||||
buf->lcontext.LeaseKeyLow = *((__le64 *)LeaseKey);
|
||||
buf->lcontext.LeaseKeyHigh = *((__le64 *)(LeaseKey + 8));
|
||||
memcpy(buf->lcontext.LeaseKey, lease->lease_key, SMB2_LEASE_KEY_SIZE);
|
||||
buf->lcontext.LeaseFlags = lease->flags;
|
||||
buf->lcontext.LeaseState = lease->state;
|
||||
buf->ccontext.DataOffset = cpu_to_le16(offsetof
|
||||
@@ -1388,58 +1405,38 @@ void create_lease_buf(u8 *rbuf, struct lease *lease)
|
||||
*/
|
||||
struct lease_ctx_info *parse_lease_state(void *open_req)
|
||||
{
|
||||
char *data_offset;
|
||||
struct create_context *cc;
|
||||
unsigned int next = 0;
|
||||
char *name;
|
||||
bool found = false;
|
||||
struct smb2_create_req *req = (struct smb2_create_req *)open_req;
|
||||
struct lease_ctx_info *lreq = kzalloc(sizeof(struct lease_ctx_info),
|
||||
GFP_KERNEL);
|
||||
struct lease_ctx_info *lreq;
|
||||
|
||||
cc = smb2_find_context_vals(req, SMB2_CREATE_REQUEST_LEASE, 4);
|
||||
if (IS_ERR_OR_NULL(cc))
|
||||
return NULL;
|
||||
|
||||
lreq = kzalloc(sizeof(struct lease_ctx_info), GFP_KERNEL);
|
||||
if (!lreq)
|
||||
return NULL;
|
||||
|
||||
data_offset = (char *)req + 4 + le32_to_cpu(req->CreateContextsOffset);
|
||||
cc = (struct create_context *)data_offset;
|
||||
do {
|
||||
cc = (struct create_context *)((char *)cc + next);
|
||||
name = le16_to_cpu(cc->NameOffset) + (char *)cc;
|
||||
if (le16_to_cpu(cc->NameLength) != 4 ||
|
||||
strncmp(name, SMB2_CREATE_REQUEST_LEASE, 4)) {
|
||||
next = le32_to_cpu(cc->Next);
|
||||
continue;
|
||||
}
|
||||
found = true;
|
||||
break;
|
||||
} while (next != 0);
|
||||
if (sizeof(struct lease_context_v2) == le32_to_cpu(cc->DataLength)) {
|
||||
struct create_lease_v2 *lc = (struct create_lease_v2 *)cc;
|
||||
|
||||
if (found) {
|
||||
if (sizeof(struct lease_context_v2) == le32_to_cpu(cc->DataLength)) {
|
||||
struct create_lease_v2 *lc = (struct create_lease_v2 *)cc;
|
||||
memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
|
||||
lreq->req_state = lc->lcontext.LeaseState;
|
||||
lreq->flags = lc->lcontext.LeaseFlags;
|
||||
lreq->duration = lc->lcontext.LeaseDuration;
|
||||
memcpy(lreq->parent_lease_key, lc->lcontext.ParentLeaseKey,
|
||||
SMB2_LEASE_KEY_SIZE);
|
||||
lreq->version = 2;
|
||||
} else {
|
||||
struct create_lease *lc = (struct create_lease *)cc;
|
||||
|
||||
*((__le64 *)lreq->lease_key) = lc->lcontext.LeaseKeyLow;
|
||||
*((__le64 *)(lreq->lease_key + 8)) = lc->lcontext.LeaseKeyHigh;
|
||||
lreq->req_state = lc->lcontext.LeaseState;
|
||||
lreq->flags = lc->lcontext.LeaseFlags;
|
||||
lreq->duration = lc->lcontext.LeaseDuration;
|
||||
*((__le64 *)lreq->parent_lease_key) = lc->lcontext.ParentLeaseKeyLow;
|
||||
*((__le64 *)(lreq->parent_lease_key + 8)) = lc->lcontext.ParentLeaseKeyHigh;
|
||||
lreq->version = 2;
|
||||
} else {
|
||||
struct create_lease *lc = (struct create_lease *)cc;
|
||||
|
||||
*((__le64 *)lreq->lease_key) = lc->lcontext.LeaseKeyLow;
|
||||
*((__le64 *)(lreq->lease_key + 8)) = lc->lcontext.LeaseKeyHigh;
|
||||
lreq->req_state = lc->lcontext.LeaseState;
|
||||
lreq->flags = lc->lcontext.LeaseFlags;
|
||||
lreq->duration = lc->lcontext.LeaseDuration;
|
||||
lreq->version = 1;
|
||||
}
|
||||
return lreq;
|
||||
memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
|
||||
lreq->req_state = lc->lcontext.LeaseState;
|
||||
lreq->flags = lc->lcontext.LeaseFlags;
|
||||
lreq->duration = lc->lcontext.LeaseDuration;
|
||||
lreq->version = 1;
|
||||
}
|
||||
|
||||
kfree(lreq);
|
||||
return NULL;
|
||||
return lreq;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1464,7 +1461,7 @@ struct create_context *smb2_find_context_vals(void *open_req, const char *tag, i
|
||||
* CreateContextsOffset and CreateContextsLength are guaranteed to
|
||||
* be valid because of ksmbd_smb2_check_message().
|
||||
*/
|
||||
cc = (struct create_context *)((char *)req + 4 +
|
||||
cc = (struct create_context *)((char *)req +
|
||||
le32_to_cpu(req->CreateContextsOffset));
|
||||
remain_len = le32_to_cpu(req->CreateContextsLength);
|
||||
do {
|
||||
@@ -1612,7 +1609,11 @@ void create_posix_rsp_buf(char *cc, struct ksmbd_file *fp)
|
||||
memset(buf, 0, sizeof(struct create_posix_rsp));
|
||||
buf->ccontext.DataOffset = cpu_to_le16(offsetof
|
||||
(struct create_posix_rsp, nlink));
|
||||
buf->ccontext.DataLength = cpu_to_le32(52);
|
||||
/*
|
||||
* DataLength = nlink(4) + reparse_tag(4) + mode(4) +
|
||||
* domain sid(28) + unix group sid(16).
|
||||
*/
|
||||
buf->ccontext.DataLength = cpu_to_le32(56);
|
||||
buf->ccontext.NameOffset = cpu_to_le16(offsetof
|
||||
(struct create_posix_rsp, Name));
|
||||
buf->ccontext.NameLength = cpu_to_le16(POSIX_CTXT_DATA_LEN);
|
||||
@@ -1636,13 +1637,20 @@ 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);
|
||||
buf->mode = cpu_to_le32(inode->i_mode & 0777);
|
||||
/*
|
||||
* SidBuffer(44) contain two sids(Domain sid(28), UNIX group sid(16)).
|
||||
* Domain sid(28) = revision(1) + num_subauth(1) + authority(6) +
|
||||
* sub_auth(4 * 4(num_subauth)) + RID(4).
|
||||
* UNIX group id(16) = revision(1) + num_subauth(1) + authority(6) +
|
||||
* sub_auth(4 * 1(num_subauth)) + RID(4).
|
||||
*/
|
||||
id_to_sid(from_kuid_munged(&init_user_ns,
|
||||
i_uid_into_mnt(user_ns, inode)),
|
||||
SIDNFS_USER, (struct smb_sid *)&buf->SidBuffer[0]);
|
||||
SIDOWNER, (struct smb_sid *)&buf->SidBuffer[0]);
|
||||
id_to_sid(from_kgid_munged(&init_user_ns,
|
||||
i_gid_into_mnt(user_ns, inode)),
|
||||
SIDNFS_GROUP, (struct smb_sid *)&buf->SidBuffer[20]);
|
||||
SIDUNIX_GROUP, (struct smb_sid *)&buf->SidBuffer[28]);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1702,33 +1710,3 @@ out:
|
||||
read_unlock(&lease_list_lock);
|
||||
return ret_op;
|
||||
}
|
||||
|
||||
int smb2_check_durable_oplock(struct ksmbd_file *fp,
|
||||
struct lease_ctx_info *lctx, char *name)
|
||||
{
|
||||
struct oplock_info *opinfo = opinfo_get(fp);
|
||||
int ret = 0;
|
||||
|
||||
if (opinfo && opinfo->is_lease) {
|
||||
if (!lctx) {
|
||||
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)) {
|
||||
pr_err("invalid lease key\n");
|
||||
ret = -EBADF;
|
||||
goto out;
|
||||
}
|
||||
if (name && strcmp(fp->filename, name)) {
|
||||
pr_err("invalid name reconnect %s\n", name);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
out:
|
||||
if (opinfo)
|
||||
opinfo_put(opinfo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -28,8 +28,6 @@
|
||||
#define OPLOCK_WRITE_TO_NONE 0x04
|
||||
#define OPLOCK_READ_TO_NONE 0x08
|
||||
|
||||
#define SMB2_LEASE_KEY_SIZE 16
|
||||
|
||||
struct lease_ctx_info {
|
||||
__u8 lease_key[SMB2_LEASE_KEY_SIZE];
|
||||
__le32 req_state;
|
||||
@@ -126,6 +124,4 @@ struct oplock_info *lookup_lease_in_table(struct ksmbd_conn *conn,
|
||||
int find_same_lease_key(struct ksmbd_session *sess, struct ksmbd_inode *ci,
|
||||
struct lease_ctx_info *lctx);
|
||||
void destroy_lease_table(struct ksmbd_conn *conn);
|
||||
int smb2_check_durable_oplock(struct ksmbd_file *fp,
|
||||
struct lease_ctx_info *lctx, char *name);
|
||||
#endif /* __KSMBD_OPLOCK_H */
|
||||
|
||||
@@ -93,7 +93,8 @@ static inline int check_conn_state(struct ksmbd_work *work)
|
||||
{
|
||||
struct smb_hdr *rsp_hdr;
|
||||
|
||||
if (ksmbd_conn_exiting(work) || ksmbd_conn_need_reconnect(work)) {
|
||||
if (ksmbd_conn_exiting(work->conn) ||
|
||||
ksmbd_conn_need_reconnect(work->conn)) {
|
||||
rsp_hdr = work->response_buf;
|
||||
rsp_hdr->Status.CifsError = STATUS_CONNECTION_DISCONNECTED;
|
||||
return 1;
|
||||
@@ -114,8 +115,10 @@ static int __process_request(struct ksmbd_work *work, struct ksmbd_conn *conn,
|
||||
if (check_conn_state(work))
|
||||
return SERVER_HANDLER_CONTINUE;
|
||||
|
||||
if (ksmbd_verify_smb_message(work))
|
||||
if (ksmbd_verify_smb_message(work)) {
|
||||
conn->ops->set_rsp_status(work, STATUS_INVALID_PARAMETER);
|
||||
return SERVER_HANDLER_ABORT;
|
||||
}
|
||||
|
||||
command = conn->ops->get_cmd_val(work);
|
||||
*cmd = command;
|
||||
@@ -162,6 +165,7 @@ static void __handle_ksmbd_work(struct ksmbd_work *work,
|
||||
{
|
||||
u16 command = 0;
|
||||
int rc;
|
||||
bool is_chained = false;
|
||||
|
||||
if (conn->ops->allocate_rsp_buf(work))
|
||||
return;
|
||||
@@ -228,16 +232,17 @@ static void __handle_ksmbd_work(struct ksmbd_work *work,
|
||||
}
|
||||
}
|
||||
|
||||
is_chained = is_chained_smb2_message(work);
|
||||
|
||||
if (work->sess &&
|
||||
(work->sess->sign || smb3_11_final_sess_setup_resp(work) ||
|
||||
conn->ops->is_sign_req(work, command)))
|
||||
conn->ops->set_sign_rsp(work);
|
||||
} while (is_chained_smb2_message(work));
|
||||
|
||||
if (work->send_no_response)
|
||||
return;
|
||||
} while (is_chained == true);
|
||||
|
||||
send:
|
||||
if (work->tcon)
|
||||
ksmbd_tree_connect_put(work->tcon);
|
||||
smb3_preauth_hash_rsp(work);
|
||||
if (work->sess && work->sess->enc && work->encrypted &&
|
||||
conn->ops->encrypt_resp) {
|
||||
@@ -266,7 +271,13 @@ static void handle_ksmbd_work(struct work_struct *wk)
|
||||
|
||||
ksmbd_conn_try_dequeue_request(work);
|
||||
ksmbd_free_work_struct(work);
|
||||
atomic_dec(&conn->r_count);
|
||||
/*
|
||||
* Checking waitqueue to dropping pending requests on
|
||||
* disconnection. waitqueue_active is safe because it
|
||||
* uses atomic operation for condition.
|
||||
*/
|
||||
if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q))
|
||||
wake_up(&conn->r_count_q);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -279,6 +290,7 @@ static void handle_ksmbd_work(struct work_struct *wk)
|
||||
static int queue_ksmbd_work(struct ksmbd_conn *conn)
|
||||
{
|
||||
struct ksmbd_work *work;
|
||||
int err;
|
||||
|
||||
work = ksmbd_alloc_work_struct();
|
||||
if (!work) {
|
||||
@@ -290,9 +302,10 @@ static int queue_ksmbd_work(struct ksmbd_conn *conn)
|
||||
work->request_buf = conn->request_buf;
|
||||
conn->request_buf = NULL;
|
||||
|
||||
if (ksmbd_init_smb_server(work)) {
|
||||
err = ksmbd_init_smb_server(work);
|
||||
if (err) {
|
||||
ksmbd_free_work_struct(work);
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ksmbd_conn_enqueue_request(work);
|
||||
@@ -433,11 +446,9 @@ static ssize_t stats_show(struct class *class, struct class_attribute *attr,
|
||||
"reset",
|
||||
"shutdown"
|
||||
};
|
||||
|
||||
ssize_t sz = scnprintf(buf, PAGE_SIZE, "%d %s %d %lu\n", stats_version,
|
||||
state[server_conf.state], server_conf.tcp_port,
|
||||
server_conf.ipc_last_active / HZ);
|
||||
return sz;
|
||||
return sysfs_emit(buf, "%d %s %d %lu\n", stats_version,
|
||||
state[server_conf.state], server_conf.tcp_port,
|
||||
server_conf.ipc_last_active / HZ);
|
||||
}
|
||||
|
||||
static ssize_t kill_server_store(struct class *class,
|
||||
@@ -469,19 +480,13 @@ static ssize_t debug_show(struct class *class, struct class_attribute *attr,
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(debug_type_strings); i++) {
|
||||
if ((ksmbd_debug_types >> i) & 1) {
|
||||
pos = scnprintf(buf + sz,
|
||||
PAGE_SIZE - sz,
|
||||
"[%s] ",
|
||||
debug_type_strings[i]);
|
||||
pos = sysfs_emit_at(buf, sz, "[%s] ", debug_type_strings[i]);
|
||||
} else {
|
||||
pos = scnprintf(buf + sz,
|
||||
PAGE_SIZE - sz,
|
||||
"%s ",
|
||||
debug_type_strings[i]);
|
||||
pos = sysfs_emit_at(buf, sz, "%s ", debug_type_strings[i]);
|
||||
}
|
||||
sz += pos;
|
||||
}
|
||||
sz += scnprintf(buf + sz, PAGE_SIZE - sz, "\n");
|
||||
sz += sysfs_emit_at(buf, sz, "\n");
|
||||
return sz;
|
||||
}
|
||||
|
||||
@@ -590,8 +595,6 @@ static int __init ksmbd_server_init(void)
|
||||
if (ret)
|
||||
goto err_crypto_destroy;
|
||||
|
||||
pr_warn_once("The ksmbd server is experimental, use at your own risk.\n");
|
||||
|
||||
return 0;
|
||||
|
||||
err_crypto_destroy:
|
||||
@@ -629,7 +632,6 @@ MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY);
|
||||
MODULE_SOFTDEP("pre: ecb");
|
||||
MODULE_SOFTDEP("pre: hmac");
|
||||
MODULE_SOFTDEP("pre: md4");
|
||||
MODULE_SOFTDEP("pre: md5");
|
||||
MODULE_SOFTDEP("pre: nls");
|
||||
MODULE_SOFTDEP("pre: aes");
|
||||
|
||||
@@ -441,10 +441,8 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work)
|
||||
|
||||
validate_credit:
|
||||
if ((work->conn->vals->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU) &&
|
||||
smb2_validate_credit_charge(work->conn, hdr)) {
|
||||
work->conn->ops->set_rsp_status(work, STATUS_INVALID_PARAMETER);
|
||||
smb2_validate_credit_charge(work->conn, hdr))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -248,8 +248,9 @@ void init_smb3_02_server(struct ksmbd_conn *conn)
|
||||
if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_LEASES)
|
||||
conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING;
|
||||
|
||||
if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION &&
|
||||
conn->cli_cap & SMB2_GLOBAL_CAP_ENCRYPTION)
|
||||
if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION ||
|
||||
(!(server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION_OFF) &&
|
||||
conn->cli_cap & SMB2_GLOBAL_CAP_ENCRYPTION))
|
||||
conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION;
|
||||
|
||||
if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL)
|
||||
@@ -272,6 +273,11 @@ int init_smb3_11_server(struct ksmbd_conn *conn)
|
||||
if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_LEASES)
|
||||
conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING;
|
||||
|
||||
if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION ||
|
||||
(!(server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION_OFF) &&
|
||||
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;
|
||||
|
||||
|
||||
2047
fs/ksmbd/smb2pdu.c
2047
fs/ksmbd/smb2pdu.c
File diff suppressed because it is too large
Load Diff
@@ -109,6 +109,7 @@
|
||||
|
||||
#define SMB2_PROTO_NUMBER cpu_to_le32(0x424d53fe) /* 'B''M''S' */
|
||||
#define SMB2_TRANSFORM_PROTO_NUM cpu_to_le32(0x424d53fd)
|
||||
#define SMB2_COMPRESSION_TRANSFORM_ID cpu_to_le32(0x424d53fc)
|
||||
|
||||
#define SMB21_DEFAULT_IOSIZE (1024 * 1024)
|
||||
#define SMB3_DEFAULT_IOSIZE (4 * 1024 * 1024)
|
||||
@@ -131,11 +132,6 @@
|
||||
cpu_to_le16(__SMB2_HEADER_STRUCTURE_SIZE)
|
||||
|
||||
struct smb2_hdr {
|
||||
__be32 smb2_buf_length; /* big endian on wire */
|
||||
/*
|
||||
* length is only two or three bytes - with
|
||||
* one or two byte type preceding it that MBZ
|
||||
*/
|
||||
__le32 ProtocolId; /* 0xFE 'S' 'M' 'B' */
|
||||
__le16 StructureSize; /* 64 */
|
||||
__le16 CreditCharge; /* MBZ */
|
||||
@@ -165,11 +161,6 @@ struct smb2_pdu {
|
||||
#define SMB3_AES_GCM_NONCE 12
|
||||
|
||||
struct smb2_transform_hdr {
|
||||
__be32 smb2_buf_length; /* big endian on wire */
|
||||
/*
|
||||
* length is only two or three bytes - with
|
||||
* one or two byte type preceding it that MBZ
|
||||
*/
|
||||
__le32 ProtocolId; /* 0xFD 'S' 'M' 'B' */
|
||||
__u8 Signature[16];
|
||||
__u8 Nonce[16];
|
||||
@@ -254,14 +245,14 @@ struct preauth_integrity_info {
|
||||
__u8 Preauth_HashValue[PREAUTH_HASHVALUE_SIZE];
|
||||
};
|
||||
|
||||
/* offset is sizeof smb2_negotiate_rsp - 4 but rounded up to 8 bytes. */
|
||||
/* offset is sizeof smb2_negotiate_rsp but rounded up to 8 bytes. */
|
||||
#ifdef CONFIG_SMB_SERVER_KERBEROS5
|
||||
/* sizeof(struct smb2_negotiate_rsp) - 4 =
|
||||
/* sizeof(struct smb2_negotiate_rsp) =
|
||||
* header(64) + response(64) + GSS_LENGTH(96) + GSS_PADDING(0)
|
||||
*/
|
||||
#define OFFSET_OF_NEG_CONTEXT 0xe0
|
||||
#else
|
||||
/* sizeof(struct smb2_negotiate_rsp) - 4 =
|
||||
/* sizeof(struct smb2_negotiate_rsp) =
|
||||
* header(64) + response(64) + GSS_LENGTH(74) + GSS_PADDING(6)
|
||||
*/
|
||||
#define OFFSET_OF_NEG_CONTEXT 0xd0
|
||||
@@ -629,6 +620,8 @@ struct create_context {
|
||||
__u8 Buffer[0];
|
||||
} __packed;
|
||||
|
||||
#define SMB2_SESSION_TIMEOUT (10 * HZ)
|
||||
|
||||
struct create_durable_req_v2 {
|
||||
struct create_context ccontext;
|
||||
__u8 Name[8];
|
||||
@@ -644,8 +637,8 @@ struct create_durable_reconn_req {
|
||||
union {
|
||||
__u8 Reserved[16];
|
||||
struct {
|
||||
__le64 PersistentFileId;
|
||||
__le64 VolatileFileId;
|
||||
__u64 PersistentFileId;
|
||||
__u64 VolatileFileId;
|
||||
} Fid;
|
||||
} Data;
|
||||
} __packed;
|
||||
@@ -654,8 +647,8 @@ struct create_durable_reconn_v2_req {
|
||||
struct create_context ccontext;
|
||||
__u8 Name[8];
|
||||
struct {
|
||||
__le64 PersistentFileId;
|
||||
__le64 VolatileFileId;
|
||||
__u64 PersistentFileId;
|
||||
__u64 VolatileFileId;
|
||||
} Fid;
|
||||
__u8 CreateGuid[16];
|
||||
__le32 Flags;
|
||||
@@ -734,7 +727,8 @@ struct create_posix_rsp {
|
||||
__le32 nlink;
|
||||
__le32 reparse_tag;
|
||||
__le32 mode;
|
||||
u8 SidBuffer[40];
|
||||
/* SidBuffer contain two sids(Domain sid(28), UNIX group sid(16)) */
|
||||
u8 SidBuffer[44];
|
||||
} __packed;
|
||||
|
||||
#define SMB2_LEASE_NONE_LE cpu_to_le32(0x00)
|
||||
@@ -744,22 +738,21 @@ struct create_posix_rsp {
|
||||
|
||||
#define SMB2_LEASE_FLAG_BREAK_IN_PROGRESS_LE cpu_to_le32(0x02)
|
||||
|
||||
#define SMB2_LEASE_KEY_SIZE 16
|
||||
|
||||
struct lease_context {
|
||||
__le64 LeaseKeyLow;
|
||||
__le64 LeaseKeyHigh;
|
||||
__u8 LeaseKey[SMB2_LEASE_KEY_SIZE];
|
||||
__le32 LeaseState;
|
||||
__le32 LeaseFlags;
|
||||
__le64 LeaseDuration;
|
||||
} __packed;
|
||||
|
||||
struct lease_context_v2 {
|
||||
__le64 LeaseKeyLow;
|
||||
__le64 LeaseKeyHigh;
|
||||
__u8 LeaseKey[SMB2_LEASE_KEY_SIZE];
|
||||
__le32 LeaseState;
|
||||
__le32 LeaseFlags;
|
||||
__le64 LeaseDuration;
|
||||
__le64 ParentLeaseKeyLow;
|
||||
__le64 ParentLeaseKeyHigh;
|
||||
__u8 ParentLeaseKey[SMB2_LEASE_KEY_SIZE];
|
||||
__le16 Epoch;
|
||||
__le16 Reserved;
|
||||
} __packed;
|
||||
@@ -900,8 +893,8 @@ struct smb2_ioctl_req {
|
||||
__le16 StructureSize; /* Must be 57 */
|
||||
__le16 Reserved; /* offset from start of SMB2 header to write data */
|
||||
__le32 CntCode;
|
||||
__le64 PersistentFileId;
|
||||
__le64 VolatileFileId;
|
||||
__u64 PersistentFileId;
|
||||
__u64 VolatileFileId;
|
||||
__le32 InputOffset; /* Reserved MBZ */
|
||||
__le32 InputCount;
|
||||
__le32 MaxInputResponse;
|
||||
@@ -918,8 +911,8 @@ struct smb2_ioctl_rsp {
|
||||
__le16 StructureSize; /* Must be 49 */
|
||||
__le16 Reserved; /* offset from start of SMB2 header to write data */
|
||||
__le32 CntCode;
|
||||
__le64 PersistentFileId;
|
||||
__le64 VolatileFileId;
|
||||
__u64 PersistentFileId;
|
||||
__u64 VolatileFileId;
|
||||
__le32 InputOffset; /* Reserved MBZ */
|
||||
__le32 InputCount;
|
||||
__le32 OutputOffset;
|
||||
@@ -988,7 +981,7 @@ struct file_object_buf_type1_ioctl_rsp {
|
||||
} __packed;
|
||||
|
||||
struct resume_key_ioctl_rsp {
|
||||
__le64 ResumeKey[3];
|
||||
__u64 ResumeKey[3];
|
||||
__le32 ContextLength;
|
||||
__u8 Context[4]; /* ignored, Windows sets to 4 bytes of zero */
|
||||
} __packed;
|
||||
@@ -1100,8 +1093,8 @@ struct smb2_lock_req {
|
||||
__le16 StructureSize; /* Must be 48 */
|
||||
__le16 LockCount;
|
||||
__le32 Reserved;
|
||||
__le64 PersistentFileId;
|
||||
__le64 VolatileFileId;
|
||||
__u64 PersistentFileId;
|
||||
__u64 VolatileFileId;
|
||||
/* Followed by at least one */
|
||||
struct smb2_lock_element locks[1];
|
||||
} __packed;
|
||||
@@ -1136,8 +1129,8 @@ struct smb2_query_directory_req {
|
||||
__u8 FileInformationClass;
|
||||
__u8 Flags;
|
||||
__le32 FileIndex;
|
||||
__le64 PersistentFileId;
|
||||
__le64 VolatileFileId;
|
||||
__u64 PersistentFileId;
|
||||
__u64 VolatileFileId;
|
||||
__le16 FileNameOffset;
|
||||
__le16 FileNameLength;
|
||||
__le32 OutputBufferLength;
|
||||
@@ -1183,8 +1176,8 @@ struct smb2_query_info_req {
|
||||
__le32 InputBufferLength;
|
||||
__le32 AdditionalInformation;
|
||||
__le32 Flags;
|
||||
__le64 PersistentFileId;
|
||||
__le64 VolatileFileId;
|
||||
__u64 PersistentFileId;
|
||||
__u64 VolatileFileId;
|
||||
__u8 Buffer[1];
|
||||
} __packed;
|
||||
|
||||
@@ -1205,8 +1198,8 @@ struct smb2_set_info_req {
|
||||
__le16 BufferOffset;
|
||||
__u16 Reserved;
|
||||
__le32 AdditionalInformation;
|
||||
__le64 PersistentFileId;
|
||||
__le64 VolatileFileId;
|
||||
__u64 PersistentFileId;
|
||||
__u64 VolatileFileId;
|
||||
__u8 Buffer[1];
|
||||
} __packed;
|
||||
|
||||
@@ -1628,9 +1621,10 @@ struct smb2_posix_info {
|
||||
__le32 HardLinks;
|
||||
__le32 ReparseTag;
|
||||
__le32 Mode;
|
||||
u8 SidBuffer[40];
|
||||
/* SidBuffer contain two sids (UNIX user sid(16), UNIX group sid(16)) */
|
||||
u8 SidBuffer[32];
|
||||
__le32 name_len;
|
||||
u8 name[1];
|
||||
u8 name[];
|
||||
/*
|
||||
* var sized owner SID
|
||||
* var sized group SID
|
||||
@@ -1672,6 +1666,7 @@ int find_matching_smb2_dialect(int start_index, __le16 *cli_dialects,
|
||||
struct file_lock *smb_flock_init(struct file *f);
|
||||
int setup_async_work(struct ksmbd_work *work, void (*fn)(void **),
|
||||
void **arg);
|
||||
void release_async_work(struct ksmbd_work *work);
|
||||
void smb2_send_interim_resp(struct ksmbd_work *work, __le32 status);
|
||||
struct channel *lookup_chann_list(struct ksmbd_session *sess,
|
||||
struct ksmbd_conn *conn);
|
||||
@@ -1681,6 +1676,7 @@ int smb3_decrypt_req(struct ksmbd_work *work);
|
||||
int smb3_encrypt_resp(struct ksmbd_work *work);
|
||||
bool smb3_11_final_sess_setup_resp(struct ksmbd_work *work);
|
||||
int smb2_set_rsp_credits(struct ksmbd_work *work);
|
||||
bool smb3_encryption_negotiated(struct ksmbd_conn *conn);
|
||||
|
||||
/* smb2 misc functions */
|
||||
int ksmbd_smb2_check_message(struct ksmbd_work *work);
|
||||
@@ -1707,4 +1703,13 @@ int smb2_ioctl(struct ksmbd_work *work);
|
||||
int smb2_oplock_break(struct ksmbd_work *work);
|
||||
int smb2_notify(struct ksmbd_work *ksmbd_work);
|
||||
|
||||
/*
|
||||
* Get the body of the smb2 message excluding the 4 byte rfc1002 headers
|
||||
* from request/response buffer.
|
||||
*/
|
||||
static inline void *smb2_get_msg(void *buf)
|
||||
{
|
||||
return buf + 4;
|
||||
}
|
||||
|
||||
#endif /* _SMB2PDU_H */
|
||||
|
||||
@@ -134,7 +134,7 @@ int ksmbd_lookup_protocol_idx(char *str)
|
||||
*/
|
||||
int ksmbd_verify_smb_message(struct ksmbd_work *work)
|
||||
{
|
||||
struct smb2_hdr *smb2_hdr = work->request_buf + work->next_smb2_rcv_hdr_off;
|
||||
struct smb2_hdr *smb2_hdr = ksmbd_req_buf_next(work);
|
||||
struct smb_hdr *hdr;
|
||||
|
||||
if (smb2_hdr->ProtocolId == SMB2_PROTO_NUMBER)
|
||||
@@ -158,7 +158,19 @@ int ksmbd_verify_smb_message(struct ksmbd_work *work)
|
||||
*/
|
||||
bool ksmbd_smb_request(struct ksmbd_conn *conn)
|
||||
{
|
||||
return conn->request_buf[0] == 0;
|
||||
__le32 *proto = (__le32 *)smb2_get_msg(conn->request_buf);
|
||||
|
||||
if (*proto == SMB2_COMPRESSION_TRANSFORM_ID) {
|
||||
pr_err_ratelimited("smb2 compression not support yet");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (*proto != SMB1_PROTO_NUMBER &&
|
||||
*proto != SMB2_PROTO_NUMBER &&
|
||||
*proto != SMB2_TRANSFORM_PROTO_NUM)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool supported_protocol(int idx)
|
||||
@@ -243,18 +255,18 @@ int ksmbd_lookup_dialect_by_id(__le16 *cli_dialects, __le16 dialects_count)
|
||||
static int ksmbd_negotiate_smb_dialect(void *buf)
|
||||
{
|
||||
int smb_buf_length = get_rfc1002_len(buf);
|
||||
__le32 proto = ((struct smb2_hdr *)buf)->ProtocolId;
|
||||
__le32 proto = ((struct smb2_hdr *)smb2_get_msg(buf))->ProtocolId;
|
||||
|
||||
if (proto == SMB2_PROTO_NUMBER) {
|
||||
struct smb2_negotiate_req *req;
|
||||
int smb2_neg_size =
|
||||
offsetof(struct smb2_negotiate_req, Dialects) - 4;
|
||||
offsetof(struct smb2_negotiate_req, Dialects);
|
||||
|
||||
req = (struct smb2_negotiate_req *)buf;
|
||||
req = (struct smb2_negotiate_req *)smb2_get_msg(buf);
|
||||
if (smb2_neg_size > smb_buf_length)
|
||||
goto err_out;
|
||||
|
||||
if (smb2_neg_size + le16_to_cpu(req->DialectCount) * sizeof(__le16) >
|
||||
if (struct_size(req, Dialects, le16_to_cpu(req->DialectCount)) >
|
||||
smb_buf_length)
|
||||
goto err_out;
|
||||
|
||||
@@ -283,18 +295,127 @@ err_out:
|
||||
return BAD_PROT_ID;
|
||||
}
|
||||
|
||||
#define SMB_COM_NEGOTIATE_EX 0x0
|
||||
|
||||
/**
|
||||
* get_smb1_cmd_val() - get smb command value from smb header
|
||||
* @work: smb work containing smb header
|
||||
*
|
||||
* Return: smb command value
|
||||
*/
|
||||
static u16 get_smb1_cmd_val(struct ksmbd_work *work)
|
||||
{
|
||||
return SMB_COM_NEGOTIATE_EX;
|
||||
}
|
||||
|
||||
/**
|
||||
* init_smb1_rsp_hdr() - initialize smb negotiate response header
|
||||
* @work: smb work containing smb request
|
||||
*
|
||||
* Return: 0 on success, otherwise -EINVAL
|
||||
*/
|
||||
static int init_smb1_rsp_hdr(struct ksmbd_work *work)
|
||||
{
|
||||
struct smb_hdr *rsp_hdr = (struct smb_hdr *)work->response_buf;
|
||||
struct smb_hdr *rcv_hdr = (struct smb_hdr *)work->request_buf;
|
||||
|
||||
rsp_hdr->Command = SMB_COM_NEGOTIATE;
|
||||
*(__le32 *)rsp_hdr->Protocol = SMB1_PROTO_NUMBER;
|
||||
rsp_hdr->Flags = SMBFLG_RESPONSE;
|
||||
rsp_hdr->Flags2 = SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS |
|
||||
SMBFLG2_EXT_SEC | SMBFLG2_IS_LONG_NAME;
|
||||
rsp_hdr->Pid = rcv_hdr->Pid;
|
||||
rsp_hdr->Mid = rcv_hdr->Mid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* smb1_check_user_session() - check for valid session for a user
|
||||
* @work: smb work containing smb request buffer
|
||||
*
|
||||
* Return: 0 on success, otherwise error
|
||||
*/
|
||||
static int smb1_check_user_session(struct ksmbd_work *work)
|
||||
{
|
||||
unsigned int cmd = work->conn->ops->get_cmd_val(work);
|
||||
|
||||
if (cmd == SMB_COM_NEGOTIATE_EX)
|
||||
return 0;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* smb1_allocate_rsp_buf() - allocate response buffer for a command
|
||||
* @work: smb work containing smb request
|
||||
*
|
||||
* Return: 0 on success, otherwise -ENOMEM
|
||||
*/
|
||||
static int smb1_allocate_rsp_buf(struct ksmbd_work *work)
|
||||
{
|
||||
work->response_buf = kzalloc(MAX_CIFS_SMALL_BUFFER_SIZE,
|
||||
GFP_KERNEL);
|
||||
work->response_sz = MAX_CIFS_SMALL_BUFFER_SIZE;
|
||||
|
||||
if (!work->response_buf) {
|
||||
pr_err("Failed to allocate %u bytes buffer\n",
|
||||
MAX_CIFS_SMALL_BUFFER_SIZE);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* set_smb1_rsp_status() - set error type in smb response header
|
||||
* @work: smb work containing smb response header
|
||||
* @err: error code to set in response
|
||||
*/
|
||||
static void set_smb1_rsp_status(struct ksmbd_work *work, __le32 err)
|
||||
{
|
||||
work->send_no_response = 1;
|
||||
}
|
||||
|
||||
static struct smb_version_ops smb1_server_ops = {
|
||||
.get_cmd_val = get_smb1_cmd_val,
|
||||
.init_rsp_hdr = init_smb1_rsp_hdr,
|
||||
.allocate_rsp_buf = smb1_allocate_rsp_buf,
|
||||
.check_user_session = smb1_check_user_session,
|
||||
.set_rsp_status = set_smb1_rsp_status,
|
||||
};
|
||||
|
||||
static int smb1_negotiate(struct ksmbd_work *work)
|
||||
{
|
||||
return ksmbd_smb_negotiate_common(work, SMB_COM_NEGOTIATE);
|
||||
}
|
||||
|
||||
static struct smb_version_cmds smb1_server_cmds[1] = {
|
||||
[SMB_COM_NEGOTIATE_EX] = { .proc = smb1_negotiate, },
|
||||
};
|
||||
|
||||
static int init_smb1_server(struct ksmbd_conn *conn)
|
||||
{
|
||||
conn->ops = &smb1_server_ops;
|
||||
conn->cmds = smb1_server_cmds;
|
||||
conn->max_cmds = ARRAY_SIZE(smb1_server_cmds);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ksmbd_init_smb_server(struct ksmbd_work *work)
|
||||
{
|
||||
struct ksmbd_conn *conn = work->conn;
|
||||
__le32 proto;
|
||||
|
||||
if (conn->need_neg == false)
|
||||
proto = *(__le32 *)((struct smb_hdr *)work->request_buf)->Protocol;
|
||||
if (conn->need_neg == false) {
|
||||
if (proto == SMB1_PROTO_NUMBER)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
init_smb3_11_server(conn);
|
||||
|
||||
if (conn->ops->get_cmd_val(work) != SMB_COM_NEGOTIATE)
|
||||
conn->need_neg = false;
|
||||
return 0;
|
||||
if (proto == SMB1_PROTO_NUMBER)
|
||||
return init_smb1_server(conn);
|
||||
return init_smb3_11_server(conn);
|
||||
}
|
||||
|
||||
int ksmbd_populate_dot_dotdot_entries(struct ksmbd_work *work, int info_level,
|
||||
@@ -444,20 +565,11 @@ static int smb_handle_negotiate(struct ksmbd_work *work)
|
||||
|
||||
ksmbd_debug(SMB, "Unsupported SMB1 protocol\n");
|
||||
|
||||
/*
|
||||
* Remove 4 byte direct TCP header, add 2 byte bcc and
|
||||
* 2 byte DialectIndex.
|
||||
*/
|
||||
*(__be32 *)work->response_buf =
|
||||
cpu_to_be32(sizeof(struct smb_hdr) - 4 + 2 + 2);
|
||||
if (ksmbd_iov_pin_rsp(work, (void *)neg_rsp,
|
||||
sizeof(struct smb_negotiate_rsp) - 4))
|
||||
return -ENOMEM;
|
||||
|
||||
neg_rsp->hdr.Status.CifsError = STATUS_SUCCESS;
|
||||
|
||||
neg_rsp->hdr.Command = SMB_COM_NEGOTIATE;
|
||||
*(__le32 *)neg_rsp->hdr.Protocol = SMB1_PROTO_NUMBER;
|
||||
neg_rsp->hdr.Flags = SMBFLG_RESPONSE;
|
||||
neg_rsp->hdr.Flags2 = SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS |
|
||||
SMBFLG2_EXT_SEC | SMBFLG2_IS_LONG_NAME;
|
||||
|
||||
neg_rsp->hdr.WordCount = 1;
|
||||
neg_rsp->DialectIndex = cpu_to_le16(work->conn->dialect);
|
||||
neg_rsp->ByteCount = 0;
|
||||
@@ -469,27 +581,17 @@ int ksmbd_smb_negotiate_common(struct ksmbd_work *work, unsigned int command)
|
||||
struct ksmbd_conn *conn = work->conn;
|
||||
int ret;
|
||||
|
||||
conn->dialect = ksmbd_negotiate_smb_dialect(work->request_buf);
|
||||
conn->dialect =
|
||||
ksmbd_negotiate_smb_dialect(work->request_buf);
|
||||
ksmbd_debug(SMB, "conn->dialect 0x%x\n", conn->dialect);
|
||||
|
||||
if (command == SMB2_NEGOTIATE_HE) {
|
||||
struct smb2_hdr *smb2_hdr = work->request_buf;
|
||||
|
||||
if (smb2_hdr->ProtocolId != SMB2_PROTO_NUMBER) {
|
||||
ksmbd_debug(SMB, "Downgrade to SMB1 negotiation\n");
|
||||
command = SMB_COM_NEGOTIATE;
|
||||
}
|
||||
}
|
||||
|
||||
if (command == SMB2_NEGOTIATE_HE) {
|
||||
ret = smb2_handle_negotiate(work);
|
||||
init_smb2_neg_rsp(work);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (command == SMB_COM_NEGOTIATE) {
|
||||
if (__smb2_negotiate(conn)) {
|
||||
conn->need_neg = true;
|
||||
init_smb3_11_server(conn);
|
||||
init_smb2_neg_rsp(work);
|
||||
ksmbd_debug(SMB, "Upgrade to SMB2 negotiation\n");
|
||||
|
||||
@@ -247,7 +247,7 @@ struct smb_hdr {
|
||||
struct smb_negotiate_req {
|
||||
struct smb_hdr hdr; /* wct = 0 */
|
||||
__le16 ByteCount;
|
||||
unsigned char DialectsArray[1];
|
||||
unsigned char DialectsArray[];
|
||||
} __packed;
|
||||
|
||||
struct smb_negotiate_rsp {
|
||||
@@ -310,14 +310,14 @@ struct file_directory_info {
|
||||
__le64 AllocationSize;
|
||||
__le32 ExtFileAttributes;
|
||||
__le32 FileNameLength;
|
||||
char FileName[1];
|
||||
char FileName[];
|
||||
} __packed; /* level 0x101 FF resp data */
|
||||
|
||||
struct file_names_info {
|
||||
__le32 NextEntryOffset;
|
||||
__u32 FileIndex;
|
||||
__le32 FileNameLength;
|
||||
char FileName[1];
|
||||
char FileName[];
|
||||
} __packed; /* level 0xc FF resp data */
|
||||
|
||||
struct file_full_directory_info {
|
||||
@@ -332,7 +332,7 @@ struct file_full_directory_info {
|
||||
__le32 ExtFileAttributes;
|
||||
__le32 FileNameLength;
|
||||
__le32 EaSize;
|
||||
char FileName[1];
|
||||
char FileName[];
|
||||
} __packed; /* level 0x102 FF resp */
|
||||
|
||||
struct file_both_directory_info {
|
||||
@@ -350,7 +350,7 @@ struct file_both_directory_info {
|
||||
__u8 ShortNameLength;
|
||||
__u8 Reserved;
|
||||
__u8 ShortName[24];
|
||||
char FileName[1];
|
||||
char FileName[];
|
||||
} __packed; /* level 0x104 FFrsp data */
|
||||
|
||||
struct file_id_both_directory_info {
|
||||
@@ -370,7 +370,7 @@ struct file_id_both_directory_info {
|
||||
__u8 ShortName[24];
|
||||
__le16 Reserved2;
|
||||
__le64 UniqueId;
|
||||
char FileName[1];
|
||||
char FileName[];
|
||||
} __packed;
|
||||
|
||||
struct file_id_full_dir_info {
|
||||
@@ -387,7 +387,7 @@ struct file_id_full_dir_info {
|
||||
__le32 EaSize; /* EA size */
|
||||
__le32 Reserved;
|
||||
__le64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/
|
||||
char FileName[1];
|
||||
char FileName[];
|
||||
} __packed; /* level 0x105 FF rsp data */
|
||||
|
||||
struct smb_version_values {
|
||||
@@ -464,12 +464,6 @@ 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);
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ int compare_sids(const struct smb_sid *ctsid, const struct smb_sid *cwsid)
|
||||
/* compare all of the subauth values if any */
|
||||
num_sat = ctsid->num_subauth;
|
||||
num_saw = cwsid->num_subauth;
|
||||
num_subauth = num_sat < num_saw ? num_sat : num_saw;
|
||||
num_subauth = min(num_sat, num_saw);
|
||||
if (num_subauth) {
|
||||
for (i = 0; i < num_subauth; ++i) {
|
||||
if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) {
|
||||
@@ -991,7 +991,7 @@ static void smb_set_ace(struct smb_ace *ace, const struct smb_sid *sid, u8 type,
|
||||
}
|
||||
|
||||
int smb_inherit_dacl(struct ksmbd_conn *conn,
|
||||
struct path *path,
|
||||
const struct path *path,
|
||||
unsigned int uid, unsigned int gid)
|
||||
{
|
||||
const struct smb_sid *psid, *creator = NULL;
|
||||
@@ -1183,8 +1183,7 @@ pass:
|
||||
pntsd_size += sizeof(struct smb_acl) + nt_size;
|
||||
}
|
||||
|
||||
ksmbd_vfs_set_sd_xattr(conn, user_ns,
|
||||
path->dentry, pntsd, pntsd_size);
|
||||
ksmbd_vfs_set_sd_xattr(conn, user_ns, path, pntsd, pntsd_size, false);
|
||||
kfree(pntsd);
|
||||
}
|
||||
|
||||
@@ -1208,7 +1207,7 @@ bool smb_inherit_flags(int flags, bool is_dir)
|
||||
return false;
|
||||
}
|
||||
|
||||
int smb_check_perm_dacl(struct ksmbd_conn *conn, struct path *path,
|
||||
int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
|
||||
__le32 *pdaccess, int uid)
|
||||
{
|
||||
struct user_namespace *user_ns = mnt_user_ns(path->mnt);
|
||||
@@ -1311,7 +1310,7 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, struct path *path,
|
||||
|
||||
if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) {
|
||||
posix_acls = get_acl(d_inode(path->dentry), ACL_TYPE_ACCESS);
|
||||
if (posix_acls && !found) {
|
||||
if (!IS_ERR_OR_NULL(posix_acls) && !found) {
|
||||
unsigned int id = -1;
|
||||
|
||||
pa_entry = posix_acls->a_entries;
|
||||
@@ -1335,7 +1334,7 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, struct path *path,
|
||||
}
|
||||
}
|
||||
}
|
||||
if (posix_acls)
|
||||
if (!IS_ERR_OR_NULL(posix_acls))
|
||||
posix_acl_release(posix_acls);
|
||||
}
|
||||
|
||||
@@ -1375,8 +1374,8 @@ err_out:
|
||||
}
|
||||
|
||||
int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon,
|
||||
struct path *path, struct smb_ntsd *pntsd, int ntsd_len,
|
||||
bool type_check)
|
||||
const struct path *path, struct smb_ntsd *pntsd, int ntsd_len,
|
||||
bool type_check, bool get_write)
|
||||
{
|
||||
int rc;
|
||||
struct smb_fattr fattr = {{0}};
|
||||
@@ -1404,7 +1403,7 @@ int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon,
|
||||
newattrs.ia_valid |= ATTR_MODE;
|
||||
newattrs.ia_mode = (inode->i_mode & ~0777) | (fattr.cf_mode & 0777);
|
||||
|
||||
ksmbd_vfs_remove_acl_xattrs(user_ns, path->dentry);
|
||||
ksmbd_vfs_remove_acl_xattrs(user_ns, path);
|
||||
/* Update posix acls */
|
||||
if (IS_ENABLED(CONFIG_FS_POSIX_ACL) && fattr.cf_dacls) {
|
||||
rc = set_posix_acl(user_ns, inode,
|
||||
@@ -1435,15 +1434,14 @@ 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(user_ns, path->dentry);
|
||||
ksmbd_vfs_set_sd_xattr(conn, user_ns,
|
||||
path->dentry, pntsd, ntsd_len);
|
||||
ksmbd_vfs_remove_sd_xattrs(user_ns, path);
|
||||
ksmbd_vfs_set_sd_xattr(conn, user_ns, path, pntsd, ntsd_len,
|
||||
get_write);
|
||||
}
|
||||
|
||||
out:
|
||||
posix_acl_release(fattr.cf_acls);
|
||||
posix_acl_release(fattr.cf_dacls);
|
||||
mark_inode_dirty(inode);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -201,13 +201,13 @@ 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 path *path,
|
||||
int smb_inherit_dacl(struct ksmbd_conn *conn, const struct path *path,
|
||||
unsigned int uid, unsigned int gid);
|
||||
int smb_check_perm_dacl(struct ksmbd_conn *conn, struct path *path,
|
||||
int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
|
||||
__le32 *pdaccess, int uid);
|
||||
int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon,
|
||||
struct path *path, struct smb_ntsd *pntsd, int ntsd_len,
|
||||
bool type_check);
|
||||
const struct path *path, struct smb_ntsd *pntsd, int ntsd_len,
|
||||
bool type_check, bool get_write);
|
||||
void id_to_sid(unsigned int cid, uint sidtype, struct smb_sid *ssid);
|
||||
void ksmbd_init_domain(u32 *sub_auth);
|
||||
|
||||
|
||||
@@ -228,7 +228,7 @@ static struct ksmbd_ipc_msg *ipc_msg_alloc(size_t sz)
|
||||
struct ksmbd_ipc_msg *msg;
|
||||
size_t msg_sz = sz + sizeof(struct ksmbd_ipc_msg);
|
||||
|
||||
msg = kvmalloc(msg_sz, GFP_KERNEL | __GFP_ZERO);
|
||||
msg = kvzalloc(msg_sz, GFP_KERNEL);
|
||||
if (msg)
|
||||
msg->sz = sz;
|
||||
return msg;
|
||||
@@ -267,7 +267,7 @@ static int handle_response(int type, void *payload, size_t sz)
|
||||
entry->type + 1, type);
|
||||
}
|
||||
|
||||
entry->response = kvmalloc(sz, GFP_KERNEL | __GFP_ZERO);
|
||||
entry->response = kvzalloc(sz, GFP_KERNEL);
|
||||
if (!entry->response) {
|
||||
ret = -ENOMEM;
|
||||
break;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,8 +7,6 @@
|
||||
#ifndef __KSMBD_TRANSPORT_RDMA_H__
|
||||
#define __KSMBD_TRANSPORT_RDMA_H__
|
||||
|
||||
#define SMB_DIRECT_PORT 5445
|
||||
|
||||
#define SMBD_DEFAULT_IOSIZE (8 * 1024 * 1024)
|
||||
#define SMBD_MIN_IOSIZE (512 * 1024)
|
||||
#define SMBD_MAX_IOSIZE (16 * 1024 * 1024)
|
||||
@@ -56,14 +54,16 @@ struct smb_direct_data_transfer {
|
||||
|
||||
#ifdef CONFIG_SMB_SERVER_SMBDIRECT
|
||||
int ksmbd_rdma_init(void);
|
||||
int ksmbd_rdma_destroy(void);
|
||||
void ksmbd_rdma_destroy(void);
|
||||
bool ksmbd_rdma_capable_netdev(struct net_device *netdev);
|
||||
void init_smbd_max_io_size(unsigned int sz);
|
||||
unsigned int get_smbd_max_read_write_size(void);
|
||||
#else
|
||||
static inline int ksmbd_rdma_init(void) { return 0; }
|
||||
static inline int ksmbd_rdma_destroy(void) { return 0; }
|
||||
static inline bool ksmbd_rdma_capable_netdev(struct net_device *netdev) { return false; }
|
||||
static inline void init_smbd_max_io_size(unsigned int sz) { }
|
||||
static inline unsigned int get_smbd_max_read_write_size(void) { return 0; }
|
||||
#endif
|
||||
|
||||
#endif /* __KSMBD_TRANSPORT_RDMA_H__ */
|
||||
|
||||
@@ -333,7 +333,7 @@ static int ksmbd_tcp_readv(struct tcp_transport *t, struct kvec *iov_orig,
|
||||
if (length == -EINTR) {
|
||||
total_read = -ESHUTDOWN;
|
||||
break;
|
||||
} else if (conn->status == KSMBD_SESS_NEED_RECONNECT) {
|
||||
} else if (ksmbd_conn_need_reconnect(conn)) {
|
||||
total_read = -EAGAIN;
|
||||
break;
|
||||
} else if (length == -ERESTARTSYS || length == -EAGAIN) {
|
||||
@@ -428,7 +428,8 @@ static int create_socket(struct interface *iface)
|
||||
|
||||
ret = sock_create(PF_INET6, SOCK_STREAM, IPPROTO_TCP, &ksmbd_socket);
|
||||
if (ret) {
|
||||
pr_err("Can't create socket for ipv6, try ipv4: %d\n", ret);
|
||||
if (ret != -EAFNOSUPPORT)
|
||||
pr_err("Can't create socket for ipv6, fallback to ipv4: %d\n", ret);
|
||||
ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP,
|
||||
&ksmbd_socket);
|
||||
if (ret) {
|
||||
@@ -505,7 +506,7 @@ static int ksmbd_netdev_event(struct notifier_block *nb, unsigned long event,
|
||||
|
||||
switch (event) {
|
||||
case NETDEV_UP:
|
||||
if (netdev->priv_flags & IFF_BRIDGE_PORT)
|
||||
if (netif_is_bridge_port(netdev))
|
||||
return NOTIFY_OK;
|
||||
|
||||
list_for_each_entry(iface, &iface_list, entry) {
|
||||
@@ -614,7 +615,7 @@ int ksmbd_tcp_set_interfaces(char *ifc_list, int ifc_list_sz)
|
||||
|
||||
rtnl_lock();
|
||||
for_each_netdev(&init_net, netdev) {
|
||||
if (netdev->priv_flags & IFF_BRIDGE_PORT)
|
||||
if (netif_is_bridge_port(netdev))
|
||||
continue;
|
||||
if (!alloc_iface(kstrdup(netdev->name, GFP_KERNEL)))
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -14,46 +14,10 @@
|
||||
#include "uniupr.h"
|
||||
#include "smb_common.h"
|
||||
|
||||
/*
|
||||
* smb_utf16_bytes() - how long will a string be after conversion?
|
||||
* @from: pointer to input string
|
||||
* @maxbytes: don't go past this many bytes of input string
|
||||
* @codepage: destination codepage
|
||||
*
|
||||
* Walk a utf16le string and return the number of bytes that the string will
|
||||
* be after being converted to the given charset, not including any null
|
||||
* termination required. Don't walk past maxbytes in the source buffer.
|
||||
*
|
||||
* Return: string length after conversion
|
||||
*/
|
||||
static int smb_utf16_bytes(const __le16 *from, int maxbytes,
|
||||
const struct nls_table *codepage)
|
||||
{
|
||||
int i;
|
||||
int charlen, outlen = 0;
|
||||
int maxwords = maxbytes / 2;
|
||||
char tmp[NLS_MAX_CHARSET_SIZE];
|
||||
__u16 ftmp;
|
||||
|
||||
for (i = 0; i < maxwords; i++) {
|
||||
ftmp = get_unaligned_le16(&from[i]);
|
||||
if (ftmp == 0)
|
||||
break;
|
||||
|
||||
charlen = codepage->uni2char(ftmp, tmp, NLS_MAX_CHARSET_SIZE);
|
||||
if (charlen > 0)
|
||||
outlen += charlen;
|
||||
else
|
||||
outlen++;
|
||||
}
|
||||
|
||||
return outlen;
|
||||
}
|
||||
|
||||
/*
|
||||
* cifs_mapchar() - convert a host-endian char to proper char in codepage
|
||||
* @target: where converted character should be copied
|
||||
* @src_char: 2 byte host-endian source character
|
||||
* @from: host-endian source string
|
||||
* @cp: codepage to which character should be converted
|
||||
* @mapchar: should character be mapped according to mapchars mount option?
|
||||
*
|
||||
@@ -64,10 +28,13 @@ static int smb_utf16_bytes(const __le16 *from, int maxbytes,
|
||||
* Return: string length after conversion
|
||||
*/
|
||||
static int
|
||||
cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp,
|
||||
cifs_mapchar(char *target, const __u16 *from, const struct nls_table *cp,
|
||||
bool mapchar)
|
||||
{
|
||||
int len = 1;
|
||||
__u16 src_char;
|
||||
|
||||
src_char = *from;
|
||||
|
||||
if (!mapchar)
|
||||
goto cp_convert;
|
||||
@@ -105,30 +72,66 @@ out:
|
||||
|
||||
cp_convert:
|
||||
len = cp->uni2char(src_char, target, NLS_MAX_CHARSET_SIZE);
|
||||
if (len <= 0) {
|
||||
*target = '?';
|
||||
len = 1;
|
||||
}
|
||||
if (len <= 0)
|
||||
goto surrogate_pair;
|
||||
|
||||
goto out;
|
||||
|
||||
surrogate_pair:
|
||||
/* convert SURROGATE_PAIR and IVS */
|
||||
if (strcmp(cp->charset, "utf8"))
|
||||
goto unknown;
|
||||
len = utf16s_to_utf8s(from, 3, UTF16_LITTLE_ENDIAN, target, 6);
|
||||
if (len <= 0)
|
||||
goto unknown;
|
||||
return len;
|
||||
|
||||
unknown:
|
||||
*target = '?';
|
||||
len = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* is_char_allowed() - check for valid character
|
||||
* @ch: input character to be checked
|
||||
* smb_utf16_bytes() - compute converted string length
|
||||
* @from: pointer to input string
|
||||
* @maxbytes: input string length
|
||||
* @codepage: destination codepage
|
||||
*
|
||||
* Return: 1 if char is allowed, otherwise 0
|
||||
* Walk a utf16le string and return the number of bytes that the string will
|
||||
* be after being converted to the given charset, not including any null
|
||||
* termination required. Don't walk past maxbytes in the source buffer.
|
||||
*
|
||||
* Return: string length after conversion
|
||||
*/
|
||||
static inline int is_char_allowed(char *ch)
|
||||
static int smb_utf16_bytes(const __le16 *from, int maxbytes,
|
||||
const struct nls_table *codepage)
|
||||
{
|
||||
/* check for control chars, wildcards etc. */
|
||||
if (!(*ch & 0x80) &&
|
||||
(*ch <= 0x1f ||
|
||||
*ch == '?' || *ch == '"' || *ch == '<' ||
|
||||
*ch == '>' || *ch == '|'))
|
||||
return 0;
|
||||
int i, j;
|
||||
int charlen, outlen = 0;
|
||||
int maxwords = maxbytes / 2;
|
||||
char tmp[NLS_MAX_CHARSET_SIZE];
|
||||
__u16 ftmp[3];
|
||||
|
||||
return 1;
|
||||
for (i = 0; i < maxwords; i++) {
|
||||
ftmp[0] = get_unaligned_le16(&from[i]);
|
||||
if (ftmp[0] == 0)
|
||||
break;
|
||||
for (j = 1; j <= 2; j++) {
|
||||
if (i + j < maxwords)
|
||||
ftmp[j] = get_unaligned_le16(&from[i + j]);
|
||||
else
|
||||
ftmp[j] = 0;
|
||||
}
|
||||
|
||||
charlen = cifs_mapchar(tmp, ftmp, codepage, 0);
|
||||
if (charlen > 0)
|
||||
outlen += charlen;
|
||||
else
|
||||
outlen++;
|
||||
}
|
||||
|
||||
return outlen;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -158,12 +161,12 @@ static inline int is_char_allowed(char *ch)
|
||||
static int smb_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
|
||||
const struct nls_table *codepage, bool mapchar)
|
||||
{
|
||||
int i, charlen, safelen;
|
||||
int i, j, charlen, safelen;
|
||||
int outlen = 0;
|
||||
int nullsize = nls_nullsize(codepage);
|
||||
int fromwords = fromlen / 2;
|
||||
char tmp[NLS_MAX_CHARSET_SIZE];
|
||||
__u16 ftmp;
|
||||
__u16 ftmp[3]; /* ftmp[3] = 3array x 2bytes = 6bytes UTF-16 */
|
||||
|
||||
/*
|
||||
* because the chars can be of varying widths, we need to take care
|
||||
@@ -174,9 +177,15 @@ static int smb_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
|
||||
safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize);
|
||||
|
||||
for (i = 0; i < fromwords; i++) {
|
||||
ftmp = get_unaligned_le16(&from[i]);
|
||||
if (ftmp == 0)
|
||||
ftmp[0] = get_unaligned_le16(&from[i]);
|
||||
if (ftmp[0] == 0)
|
||||
break;
|
||||
for (j = 1; j <= 2; j++) {
|
||||
if (i + j < fromwords)
|
||||
ftmp[j] = get_unaligned_le16(&from[i + j]);
|
||||
else
|
||||
ftmp[j] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* check to see if converting this character might make the
|
||||
@@ -191,6 +200,19 @@ static int smb_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
|
||||
/* put converted char into 'to' buffer */
|
||||
charlen = cifs_mapchar(&to[outlen], ftmp, codepage, mapchar);
|
||||
outlen += charlen;
|
||||
|
||||
/*
|
||||
* charlen (=bytes of UTF-8 for 1 character)
|
||||
* 4bytes UTF-8(surrogate pair) is charlen=4
|
||||
* (4bytes UTF-16 code)
|
||||
* 7-8bytes UTF-8(IVS) is charlen=3+4 or 4+4
|
||||
* (2 UTF-8 pairs divided to 2 UTF-16 pairs)
|
||||
*/
|
||||
if (charlen == 4)
|
||||
i++;
|
||||
else if (charlen >= 5)
|
||||
/* 5-6bytes UTF-8 */
|
||||
i += 2;
|
||||
}
|
||||
|
||||
/* properly null-terminate string */
|
||||
@@ -325,6 +347,9 @@ int smbConvertToUTF16(__le16 *target, const char *source, int srclen,
|
||||
char src_char;
|
||||
__le16 dst_char;
|
||||
wchar_t tmp;
|
||||
wchar_t wchar_to[6]; /* UTF-16 */
|
||||
int ret;
|
||||
unicode_t u;
|
||||
|
||||
if (!mapchars)
|
||||
return smb_strtoUTF16(target, source, srclen, cp);
|
||||
@@ -367,11 +392,57 @@ int smbConvertToUTF16(__le16 *target, const char *source, int srclen,
|
||||
* if no match, use question mark, which at least in
|
||||
* some cases serves as wild card
|
||||
*/
|
||||
if (charlen < 1) {
|
||||
dst_char = cpu_to_le16(0x003f);
|
||||
charlen = 1;
|
||||
if (charlen > 0)
|
||||
goto ctoUTF16;
|
||||
|
||||
/* convert SURROGATE_PAIR */
|
||||
if (strcmp(cp->charset, "utf8"))
|
||||
goto unknown;
|
||||
if (*(source + i) & 0x80) {
|
||||
charlen = utf8_to_utf32(source + i, 6, &u);
|
||||
if (charlen < 0)
|
||||
goto unknown;
|
||||
} else
|
||||
goto unknown;
|
||||
ret = utf8s_to_utf16s(source + i, charlen,
|
||||
UTF16_LITTLE_ENDIAN,
|
||||
wchar_to, 6);
|
||||
if (ret < 0)
|
||||
goto unknown;
|
||||
|
||||
i += charlen;
|
||||
dst_char = cpu_to_le16(*wchar_to);
|
||||
if (charlen <= 3)
|
||||
/* 1-3bytes UTF-8 to 2bytes UTF-16 */
|
||||
put_unaligned(dst_char, &target[j]);
|
||||
else if (charlen == 4) {
|
||||
/*
|
||||
* 4bytes UTF-8(surrogate pair) to 4bytes UTF-16
|
||||
* 7-8bytes UTF-8(IVS) divided to 2 UTF-16
|
||||
* (charlen=3+4 or 4+4)
|
||||
*/
|
||||
put_unaligned(dst_char, &target[j]);
|
||||
dst_char = cpu_to_le16(*(wchar_to + 1));
|
||||
j++;
|
||||
put_unaligned(dst_char, &target[j]);
|
||||
} else if (charlen >= 5) {
|
||||
/* 5-6bytes UTF-8 to 6bytes UTF-16 */
|
||||
put_unaligned(dst_char, &target[j]);
|
||||
dst_char = cpu_to_le16(*(wchar_to + 1));
|
||||
j++;
|
||||
put_unaligned(dst_char, &target[j]);
|
||||
dst_char = cpu_to_le16(*(wchar_to + 2));
|
||||
j++;
|
||||
put_unaligned(dst_char, &target[j]);
|
||||
}
|
||||
continue;
|
||||
|
||||
unknown:
|
||||
dst_char = cpu_to_le16(0x003f);
|
||||
charlen = 1;
|
||||
}
|
||||
|
||||
ctoUTF16:
|
||||
/*
|
||||
* character may take more than one byte in the source string,
|
||||
* but will take exactly two bytes in the target string
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <asm/byteorder.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/nls.h>
|
||||
#include <linux/unicode.h>
|
||||
|
||||
#define UNIUPR_NOLOWER /* Example to not expand lower case tables */
|
||||
|
||||
@@ -69,7 +70,7 @@ char *smb_strndup_from_utf16(const char *src, const int maxlen,
|
||||
const struct nls_table *codepage);
|
||||
int smbConvertToUTF16(__le16 *target, const char *source, int srclen,
|
||||
const struct nls_table *cp, int mapchars);
|
||||
char *ksmbd_extract_sharename(char *treename);
|
||||
char *ksmbd_extract_sharename(struct unicode_map *um, const char *treename);
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
||||
677
fs/ksmbd/vfs.c
677
fs/ksmbd/vfs.c
File diff suppressed because it is too large
Load Diff
@@ -12,6 +12,7 @@
|
||||
#include <linux/namei.h>
|
||||
#include <uapi/linux/xattr.h>
|
||||
#include <linux/posix_acl.h>
|
||||
#include <linux/unicode.h>
|
||||
|
||||
#include "smbacl.h"
|
||||
#include "xattr.h"
|
||||
@@ -99,6 +100,7 @@ struct ksmbd_readdir_data {
|
||||
unsigned int used;
|
||||
unsigned int dirent_count;
|
||||
unsigned int file_attr;
|
||||
struct unicode_map *um;
|
||||
};
|
||||
|
||||
/* ksmbd kstat wrapper to get valid create time when reading dir entry */
|
||||
@@ -108,25 +110,23 @@ struct ksmbd_kstat {
|
||||
__le32 file_attributes;
|
||||
};
|
||||
|
||||
int ksmbd_vfs_lock_parent(struct user_namespace *user_ns, 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,
|
||||
int ksmbd_vfs_lock_parent(struct dentry *parent, struct dentry *child);
|
||||
void 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,
|
||||
size_t count, loff_t *pos);
|
||||
int ksmbd_vfs_read(struct ksmbd_work *work, struct ksmbd_file *fp, size_t count,
|
||||
loff_t *pos, char *rbuf);
|
||||
int ksmbd_vfs_write(struct ksmbd_work *work, struct ksmbd_file *fp,
|
||||
char *buf, size_t count, loff_t *pos, bool sync,
|
||||
ssize_t *written);
|
||||
int ksmbd_vfs_fsync(struct ksmbd_work *work, u64 fid, u64 p_id);
|
||||
int ksmbd_vfs_remove_file(struct ksmbd_work *work, char *name);
|
||||
int ksmbd_vfs_remove_file(struct ksmbd_work *work, const struct path *path);
|
||||
int ksmbd_vfs_link(struct ksmbd_work *work,
|
||||
const char *oldname, const char *newname);
|
||||
int ksmbd_vfs_getattr(struct path *path, struct kstat *stat);
|
||||
int ksmbd_vfs_fp_rename(struct ksmbd_work *work, struct ksmbd_file *fp,
|
||||
char *newname);
|
||||
int ksmbd_vfs_getattr(const struct path *path, struct kstat *stat);
|
||||
int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path,
|
||||
char *newname, int flags);
|
||||
int ksmbd_vfs_truncate(struct ksmbd_work *work,
|
||||
struct ksmbd_file *fp, loff_t size);
|
||||
struct srv_copychunk;
|
||||
@@ -147,15 +147,17 @@ 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 user_namespace *user_ns,
|
||||
struct dentry *dentry, const char *attr_name,
|
||||
const void *attr_value, size_t attr_size, int flags);
|
||||
const struct path *path, const char *attr_name,
|
||||
const void *attr_value, size_t attr_size, int flags,
|
||||
bool get_write);
|
||||
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 user_namespace *user_ns,
|
||||
struct dentry *dentry, char *attr_name);
|
||||
int ksmbd_vfs_kern_path(struct ksmbd_work *work,
|
||||
char *name, unsigned int flags, struct path *path,
|
||||
bool caseless);
|
||||
const struct path *path, char *attr_name);
|
||||
int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *name,
|
||||
unsigned int flags, struct path *parent_path,
|
||||
struct path *path, bool caseless);
|
||||
void ksmbd_vfs_kern_path_unlock(struct path *parent_path, struct path *path);
|
||||
struct dentry *ksmbd_vfs_kern_path_create(struct ksmbd_work *work,
|
||||
const char *name,
|
||||
unsigned int flags,
|
||||
@@ -168,8 +170,7 @@ 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,
|
||||
unsigned int in_count, unsigned int *out_count);
|
||||
int ksmbd_vfs_unlink(struct user_namespace *user_ns,
|
||||
struct dentry *dir, struct dentry *dentry);
|
||||
int ksmbd_vfs_unlink(struct file *filp);
|
||||
void *ksmbd_vfs_init_kstat(char **p, struct ksmbd_kstat *ksmbd_kstat);
|
||||
int ksmbd_vfs_fill_dentry_attrs(struct ksmbd_work *work,
|
||||
struct user_namespace *user_ns,
|
||||
@@ -179,26 +180,27 @@ void 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 user_namespace *user_ns,
|
||||
struct dentry *dentry);
|
||||
int ksmbd_vfs_remove_sd_xattrs(struct user_namespace *user_ns,
|
||||
struct dentry *dentry);
|
||||
const struct path *path);
|
||||
int ksmbd_vfs_remove_sd_xattrs(struct user_namespace *user_ns, const struct path *path);
|
||||
int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn,
|
||||
struct user_namespace *user_ns,
|
||||
struct dentry *dentry,
|
||||
struct smb_ntsd *pntsd, int len);
|
||||
const struct path *path,
|
||||
struct smb_ntsd *pntsd, int len,
|
||||
bool get_write);
|
||||
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 user_namespace *user_ns,
|
||||
struct dentry *dentry,
|
||||
struct xattr_dos_attrib *da);
|
||||
const struct path *path,
|
||||
struct xattr_dos_attrib *da,
|
||||
bool get_write);
|
||||
int ksmbd_vfs_get_dos_attrib_xattr(struct user_namespace *user_ns,
|
||||
struct dentry *dentry,
|
||||
struct xattr_dos_attrib *da);
|
||||
int ksmbd_vfs_set_init_posix_acl(struct user_namespace *user_ns,
|
||||
struct inode *inode);
|
||||
struct path *path);
|
||||
int ksmbd_vfs_inherit_posix_acl(struct user_namespace *user_ns,
|
||||
struct inode *inode,
|
||||
struct path *path,
|
||||
struct inode *parent_inode);
|
||||
#endif /* __KSMBD_VFS_H__ */
|
||||
|
||||
@@ -65,14 +65,14 @@ static unsigned long inode_hash(struct super_block *sb, unsigned long hashval)
|
||||
return tmp & inode_hash_mask;
|
||||
}
|
||||
|
||||
static struct ksmbd_inode *__ksmbd_inode_lookup(struct inode *inode)
|
||||
static struct ksmbd_inode *__ksmbd_inode_lookup(struct dentry *de)
|
||||
{
|
||||
struct hlist_head *head = inode_hashtable +
|
||||
inode_hash(inode->i_sb, inode->i_ino);
|
||||
inode_hash(d_inode(de)->i_sb, (unsigned long)de);
|
||||
struct ksmbd_inode *ci = NULL, *ret_ci = NULL;
|
||||
|
||||
hlist_for_each_entry(ci, head, m_hash) {
|
||||
if (ci->m_inode == inode) {
|
||||
if (ci->m_de == de) {
|
||||
if (atomic_inc_not_zero(&ci->m_count))
|
||||
ret_ci = ci;
|
||||
break;
|
||||
@@ -83,26 +83,16 @@ 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(file_inode(fp->filp));
|
||||
return __ksmbd_inode_lookup(fp->filp->f_path.dentry);
|
||||
}
|
||||
|
||||
static struct ksmbd_inode *ksmbd_inode_lookup_by_vfsinode(struct inode *inode)
|
||||
{
|
||||
struct ksmbd_inode *ci;
|
||||
|
||||
read_lock(&inode_hash_lock);
|
||||
ci = __ksmbd_inode_lookup(inode);
|
||||
read_unlock(&inode_hash_lock);
|
||||
return ci;
|
||||
}
|
||||
|
||||
int ksmbd_query_inode_status(struct inode *inode)
|
||||
int ksmbd_query_inode_status(struct dentry *dentry)
|
||||
{
|
||||
struct ksmbd_inode *ci;
|
||||
int ret = KSMBD_INODE_STATUS_UNKNOWN;
|
||||
|
||||
read_lock(&inode_hash_lock);
|
||||
ci = __ksmbd_inode_lookup(inode);
|
||||
ci = __ksmbd_inode_lookup(dentry);
|
||||
if (ci) {
|
||||
ret = KSMBD_INODE_STATUS_OK;
|
||||
if (ci->m_flags & (S_DEL_PENDING | S_DEL_ON_CLS))
|
||||
@@ -142,7 +132,7 @@ void ksmbd_fd_set_delete_on_close(struct ksmbd_file *fp,
|
||||
static void ksmbd_inode_hash(struct ksmbd_inode *ci)
|
||||
{
|
||||
struct hlist_head *b = inode_hashtable +
|
||||
inode_hash(ci->m_inode->i_sb, ci->m_inode->i_ino);
|
||||
inode_hash(d_inode(ci->m_de)->i_sb, (unsigned long)ci->m_de);
|
||||
|
||||
hlist_add_head(&ci->m_hash, b);
|
||||
}
|
||||
@@ -156,7 +146,6 @@ 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 = file_inode(fp->filp);
|
||||
atomic_set(&ci->m_count, 1);
|
||||
atomic_set(&ci->op_count, 0);
|
||||
atomic_set(&ci->sop_count, 0);
|
||||
@@ -165,6 +154,7 @@ static int ksmbd_inode_init(struct ksmbd_inode *ci, struct ksmbd_file *fp)
|
||||
INIT_LIST_HEAD(&ci->m_fp_list);
|
||||
INIT_LIST_HEAD(&ci->m_op_list);
|
||||
rwlock_init(&ci->m_lock);
|
||||
ci->m_de = fp->filp->f_path.dentry;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -243,7 +233,6 @@ void ksmbd_release_inode_hash(void)
|
||||
|
||||
static void __ksmbd_inode_close(struct ksmbd_file *fp)
|
||||
{
|
||||
struct dentry *dir, *dentry;
|
||||
struct ksmbd_inode *ci = fp->f_ci;
|
||||
int err;
|
||||
struct file *filp;
|
||||
@@ -252,7 +241,7 @@ static void __ksmbd_inode_close(struct ksmbd_file *fp)
|
||||
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(file_mnt_user_ns(filp),
|
||||
filp->f_path.dentry,
|
||||
&filp->f_path,
|
||||
fp->stream.name);
|
||||
if (err)
|
||||
pr_err("remove xattr failed : %s\n",
|
||||
@@ -262,11 +251,9 @@ static void __ksmbd_inode_close(struct ksmbd_file *fp)
|
||||
if (atomic_dec_and_test(&ci->m_count)) {
|
||||
write_lock(&ci->m_lock);
|
||||
if (ci->m_flags & (S_DEL_ON_CLS | S_DEL_PENDING)) {
|
||||
dentry = filp->f_path.dentry;
|
||||
dir = dentry->d_parent;
|
||||
ci->m_flags &= ~(S_DEL_ON_CLS | S_DEL_PENDING);
|
||||
write_unlock(&ci->m_lock);
|
||||
ksmbd_vfs_unlink(file_mnt_user_ns(filp), dir, dentry);
|
||||
ksmbd_vfs_unlink(filp);
|
||||
write_lock(&ci->m_lock);
|
||||
}
|
||||
write_unlock(&ci->m_lock);
|
||||
@@ -328,7 +315,6 @@ static void __ksmbd_close_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp)
|
||||
kfree(smb_lock);
|
||||
}
|
||||
|
||||
kfree(fp->filename);
|
||||
if (ksmbd_stream_fd(fp))
|
||||
kfree(fp->stream.name);
|
||||
kmem_cache_free(filp_cache, fp);
|
||||
@@ -336,6 +322,9 @@ static void __ksmbd_close_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp)
|
||||
|
||||
static struct ksmbd_file *ksmbd_fp_get(struct ksmbd_file *fp)
|
||||
{
|
||||
if (fp->f_state != FP_INITED)
|
||||
return NULL;
|
||||
|
||||
if (!atomic_inc_not_zero(&fp->refcount))
|
||||
return NULL;
|
||||
return fp;
|
||||
@@ -365,12 +354,11 @@ static void __put_fd_final(struct ksmbd_work *work, struct ksmbd_file *fp)
|
||||
|
||||
static void set_close_state_blocked_works(struct ksmbd_file *fp)
|
||||
{
|
||||
struct ksmbd_work *cancel_work, *ctmp;
|
||||
struct ksmbd_work *cancel_work;
|
||||
|
||||
spin_lock(&fp->f_lock);
|
||||
list_for_each_entry_safe(cancel_work, ctmp, &fp->blocked_works,
|
||||
list_for_each_entry(cancel_work, &fp->blocked_works,
|
||||
fp_entry) {
|
||||
list_del(&cancel_work->fp_entry);
|
||||
cancel_work->state = KSMBD_WORK_CLOSED;
|
||||
cancel_work->cancel_fn(cancel_work->cancel_argv);
|
||||
}
|
||||
@@ -386,15 +374,20 @@ int ksmbd_close_fd(struct ksmbd_work *work, u64 id)
|
||||
return 0;
|
||||
|
||||
ft = &work->sess->file_table;
|
||||
read_lock(&ft->lock);
|
||||
write_lock(&ft->lock);
|
||||
fp = idr_find(ft->idr, id);
|
||||
if (fp) {
|
||||
set_close_state_blocked_works(fp);
|
||||
|
||||
if (!atomic_dec_and_test(&fp->refcount))
|
||||
if (fp->f_state != FP_INITED)
|
||||
fp = NULL;
|
||||
else {
|
||||
fp->f_state = FP_CLOSED;
|
||||
if (!atomic_dec_and_test(&fp->refcount))
|
||||
fp = NULL;
|
||||
}
|
||||
}
|
||||
read_unlock(&ft->lock);
|
||||
write_unlock(&ft->lock);
|
||||
|
||||
if (!fp)
|
||||
return -EINVAL;
|
||||
@@ -484,12 +477,15 @@ struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid)
|
||||
return fp;
|
||||
}
|
||||
|
||||
struct ksmbd_file *ksmbd_lookup_fd_inode(struct inode *inode)
|
||||
struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry)
|
||||
{
|
||||
struct ksmbd_file *lfp;
|
||||
struct ksmbd_inode *ci;
|
||||
struct inode *inode = d_inode(dentry);
|
||||
|
||||
ci = ksmbd_inode_lookup_by_vfsinode(inode);
|
||||
read_lock(&inode_hash_lock);
|
||||
ci = __ksmbd_inode_lookup(dentry);
|
||||
read_unlock(&inode_hash_lock);
|
||||
if (!ci)
|
||||
return NULL;
|
||||
|
||||
@@ -574,6 +570,7 @@ struct ksmbd_file *ksmbd_open_fd(struct ksmbd_work *work, struct file *filp)
|
||||
fp->tcon = work->tcon;
|
||||
fp->volatile_id = KSMBD_NO_FID;
|
||||
fp->persistent_id = KSMBD_NO_FID;
|
||||
fp->f_state = FP_NEW;
|
||||
fp->f_ci = ksmbd_inode_get(fp);
|
||||
|
||||
if (!fp->f_ci) {
|
||||
@@ -595,6 +592,17 @@ err_out:
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
void ksmbd_update_fstate(struct ksmbd_file_table *ft, struct ksmbd_file *fp,
|
||||
unsigned int state)
|
||||
{
|
||||
if (!fp)
|
||||
return;
|
||||
|
||||
write_lock(&ft->lock);
|
||||
fp->f_state = state;
|
||||
write_unlock(&ft->lock);
|
||||
}
|
||||
|
||||
static int
|
||||
__close_file_table_ids(struct ksmbd_file_table *ft,
|
||||
struct ksmbd_tree_connect *tcon,
|
||||
|
||||
@@ -51,7 +51,7 @@ struct ksmbd_inode {
|
||||
atomic_t op_count;
|
||||
/* opinfo count for streams */
|
||||
atomic_t sop_count;
|
||||
struct inode *m_inode;
|
||||
struct dentry *m_de;
|
||||
unsigned int m_flags;
|
||||
struct hlist_node m_hash;
|
||||
struct list_head m_fp_list;
|
||||
@@ -60,9 +60,14 @@ struct ksmbd_inode {
|
||||
__le32 m_fattr;
|
||||
};
|
||||
|
||||
enum {
|
||||
FP_NEW = 0,
|
||||
FP_INITED,
|
||||
FP_CLOSED
|
||||
};
|
||||
|
||||
struct ksmbd_file {
|
||||
struct file *filp;
|
||||
char *filename;
|
||||
u64 persistent_id;
|
||||
u64 volatile_id;
|
||||
|
||||
@@ -96,19 +101,10 @@ struct ksmbd_file {
|
||||
|
||||
int durable_timeout;
|
||||
|
||||
/* for SMB1 */
|
||||
int pid;
|
||||
|
||||
/* conflict lock fail count for SMB1 */
|
||||
unsigned int cflock_cnt;
|
||||
/* last lock failure start offset for SMB1 */
|
||||
unsigned long long llock_fstart;
|
||||
|
||||
int dirent_offset;
|
||||
|
||||
/* if ls is happening on directory, below is valid*/
|
||||
struct ksmbd_readdir_data readdir_data;
|
||||
int dot_dotdot[2];
|
||||
unsigned int f_state;
|
||||
};
|
||||
|
||||
static inline void set_ctx_actor(struct dir_context *ctx,
|
||||
@@ -144,7 +140,7 @@ struct ksmbd_file *ksmbd_lookup_fd_slow(struct ksmbd_work *work, u64 id,
|
||||
void ksmbd_fd_put(struct ksmbd_work *work, struct ksmbd_file *fp);
|
||||
struct ksmbd_file *ksmbd_lookup_durable_fd(unsigned long long id);
|
||||
struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid);
|
||||
struct ksmbd_file *ksmbd_lookup_fd_inode(struct inode *inode);
|
||||
struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry);
|
||||
unsigned int ksmbd_open_durable_fd(struct ksmbd_file *fp);
|
||||
struct ksmbd_file *ksmbd_open_fd(struct ksmbd_work *work, struct file *filp);
|
||||
void ksmbd_close_tree_conn_fds(struct ksmbd_work *work);
|
||||
@@ -153,6 +149,8 @@ int ksmbd_close_inode_fds(struct ksmbd_work *work, struct inode *inode);
|
||||
int ksmbd_init_global_file_table(void);
|
||||
void ksmbd_free_global_file_table(void);
|
||||
void ksmbd_set_fd_limit(unsigned long limit);
|
||||
void ksmbd_update_fstate(struct ksmbd_file_table *ft, struct ksmbd_file *fp,
|
||||
unsigned int state);
|
||||
|
||||
/*
|
||||
* INODE hash
|
||||
@@ -166,7 +164,7 @@ enum KSMBD_INODE_STATUS {
|
||||
KSMBD_INODE_STATUS_PENDING_DELETE,
|
||||
};
|
||||
|
||||
int ksmbd_query_inode_status(struct inode *inode);
|
||||
int ksmbd_query_inode_status(struct dentry *dentry);
|
||||
bool ksmbd_inode_pending_delete(struct ksmbd_file *fp);
|
||||
void ksmbd_set_inode_pending_delete(struct ksmbd_file *fp);
|
||||
void ksmbd_clear_inode_pending_delete(struct ksmbd_file *fp);
|
||||
|
||||
125
fs/namei.c
125
fs/namei.c
@@ -252,6 +252,7 @@ getname_kernel(const char * filename)
|
||||
|
||||
return result;
|
||||
}
|
||||
EXPORT_SYMBOL(getname_kernel);
|
||||
|
||||
void putname(struct filename *name)
|
||||
{
|
||||
@@ -269,6 +270,7 @@ void putname(struct filename *name)
|
||||
} else
|
||||
__putname(name);
|
||||
}
|
||||
EXPORT_SYMBOL(putname);
|
||||
|
||||
/**
|
||||
* check_acl - perform ACL permission checking
|
||||
@@ -1539,8 +1541,9 @@ static struct dentry *lookup_dcache(const struct qstr *name,
|
||||
* when directory is guaranteed to have no in-lookup children
|
||||
* at all.
|
||||
*/
|
||||
static struct dentry *__lookup_hash(const struct qstr *name,
|
||||
struct dentry *base, unsigned int flags)
|
||||
struct dentry *lookup_one_qstr_excl(const struct qstr *name,
|
||||
struct dentry *base,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct dentry *dentry = lookup_dcache(name, base, flags);
|
||||
struct dentry *old;
|
||||
@@ -1564,6 +1567,7 @@ static struct dentry *__lookup_hash(const struct qstr *name,
|
||||
}
|
||||
return dentry;
|
||||
}
|
||||
EXPORT_SYMBOL(lookup_one_qstr_excl);
|
||||
|
||||
static struct dentry *lookup_fast(struct nameidata *nd,
|
||||
struct inode **inode,
|
||||
@@ -2508,16 +2512,17 @@ static int path_parentat(struct nameidata *nd, unsigned flags,
|
||||
}
|
||||
|
||||
/* Note: this does not consume "name" */
|
||||
static int filename_parentat(int dfd, struct filename *name,
|
||||
unsigned int flags, struct path *parent,
|
||||
struct qstr *last, int *type)
|
||||
static int __filename_parentat(int dfd, struct filename *name,
|
||||
unsigned int flags, struct path *parent,
|
||||
struct qstr *last, int *type,
|
||||
const struct path *root)
|
||||
{
|
||||
int retval;
|
||||
struct nameidata nd;
|
||||
|
||||
if (IS_ERR(name))
|
||||
return PTR_ERR(name);
|
||||
set_nameidata(&nd, dfd, name, NULL);
|
||||
set_nameidata(&nd, dfd, name, root);
|
||||
retval = path_parentat(&nd, flags | LOOKUP_RCU, parent);
|
||||
if (unlikely(retval == -ECHILD))
|
||||
retval = path_parentat(&nd, flags, parent);
|
||||
@@ -2532,6 +2537,13 @@ static int filename_parentat(int dfd, struct filename *name,
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int filename_parentat(int dfd, struct filename *name,
|
||||
unsigned int flags, struct path *parent,
|
||||
struct qstr *last, int *type)
|
||||
{
|
||||
return __filename_parentat(dfd, name, flags, parent, last, type, NULL);
|
||||
}
|
||||
|
||||
/* does lookup, returns the object with parent locked */
|
||||
static struct dentry *__kern_path_locked(struct filename *name, struct path *path)
|
||||
{
|
||||
@@ -2547,7 +2559,7 @@ static struct dentry *__kern_path_locked(struct filename *name, struct path *pat
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
inode_lock_nested(path->dentry->d_inode, I_MUTEX_PARENT);
|
||||
d = __lookup_hash(&last, path->dentry, 0);
|
||||
d = lookup_one_qstr_excl(&last, path->dentry, 0);
|
||||
if (IS_ERR(d)) {
|
||||
inode_unlock(path->dentry->d_inode);
|
||||
path_put(path);
|
||||
@@ -2575,6 +2587,24 @@ int kern_path(const char *name, unsigned int flags, struct path *path)
|
||||
}
|
||||
EXPORT_SYMBOL_NS(kern_path, ANDROID_GKI_VFS_EXPORT_ONLY);
|
||||
|
||||
/**
|
||||
* vfs_path_parent_lookup - lookup a parent path relative to a dentry-vfsmount pair
|
||||
* @filename: filename structure
|
||||
* @flags: lookup flags
|
||||
* @parent: pointer to struct path to fill
|
||||
* @last: last component
|
||||
* @type: type of the last component
|
||||
* @root: pointer to struct path of the base directory
|
||||
*/
|
||||
int vfs_path_parent_lookup(struct filename *filename, unsigned int flags,
|
||||
struct path *parent, struct qstr *last, int *type,
|
||||
const struct path *root)
|
||||
{
|
||||
return __filename_parentat(AT_FDCWD, filename, flags, parent, last,
|
||||
type, root);
|
||||
}
|
||||
EXPORT_SYMBOL(vfs_path_parent_lookup);
|
||||
|
||||
/**
|
||||
* vfs_path_lookup - lookup a file path relative to a dentry-vfsmount pair
|
||||
* @dentry: pointer to dentry of the base directory
|
||||
@@ -2956,20 +2986,10 @@ static inline int may_create(struct user_namespace *mnt_userns,
|
||||
return inode_permission(mnt_userns, dir, MAY_WRITE | MAY_EXEC);
|
||||
}
|
||||
|
||||
/*
|
||||
* p1 and p2 should be directories on the same fs.
|
||||
*/
|
||||
struct dentry *lock_rename(struct dentry *p1, struct dentry *p2)
|
||||
static struct dentry *lock_two_directories(struct dentry *p1, struct dentry *p2)
|
||||
{
|
||||
struct dentry *p;
|
||||
|
||||
if (p1 == p2) {
|
||||
inode_lock_nested(p1->d_inode, I_MUTEX_PARENT);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mutex_lock(&p1->d_sb->s_vfs_rename_mutex);
|
||||
|
||||
p = d_ancestor(p2, p1);
|
||||
if (p) {
|
||||
inode_lock_nested(p2->d_inode, I_MUTEX_PARENT);
|
||||
@@ -2988,8 +3008,64 @@ struct dentry *lock_rename(struct dentry *p1, struct dentry *p2)
|
||||
I_MUTEX_PARENT, I_MUTEX_PARENT2);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* p1 and p2 should be directories on the same fs.
|
||||
*/
|
||||
struct dentry *lock_rename(struct dentry *p1, struct dentry *p2)
|
||||
{
|
||||
if (p1 == p2) {
|
||||
inode_lock_nested(p1->d_inode, I_MUTEX_PARENT);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mutex_lock(&p1->d_sb->s_vfs_rename_mutex);
|
||||
return lock_two_directories(p1, p2);
|
||||
}
|
||||
EXPORT_SYMBOL(lock_rename);
|
||||
|
||||
/*
|
||||
* c1 and p2 should be on the same fs.
|
||||
*/
|
||||
struct dentry *lock_rename_child(struct dentry *c1, struct dentry *p2)
|
||||
{
|
||||
if (READ_ONCE(c1->d_parent) == p2) {
|
||||
/*
|
||||
* hopefully won't need to touch ->s_vfs_rename_mutex at all.
|
||||
*/
|
||||
inode_lock_nested(p2->d_inode, I_MUTEX_PARENT);
|
||||
/*
|
||||
* now that p2 is locked, nobody can move in or out of it,
|
||||
* so the test below is safe.
|
||||
*/
|
||||
if (likely(c1->d_parent == p2))
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* c1 got moved out of p2 while we'd been taking locks;
|
||||
* unlock and fall back to slow case.
|
||||
*/
|
||||
inode_unlock(p2->d_inode);
|
||||
}
|
||||
|
||||
mutex_lock(&c1->d_sb->s_vfs_rename_mutex);
|
||||
/*
|
||||
* nobody can move out of any directories on this fs.
|
||||
*/
|
||||
if (likely(c1->d_parent != p2))
|
||||
return lock_two_directories(c1->d_parent, p2);
|
||||
|
||||
/*
|
||||
* c1 got moved into p2 while we were taking locks;
|
||||
* we need p2 locked and ->s_vfs_rename_mutex unlocked,
|
||||
* for consistency with lock_rename().
|
||||
*/
|
||||
inode_lock_nested(p2->d_inode, I_MUTEX_PARENT);
|
||||
mutex_unlock(&c1->d_sb->s_vfs_rename_mutex);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(lock_rename_child);
|
||||
|
||||
void unlock_rename(struct dentry *p1, struct dentry *p2)
|
||||
{
|
||||
inode_unlock(p1->d_inode);
|
||||
@@ -3763,7 +3839,8 @@ static struct dentry *filename_create(int dfd, struct filename *name,
|
||||
if (last.name[last.len] && !want_dir)
|
||||
create_flags = 0;
|
||||
inode_lock_nested(path->dentry->d_inode, I_MUTEX_PARENT);
|
||||
dentry = __lookup_hash(&last, path->dentry, reval_flag | create_flags);
|
||||
dentry = lookup_one_qstr_excl(&last, path->dentry,
|
||||
reval_flag | create_flags);
|
||||
if (IS_ERR(dentry))
|
||||
goto unlock;
|
||||
|
||||
@@ -4124,7 +4201,7 @@ retry:
|
||||
goto exit2;
|
||||
|
||||
inode_lock_nested(path.dentry->d_inode, I_MUTEX_PARENT);
|
||||
dentry = __lookup_hash(&last, path.dentry, lookup_flags);
|
||||
dentry = lookup_one_qstr_excl(&last, path.dentry, lookup_flags);
|
||||
error = PTR_ERR(dentry);
|
||||
if (IS_ERR(dentry))
|
||||
goto exit3;
|
||||
@@ -4258,7 +4335,7 @@ retry:
|
||||
goto exit2;
|
||||
retry_deleg:
|
||||
inode_lock_nested(path.dentry->d_inode, I_MUTEX_PARENT);
|
||||
dentry = __lookup_hash(&last, path.dentry, lookup_flags);
|
||||
dentry = lookup_one_qstr_excl(&last, path.dentry, lookup_flags);
|
||||
error = PTR_ERR(dentry);
|
||||
if (!IS_ERR(dentry)) {
|
||||
struct user_namespace *mnt_userns;
|
||||
@@ -4832,7 +4909,8 @@ retry:
|
||||
retry_deleg:
|
||||
trap = lock_rename(new_path.dentry, old_path.dentry);
|
||||
|
||||
old_dentry = __lookup_hash(&old_last, old_path.dentry, lookup_flags);
|
||||
old_dentry = lookup_one_qstr_excl(&old_last, old_path.dentry,
|
||||
lookup_flags);
|
||||
error = PTR_ERR(old_dentry);
|
||||
if (IS_ERR(old_dentry))
|
||||
goto exit3;
|
||||
@@ -4840,7 +4918,8 @@ retry_deleg:
|
||||
error = -ENOENT;
|
||||
if (d_is_negative(old_dentry))
|
||||
goto exit4;
|
||||
new_dentry = __lookup_hash(&new_last, new_path.dentry, lookup_flags | target_flags);
|
||||
new_dentry = lookup_one_qstr_excl(&new_last, new_path.dentry,
|
||||
lookup_flags | target_flags);
|
||||
error = PTR_ERR(new_dentry);
|
||||
if (IS_ERR(new_dentry))
|
||||
goto exit4;
|
||||
|
||||
@@ -468,10 +468,10 @@ static inline void kasan_free_module_shadow(const struct vm_struct *vm) {}
|
||||
|
||||
#endif /* (CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS) && !CONFIG_KASAN_VMALLOC */
|
||||
|
||||
#ifdef CONFIG_KASAN
|
||||
#if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
|
||||
void kasan_non_canonical_hook(unsigned long addr);
|
||||
#else /* CONFIG_KASAN */
|
||||
#else /* CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS */
|
||||
static inline void kasan_non_canonical_hook(unsigned long addr) { }
|
||||
#endif /* CONFIG_KASAN */
|
||||
#endif /* CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS */
|
||||
|
||||
#endif /* LINUX_KASAN_H */
|
||||
|
||||
@@ -57,12 +57,18 @@ static inline int user_path_at(int dfd, const char __user *name, unsigned flags,
|
||||
return user_path_at_empty(dfd, name, flags, path, NULL);
|
||||
}
|
||||
|
||||
struct dentry *lookup_one_qstr_excl(const struct qstr *name,
|
||||
struct dentry *base,
|
||||
unsigned int flags);
|
||||
extern int kern_path(const char *, unsigned, struct path *);
|
||||
|
||||
extern struct dentry *kern_path_create(int, const char *, struct path *, unsigned int);
|
||||
extern struct dentry *user_path_create(int, const char __user *, struct path *, unsigned int);
|
||||
extern void done_path_create(struct path *, struct dentry *);
|
||||
extern struct dentry *kern_path_locked(const char *, struct path *);
|
||||
int vfs_path_parent_lookup(struct filename *filename, unsigned int flags,
|
||||
struct path *parent, struct qstr *last, int *type,
|
||||
const struct path *root);
|
||||
int vfs_path_lookup(struct dentry *, struct vfsmount *, const char *,
|
||||
unsigned int, struct path *);
|
||||
|
||||
@@ -83,6 +89,7 @@ extern int follow_down(struct path *);
|
||||
extern int follow_up(struct path *);
|
||||
|
||||
extern struct dentry *lock_rename(struct dentry *, struct dentry *);
|
||||
extern struct dentry *lock_rename_child(struct dentry *, struct dentry *);
|
||||
extern void unlock_rename(struct dentry *, struct dentry *);
|
||||
|
||||
extern int __must_check nd_jump_link(struct path *path);
|
||||
|
||||
@@ -708,6 +708,36 @@ static struct notifier_block trace_kprobe_module_nb = {
|
||||
.priority = 1 /* Invoked after kprobe module callback */
|
||||
};
|
||||
|
||||
struct count_symbols_struct {
|
||||
const char *func_name;
|
||||
unsigned int count;
|
||||
};
|
||||
|
||||
static int count_symbols(void *data, const char *name, struct module *unused0,
|
||||
unsigned long unused1)
|
||||
{
|
||||
struct count_symbols_struct *args = data;
|
||||
|
||||
if (strcmp(args->func_name, name))
|
||||
return 0;
|
||||
|
||||
args->count++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int number_of_same_symbols(char *func_name)
|
||||
{
|
||||
struct count_symbols_struct args = {
|
||||
.func_name = func_name,
|
||||
.count = 0,
|
||||
};
|
||||
|
||||
kallsyms_on_each_symbol(count_symbols, &args);
|
||||
|
||||
return args.count;
|
||||
}
|
||||
|
||||
static int __trace_kprobe_create(int argc, const char *argv[])
|
||||
{
|
||||
/*
|
||||
@@ -836,6 +866,31 @@ static int __trace_kprobe_create(int argc, const char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if (symbol && !strchr(symbol, ':')) {
|
||||
unsigned int count;
|
||||
|
||||
count = number_of_same_symbols(symbol);
|
||||
if (count > 1) {
|
||||
/*
|
||||
* Users should use ADDR to remove the ambiguity of
|
||||
* using KSYM only.
|
||||
*/
|
||||
trace_probe_log_err(0, NON_UNIQ_SYMBOL);
|
||||
ret = -EADDRNOTAVAIL;
|
||||
|
||||
goto error;
|
||||
} else if (count == 0) {
|
||||
/*
|
||||
* We can return ENOENT earlier than when register the
|
||||
* kprobe.
|
||||
*/
|
||||
trace_probe_log_err(0, BAD_PROBE_ADDR);
|
||||
ret = -ENOENT;
|
||||
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
trace_probe_log_set_index(0);
|
||||
if (event) {
|
||||
ret = traceprobe_parse_event_name(&event, &group, buf,
|
||||
@@ -1755,6 +1810,7 @@ static int unregister_kprobe_event(struct trace_kprobe *tk)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PERF_EVENTS
|
||||
|
||||
/* create a trace_kprobe, but don't add it to global lists */
|
||||
struct trace_event_call *
|
||||
create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
|
||||
@@ -1765,6 +1821,24 @@ create_local_trace_kprobe(char *func, void *addr, unsigned long offs,
|
||||
int ret;
|
||||
char *event;
|
||||
|
||||
if (func) {
|
||||
unsigned int count;
|
||||
|
||||
count = number_of_same_symbols(func);
|
||||
if (count > 1)
|
||||
/*
|
||||
* Users should use addr to remove the ambiguity of
|
||||
* using func only.
|
||||
*/
|
||||
return ERR_PTR(-EADDRNOTAVAIL);
|
||||
else if (count == 0)
|
||||
/*
|
||||
* We can return ENOENT earlier than when register the
|
||||
* kprobe.
|
||||
*/
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
/*
|
||||
* local trace_kprobes are not added to dyn_event, so they are never
|
||||
* searched in find_trace_kprobe(). Therefore, there is no concern of
|
||||
|
||||
@@ -405,6 +405,7 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,
|
||||
C(BAD_MAXACT, "Invalid maxactive number"), \
|
||||
C(MAXACT_TOO_BIG, "Maxactive is too big"), \
|
||||
C(BAD_PROBE_ADDR, "Invalid probed address or symbol"), \
|
||||
C(NON_UNIQ_SYMBOL, "The symbol is not unique"), \
|
||||
C(BAD_RETPROBE, "Retprobe address must be an function entry"), \
|
||||
C(BAD_ADDR_SUFFIX, "Invalid probed address suffix"), \
|
||||
C(NO_GROUP_NAME, "Group name is not specified"), \
|
||||
|
||||
@@ -556,7 +556,7 @@ void kasan_report_async(void)
|
||||
}
|
||||
#endif /* CONFIG_KASAN_HW_TAGS */
|
||||
|
||||
#ifdef CONFIG_KASAN_INLINE
|
||||
#if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
|
||||
/*
|
||||
* With CONFIG_KASAN_INLINE, accesses to bogus pointers (outside the high
|
||||
* canonical half of the address space) cause out-of-bounds shadow memory reads
|
||||
|
||||
Reference in New Issue
Block a user