12 server fixes, including for oopses, memory leaks and adding a channel lock
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmLwixsACgkQiiy9cAdy T1FT6Av+NY7R2f7/vDRzX/8u1fFXmyQDU2/dl3S0ysqqFEYE5hnHgbFtVP1IYwId /IAV8R6E/YMm8Nkbkf173EqHI8E9QNUSngTCk1bcvsiNSW4z3QOsujs9B6oTUeXM ARthU4eFJQW0wcTyjElVcm59I/jdtpQKaoVDQ/uXlCjPMT+0BUHS4mFRJkAx6DrX 7wOO0vJ/WCqO2u0rSvK4unOZsvhrKHibtPMvQSiV6k3a+LVCJ5/5lwBpENKK4Mdw n4LeNhSDtm6HE6WDFIxSj008WPX7CF3JvX+zvZJEsB7uFNry/GVkWySPLqVYUmtp aSftdnWnw0Mv9AG3L4OMzyCQQP89ccoV81d6lyyJEBaGiOFhH8L1v6b7qAStCZue zyyFWIVUXnstQKwDY8QWLKjmi7H+I1drFExxn0vABInPcaijQE8Mct0fSt015Tc1 EuCsO1JRyo+zn0mx7a1L80kHUH+yvHjKkfbINvPSa+qTFy21bgQZcG5CWSPpjadr 4zibpKko =cDaA -----END PGP SIGNATURE----- Merge tag '5.20-rc-ksmbd-server-fixes' of git://git.samba.org/ksmbd Pull ksmbd updates from Steve French: - fixes for memory access bugs (out of bounds access, oops, leak) - multichannel fixes - session disconnect performance improvement, and session register improvement - cleanup * tag '5.20-rc-ksmbd-server-fixes' of git://git.samba.org/ksmbd: ksmbd: fix heap-based overflow in set_ntacl_dacl() ksmbd: prevent out of bound read for SMB2_TREE_CONNNECT ksmbd: prevent out of bound read for SMB2_WRITE ksmbd: fix use-after-free bug in smb2_tree_disconect ksmbd: fix memory leak in smb2_handle_negotiate ksmbd: fix racy issue while destroying session on multichannel ksmbd: use wait_event instead of schedule_timeout() ksmbd: fix kernel oops from idr_remove() ksmbd: add channel rwlock ksmbd: replace sessions list in connection with xarray MAINTAINERS: ksmbd: add entry for documentation ksmbd: remove unused ksmbd_share_configs_cleanup function
This commit is contained in:
commit
eb555cb5b7
@ -11063,6 +11063,7 @@ R: Sergey Senozhatsky <senozhatsky@chromium.org>
|
||||
L: linux-cifs@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://git.samba.org/ksmbd.git
|
||||
F: Documentation/filesystems/cifs/ksmbd.rst
|
||||
F: fs/ksmbd/
|
||||
F: fs/smbfs_common/
|
||||
|
||||
|
@ -121,8 +121,8 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int calc_ntlmv2_hash(struct ksmbd_session *sess, char *ntlmv2_hash,
|
||||
char *dname)
|
||||
static int calc_ntlmv2_hash(struct ksmbd_conn *conn, struct ksmbd_session *sess,
|
||||
char *ntlmv2_hash, char *dname)
|
||||
{
|
||||
int ret, len, conv_len;
|
||||
wchar_t *domain = NULL;
|
||||
@ -158,7 +158,7 @@ static int calc_ntlmv2_hash(struct ksmbd_session *sess, char *ntlmv2_hash,
|
||||
}
|
||||
|
||||
conv_len = smb_strtoUTF16(uniname, user_name(sess->user), len,
|
||||
sess->conn->local_nls);
|
||||
conn->local_nls);
|
||||
if (conv_len < 0 || conv_len > len) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
@ -182,7 +182,7 @@ static int calc_ntlmv2_hash(struct ksmbd_session *sess, char *ntlmv2_hash,
|
||||
}
|
||||
|
||||
conv_len = smb_strtoUTF16((__le16 *)domain, dname, len,
|
||||
sess->conn->local_nls);
|
||||
conn->local_nls);
|
||||
if (conv_len < 0 || conv_len > len) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
@ -215,8 +215,9 @@ out:
|
||||
*
|
||||
* Return: 0 on success, error number on error
|
||||
*/
|
||||
int ksmbd_auth_ntlmv2(struct ksmbd_session *sess, struct ntlmv2_resp *ntlmv2,
|
||||
int blen, char *domain_name, char *cryptkey)
|
||||
int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
|
||||
struct ntlmv2_resp *ntlmv2, int blen, char *domain_name,
|
||||
char *cryptkey)
|
||||
{
|
||||
char ntlmv2_hash[CIFS_ENCPWD_SIZE];
|
||||
char ntlmv2_rsp[CIFS_HMAC_MD5_HASH_SIZE];
|
||||
@ -230,7 +231,7 @@ int ksmbd_auth_ntlmv2(struct ksmbd_session *sess, struct ntlmv2_resp *ntlmv2,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rc = calc_ntlmv2_hash(sess, ntlmv2_hash, domain_name);
|
||||
rc = calc_ntlmv2_hash(conn, sess, ntlmv2_hash, domain_name);
|
||||
if (rc) {
|
||||
ksmbd_debug(AUTH, "could not get v2 hash rc %d\n", rc);
|
||||
goto out;
|
||||
@ -333,7 +334,8 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
|
||||
/* process NTLMv2 authentication */
|
||||
ksmbd_debug(AUTH, "decode_ntlmssp_authenticate_blob dname%s\n",
|
||||
domain_name);
|
||||
ret = ksmbd_auth_ntlmv2(sess, (struct ntlmv2_resp *)((char *)authblob + nt_off),
|
||||
ret = ksmbd_auth_ntlmv2(conn, sess,
|
||||
(struct ntlmv2_resp *)((char *)authblob + nt_off),
|
||||
nt_len - CIFS_ENCPWD_SIZE,
|
||||
domain_name, conn->ntlmssp.cryptkey);
|
||||
kfree(domain_name);
|
||||
@ -659,8 +661,9 @@ struct derivation {
|
||||
bool binding;
|
||||
};
|
||||
|
||||
static int generate_key(struct ksmbd_session *sess, struct kvec label,
|
||||
struct kvec context, __u8 *key, unsigned int key_size)
|
||||
static int generate_key(struct ksmbd_conn *conn, struct ksmbd_session *sess,
|
||||
struct kvec label, struct kvec context, __u8 *key,
|
||||
unsigned int key_size)
|
||||
{
|
||||
unsigned char zero = 0x0;
|
||||
__u8 i[4] = {0, 0, 0, 1};
|
||||
@ -720,8 +723,8 @@ static int generate_key(struct ksmbd_session *sess, struct kvec label,
|
||||
goto smb3signkey_ret;
|
||||
}
|
||||
|
||||
if (sess->conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM ||
|
||||
sess->conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM)
|
||||
if (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);
|
||||
@ -756,17 +759,17 @@ static int generate_smb3signingkey(struct ksmbd_session *sess,
|
||||
if (!chann)
|
||||
return 0;
|
||||
|
||||
if (sess->conn->dialect >= SMB30_PROT_ID && signing->binding)
|
||||
if (conn->dialect >= SMB30_PROT_ID && signing->binding)
|
||||
key = chann->smb3signingkey;
|
||||
else
|
||||
key = sess->smb3signingkey;
|
||||
|
||||
rc = generate_key(sess, signing->label, signing->context, key,
|
||||
rc = generate_key(conn, sess, signing->label, signing->context, key,
|
||||
SMB3_SIGN_KEY_SIZE);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (!(sess->conn->dialect >= SMB30_PROT_ID && signing->binding))
|
||||
if (!(conn->dialect >= SMB30_PROT_ID && signing->binding))
|
||||
memcpy(chann->smb3signingkey, key, SMB3_SIGN_KEY_SIZE);
|
||||
|
||||
ksmbd_debug(AUTH, "dumping generated AES signing keys\n");
|
||||
@ -820,30 +823,31 @@ struct derivation_twin {
|
||||
struct derivation decryption;
|
||||
};
|
||||
|
||||
static int generate_smb3encryptionkey(struct ksmbd_session *sess,
|
||||
static int generate_smb3encryptionkey(struct ksmbd_conn *conn,
|
||||
struct ksmbd_session *sess,
|
||||
const struct derivation_twin *ptwin)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = generate_key(sess, ptwin->encryption.label,
|
||||
rc = generate_key(conn, sess, ptwin->encryption.label,
|
||||
ptwin->encryption.context, sess->smb3encryptionkey,
|
||||
SMB3_ENC_DEC_KEY_SIZE);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = generate_key(sess, ptwin->decryption.label,
|
||||
rc = generate_key(conn, sess, ptwin->decryption.label,
|
||||
ptwin->decryption.context,
|
||||
sess->smb3decryptionkey, SMB3_ENC_DEC_KEY_SIZE);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
ksmbd_debug(AUTH, "dumping generated AES encryption keys\n");
|
||||
ksmbd_debug(AUTH, "Cipher type %d\n", sess->conn->cipher_type);
|
||||
ksmbd_debug(AUTH, "Cipher type %d\n", conn->cipher_type);
|
||||
ksmbd_debug(AUTH, "Session Id %llu\n", sess->id);
|
||||
ksmbd_debug(AUTH, "Session Key %*ph\n",
|
||||
SMB2_NTLMV2_SESSKEY_SIZE, sess->sess_key);
|
||||
if (sess->conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM ||
|
||||
sess->conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM) {
|
||||
if (conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM ||
|
||||
conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM) {
|
||||
ksmbd_debug(AUTH, "ServerIn Key %*ph\n",
|
||||
SMB3_GCM256_CRYPTKEY_SIZE, sess->smb3encryptionkey);
|
||||
ksmbd_debug(AUTH, "ServerOut Key %*ph\n",
|
||||
@ -857,7 +861,8 @@ static int generate_smb3encryptionkey(struct ksmbd_session *sess,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ksmbd_gen_smb30_encryptionkey(struct ksmbd_session *sess)
|
||||
int ksmbd_gen_smb30_encryptionkey(struct ksmbd_conn *conn,
|
||||
struct ksmbd_session *sess)
|
||||
{
|
||||
struct derivation_twin twin;
|
||||
struct derivation *d;
|
||||
@ -874,10 +879,11 @@ int ksmbd_gen_smb30_encryptionkey(struct ksmbd_session *sess)
|
||||
d->context.iov_base = "ServerIn ";
|
||||
d->context.iov_len = 10;
|
||||
|
||||
return generate_smb3encryptionkey(sess, &twin);
|
||||
return generate_smb3encryptionkey(conn, sess, &twin);
|
||||
}
|
||||
|
||||
int ksmbd_gen_smb311_encryptionkey(struct ksmbd_session *sess)
|
||||
int ksmbd_gen_smb311_encryptionkey(struct ksmbd_conn *conn,
|
||||
struct ksmbd_session *sess)
|
||||
{
|
||||
struct derivation_twin twin;
|
||||
struct derivation *d;
|
||||
@ -894,7 +900,7 @@ int ksmbd_gen_smb311_encryptionkey(struct ksmbd_session *sess)
|
||||
d->context.iov_base = sess->Preauth_HashValue;
|
||||
d->context.iov_len = 64;
|
||||
|
||||
return generate_smb3encryptionkey(sess, &twin);
|
||||
return generate_smb3encryptionkey(conn, sess, &twin);
|
||||
}
|
||||
|
||||
int ksmbd_gen_preauth_integrity_hash(struct ksmbd_conn *conn, char *buf,
|
||||
|
@ -38,8 +38,9 @@ struct kvec;
|
||||
int ksmbd_crypt_message(struct ksmbd_conn *conn, struct kvec *iov,
|
||||
unsigned int nvec, int enc);
|
||||
void ksmbd_copy_gss_neg_header(void *buf);
|
||||
int ksmbd_auth_ntlmv2(struct ksmbd_session *sess, struct ntlmv2_resp *ntlmv2,
|
||||
int blen, char *domain_name, char *cryptkey);
|
||||
int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
|
||||
struct ntlmv2_resp *ntlmv2, int blen, char *domain_name,
|
||||
char *cryptkey);
|
||||
int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
|
||||
int blob_len, struct ksmbd_conn *conn,
|
||||
struct ksmbd_session *sess);
|
||||
@ -58,8 +59,10 @@ int ksmbd_gen_smb30_signingkey(struct ksmbd_session *sess,
|
||||
struct ksmbd_conn *conn);
|
||||
int ksmbd_gen_smb311_signingkey(struct ksmbd_session *sess,
|
||||
struct ksmbd_conn *conn);
|
||||
int ksmbd_gen_smb30_encryptionkey(struct ksmbd_session *sess);
|
||||
int ksmbd_gen_smb311_encryptionkey(struct ksmbd_session *sess);
|
||||
int ksmbd_gen_smb30_encryptionkey(struct ksmbd_conn *conn,
|
||||
struct ksmbd_session *sess);
|
||||
int ksmbd_gen_smb311_encryptionkey(struct ksmbd_conn *conn,
|
||||
struct ksmbd_session *sess);
|
||||
int ksmbd_gen_preauth_integrity_hash(struct ksmbd_conn *conn, char *buf,
|
||||
__u8 *pi_hash);
|
||||
int ksmbd_gen_sd_hash(struct ksmbd_conn *conn, char *sd_buf, int len,
|
||||
|
@ -36,6 +36,7 @@ void ksmbd_conn_free(struct ksmbd_conn *conn)
|
||||
list_del(&conn->conns_list);
|
||||
write_unlock(&conn_list_lock);
|
||||
|
||||
xa_destroy(&conn->sessions);
|
||||
kvfree(conn->request_buf);
|
||||
kfree(conn->preauth_info);
|
||||
kfree(conn);
|
||||
@ -65,13 +66,14 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
|
||||
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->sessions);
|
||||
INIT_LIST_HEAD(&conn->requests);
|
||||
INIT_LIST_HEAD(&conn->async_requests);
|
||||
spin_lock_init(&conn->request_lock);
|
||||
spin_lock_init(&conn->credits_lock);
|
||||
ida_init(&conn->async_ida);
|
||||
xa_init(&conn->sessions);
|
||||
|
||||
spin_lock_init(&conn->llist_lock);
|
||||
INIT_LIST_HEAD(&conn->lock_list);
|
||||
@ -164,7 +166,6 @@ int ksmbd_conn_write(struct ksmbd_work *work)
|
||||
struct kvec iov[3];
|
||||
int iov_idx = 0;
|
||||
|
||||
ksmbd_conn_try_dequeue_request(work);
|
||||
if (!work->response_buf) {
|
||||
pr_err("NULL response header\n");
|
||||
return -EINVAL;
|
||||
@ -346,8 +347,8 @@ int ksmbd_conn_handler_loop(void *p)
|
||||
|
||||
out:
|
||||
/* 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);
|
||||
|
||||
|
||||
unload_nls(conn->local_nls);
|
||||
if (default_conn_ops.terminate_fn)
|
||||
|
@ -20,13 +20,6 @@
|
||||
|
||||
#define KSMBD_SOCKET_BACKLOG 16
|
||||
|
||||
/*
|
||||
* WARNING
|
||||
*
|
||||
* This is nothing but a HACK. Session status should move to channel
|
||||
* or to session. As of now we have 1 tcp_conn : 1 ksmbd_session, but
|
||||
* we need to change it to 1 tcp_conn : N ksmbd_sessions.
|
||||
*/
|
||||
enum {
|
||||
KSMBD_SESS_NEW = 0,
|
||||
KSMBD_SESS_GOOD,
|
||||
@ -55,7 +48,7 @@ struct ksmbd_conn {
|
||||
struct nls_table *local_nls;
|
||||
struct list_head conns_list;
|
||||
/* smb session 1 per user */
|
||||
struct list_head sessions;
|
||||
struct xarray sessions;
|
||||
unsigned long last_active;
|
||||
/* How many request are running currently */
|
||||
atomic_t req_running;
|
||||
@ -65,6 +58,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;
|
||||
|
@ -222,17 +222,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);
|
||||
}
|
||||
|
@ -76,6 +76,4 @@ static inline void ksmbd_share_config_put(struct ksmbd_share_config *share)
|
||||
struct ksmbd_share_config *ksmbd_share_config_get(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__ */
|
||||
|
@ -16,7 +16,8 @@
|
||||
#include "user_session.h"
|
||||
|
||||
struct ksmbd_tree_conn_status
|
||||
ksmbd_tree_conn_connect(struct ksmbd_session *sess, char *share_name)
|
||||
ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess,
|
||||
char *share_name)
|
||||
{
|
||||
struct ksmbd_tree_conn_status status = {-EINVAL, NULL};
|
||||
struct ksmbd_tree_connect_response *resp = NULL;
|
||||
@ -41,7 +42,7 @@ ksmbd_tree_conn_connect(struct ksmbd_session *sess, char *share_name)
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
peer_addr = KSMBD_TCP_PEER_SOCKADDR(sess->conn);
|
||||
peer_addr = KSMBD_TCP_PEER_SOCKADDR(conn);
|
||||
resp = ksmbd_ipc_tree_connect_request(sess,
|
||||
sc,
|
||||
tree_conn,
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
struct ksmbd_share_config;
|
||||
struct ksmbd_user;
|
||||
struct ksmbd_conn;
|
||||
|
||||
struct ksmbd_tree_connect {
|
||||
int id;
|
||||
@ -40,7 +41,8 @@ static inline int test_tree_conn_flag(struct ksmbd_tree_connect *tree_conn,
|
||||
struct ksmbd_session;
|
||||
|
||||
struct ksmbd_tree_conn_status
|
||||
ksmbd_tree_conn_connect(struct ksmbd_session *sess, char *share_name);
|
||||
ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess,
|
||||
char *share_name);
|
||||
|
||||
int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess,
|
||||
struct ksmbd_tree_connect *tree_conn);
|
||||
|
@ -32,11 +32,13 @@ static void free_channel_list(struct ksmbd_session *sess)
|
||||
{
|
||||
struct channel *chann, *tmp;
|
||||
|
||||
write_lock(&sess->chann_lock);
|
||||
list_for_each_entry_safe(chann, tmp, &sess->ksmbd_chann_list,
|
||||
chann_list) {
|
||||
list_del(&chann->chann_list);
|
||||
kfree(chann);
|
||||
}
|
||||
write_unlock(&sess->chann_lock);
|
||||
}
|
||||
|
||||
static void __session_rpc_close(struct ksmbd_session *sess,
|
||||
@ -149,11 +151,6 @@ void ksmbd_session_destroy(struct ksmbd_session *sess)
|
||||
if (!sess)
|
||||
return;
|
||||
|
||||
if (!atomic_dec_and_test(&sess->refcnt))
|
||||
return;
|
||||
|
||||
list_del(&sess->sessions_entry);
|
||||
|
||||
down_write(&sessions_table_lock);
|
||||
hash_del(&sess->hlist);
|
||||
up_write(&sessions_table_lock);
|
||||
@ -181,53 +178,70 @@ static struct ksmbd_session *__session_lookup(unsigned long long id)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ksmbd_session_register(struct ksmbd_conn *conn,
|
||||
struct ksmbd_session *sess)
|
||||
int ksmbd_session_register(struct ksmbd_conn *conn,
|
||||
struct ksmbd_session *sess)
|
||||
{
|
||||
sess->conn = conn;
|
||||
list_add(&sess->sessions_entry, &conn->sessions);
|
||||
sess->dialect = conn->dialect;
|
||||
memcpy(sess->ClientGUID, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE);
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
|
||||
{
|
||||
struct ksmbd_session *sess;
|
||||
|
||||
while (!list_empty(&conn->sessions)) {
|
||||
sess = list_entry(conn->sessions.next,
|
||||
struct ksmbd_session,
|
||||
sessions_entry);
|
||||
if (conn->binding) {
|
||||
int bkt;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
up_write(&sessions_table_lock);
|
||||
} else {
|
||||
unsigned long id;
|
||||
|
||||
xa_for_each(&conn->sessions, id, sess) {
|
||||
if (!ksmbd_chann_del(conn, sess))
|
||||
goto sess_destroy;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
sess_destroy:
|
||||
if (list_empty(&sess->ksmbd_chann_list)) {
|
||||
xa_erase(&conn->sessions, sess->id);
|
||||
ksmbd_session_destroy(sess);
|
||||
}
|
||||
}
|
||||
|
||||
static bool ksmbd_session_id_match(struct ksmbd_session *sess,
|
||||
unsigned long long id)
|
||||
{
|
||||
return sess->id == id;
|
||||
}
|
||||
|
||||
struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
|
||||
unsigned long long id)
|
||||
{
|
||||
struct ksmbd_session *sess = NULL;
|
||||
|
||||
list_for_each_entry(sess, &conn->sessions, sessions_entry) {
|
||||
if (ksmbd_session_id_match(sess, id))
|
||||
return sess;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int get_session(struct ksmbd_session *sess)
|
||||
{
|
||||
return atomic_inc_not_zero(&sess->refcnt);
|
||||
}
|
||||
|
||||
void put_session(struct ksmbd_session *sess)
|
||||
{
|
||||
if (atomic_dec_and_test(&sess->refcnt))
|
||||
pr_err("get/%s seems to be mismatched.", __func__);
|
||||
return xa_load(&conn->sessions, id);
|
||||
}
|
||||
|
||||
struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id)
|
||||
@ -236,10 +250,6 @@ struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id)
|
||||
|
||||
down_read(&sessions_table_lock);
|
||||
sess = __session_lookup(id);
|
||||
if (sess) {
|
||||
if (!get_session(sess))
|
||||
sess = NULL;
|
||||
}
|
||||
up_read(&sessions_table_lock);
|
||||
|
||||
return sess;
|
||||
@ -253,6 +263,8 @@ struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,
|
||||
sess = ksmbd_session_lookup(conn, id);
|
||||
if (!sess && conn->binding)
|
||||
sess = ksmbd_session_lookup_slowpath(id);
|
||||
if (sess && sess->state != SMB2_SESSION_VALID)
|
||||
sess = NULL;
|
||||
return sess;
|
||||
}
|
||||
|
||||
@ -314,12 +326,11 @@ static struct ksmbd_session *__session_create(int protocol)
|
||||
goto error;
|
||||
|
||||
set_session_flag(sess, protocol);
|
||||
INIT_LIST_HEAD(&sess->sessions_entry);
|
||||
xa_init(&sess->tree_conns);
|
||||
INIT_LIST_HEAD(&sess->ksmbd_chann_list);
|
||||
INIT_LIST_HEAD(&sess->rpc_handle_list);
|
||||
sess->sequence_number = 1;
|
||||
atomic_set(&sess->refcnt, 1);
|
||||
rwlock_init(&sess->chann_lock);
|
||||
|
||||
switch (protocol) {
|
||||
case CIFDS_SESSION_FLAG_SMB2:
|
||||
|
@ -33,8 +33,10 @@ struct preauth_session {
|
||||
struct ksmbd_session {
|
||||
u64 id;
|
||||
|
||||
__u16 dialect;
|
||||
char ClientGUID[SMB2_CLIENT_GUID_SIZE];
|
||||
|
||||
struct ksmbd_user *user;
|
||||
struct ksmbd_conn *conn;
|
||||
unsigned int sequence_number;
|
||||
unsigned int flags;
|
||||
|
||||
@ -48,6 +50,7 @@ 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 tree_conns;
|
||||
struct ida tree_conn_ida;
|
||||
@ -57,9 +60,7 @@ struct ksmbd_session {
|
||||
__u8 smb3decryptionkey[SMB3_ENC_DEC_KEY_SIZE];
|
||||
__u8 smb3signingkey[SMB3_SIGN_KEY_SIZE];
|
||||
|
||||
struct list_head sessions_entry;
|
||||
struct ksmbd_file_table file_table;
|
||||
atomic_t refcnt;
|
||||
};
|
||||
|
||||
static inline int test_session_flag(struct ksmbd_session *sess, int bit)
|
||||
@ -84,8 +85,8 @@ void ksmbd_session_destroy(struct ksmbd_session *sess);
|
||||
struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id);
|
||||
struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
|
||||
unsigned long long id);
|
||||
void ksmbd_session_register(struct ksmbd_conn *conn,
|
||||
struct ksmbd_session *sess);
|
||||
int ksmbd_session_register(struct ksmbd_conn *conn,
|
||||
struct ksmbd_session *sess);
|
||||
void ksmbd_sessions_deregister(struct ksmbd_conn *conn);
|
||||
struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,
|
||||
unsigned long long id);
|
||||
@ -100,6 +101,4 @@ void ksmbd_release_tree_conn_id(struct ksmbd_session *sess, int id);
|
||||
int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name);
|
||||
void ksmbd_session_rpc_close(struct ksmbd_session *sess, int id);
|
||||
int ksmbd_session_rpc_method(struct ksmbd_session *sess, int id);
|
||||
int get_session(struct ksmbd_session *sess);
|
||||
void put_session(struct ksmbd_session *sess);
|
||||
#endif /* __USER_SESSION_MANAGEMENT_H__ */
|
||||
|
@ -30,6 +30,7 @@ static DEFINE_RWLOCK(lease_list_lock);
|
||||
static struct oplock_info *alloc_opinfo(struct ksmbd_work *work,
|
||||
u64 id, __u16 Tid)
|
||||
{
|
||||
struct ksmbd_conn *conn = work->conn;
|
||||
struct ksmbd_session *sess = work->sess;
|
||||
struct oplock_info *opinfo;
|
||||
|
||||
@ -38,7 +39,7 @@ static struct oplock_info *alloc_opinfo(struct ksmbd_work *work,
|
||||
return NULL;
|
||||
|
||||
opinfo->sess = sess;
|
||||
opinfo->conn = sess->conn;
|
||||
opinfo->conn = conn;
|
||||
opinfo->level = SMB2_OPLOCK_LEVEL_NONE;
|
||||
opinfo->op_state = OPLOCK_STATE_NONE;
|
||||
opinfo->pending_break = 0;
|
||||
@ -615,18 +616,13 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
|
||||
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)) {
|
||||
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 = smb2_get_msg(work->response_buf);
|
||||
@ -667,8 +663,16 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
|
||||
|
||||
ksmbd_fd_put(work, fp);
|
||||
ksmbd_conn_write(work);
|
||||
|
||||
out:
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -731,9 +735,7 @@ static void __smb2_lease_break_noti(struct work_struct *wk)
|
||||
|
||||
if (allocate_oplock_break_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 = smb2_get_msg(work->response_buf);
|
||||
@ -771,8 +773,16 @@ static void __smb2_lease_break_noti(struct work_struct *wk)
|
||||
inc_rfc1001_len(work->response_buf, 44);
|
||||
|
||||
ksmbd_conn_write(work);
|
||||
|
||||
out:
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -972,7 +982,7 @@ int find_same_lease_key(struct ksmbd_session *sess, struct ksmbd_inode *ci,
|
||||
}
|
||||
|
||||
list_for_each_entry(lb, &lease_table_list, l_entry) {
|
||||
if (!memcmp(lb->client_guid, sess->conn->ClientGUID,
|
||||
if (!memcmp(lb->client_guid, sess->ClientGUID,
|
||||
SMB2_CLIENT_GUID_SIZE))
|
||||
goto found;
|
||||
}
|
||||
@ -988,7 +998,7 @@ found:
|
||||
rcu_read_unlock();
|
||||
if (opinfo->o_fp->f_ci == ci)
|
||||
goto op_next;
|
||||
err = compare_guid_key(opinfo, sess->conn->ClientGUID,
|
||||
err = compare_guid_key(opinfo, sess->ClientGUID,
|
||||
lctx->lease_key);
|
||||
if (err) {
|
||||
err = -EINVAL;
|
||||
@ -1122,7 +1132,7 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,
|
||||
struct oplock_info *m_opinfo;
|
||||
|
||||
/* is lease already granted ? */
|
||||
m_opinfo = same_client_has_lease(ci, sess->conn->ClientGUID,
|
||||
m_opinfo = same_client_has_lease(ci, sess->ClientGUID,
|
||||
lctx);
|
||||
if (m_opinfo) {
|
||||
copy_lease(m_opinfo, opinfo);
|
||||
@ -1240,7 +1250,7 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,
|
||||
{
|
||||
struct oplock_info *op, *brk_op;
|
||||
struct ksmbd_inode *ci;
|
||||
struct ksmbd_conn *conn = work->sess->conn;
|
||||
struct ksmbd_conn *conn = work->conn;
|
||||
|
||||
if (!test_share_config_flag(work->tcon->share_conf,
|
||||
KSMBD_SHARE_FLAG_OPLOCKS))
|
||||
|
@ -261,7 +261,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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -90,11 +90,6 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
|
||||
*off = 0;
|
||||
*len = 0;
|
||||
|
||||
/* error reqeusts do not have data area */
|
||||
if (hdr->Status && hdr->Status != STATUS_MORE_PROCESSING_REQUIRED &&
|
||||
(((struct smb2_err_rsp *)hdr)->StructureSize) == SMB2_ERROR_STRUCTURE_SIZE2_LE)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Following commands have data areas so we have to get the location
|
||||
* of the data buffer offset and data buffer length for the particular
|
||||
@ -136,8 +131,11 @@ static int smb2_get_data_area_len(unsigned int *off, unsigned int *len,
|
||||
*len = le16_to_cpu(((struct smb2_read_req *)hdr)->ReadChannelInfoLength);
|
||||
break;
|
||||
case SMB2_WRITE:
|
||||
if (((struct smb2_write_req *)hdr)->DataOffset) {
|
||||
*off = le16_to_cpu(((struct smb2_write_req *)hdr)->DataOffset);
|
||||
if (((struct smb2_write_req *)hdr)->DataOffset ||
|
||||
((struct smb2_write_req *)hdr)->Length) {
|
||||
*off = max_t(unsigned int,
|
||||
le16_to_cpu(((struct smb2_write_req *)hdr)->DataOffset),
|
||||
offsetof(struct smb2_write_req, Buffer));
|
||||
*len = le32_to_cpu(((struct smb2_write_req *)hdr)->Length);
|
||||
break;
|
||||
}
|
||||
|
@ -535,9 +535,10 @@ int smb2_allocate_rsp_buf(struct ksmbd_work *work)
|
||||
struct smb2_query_info_req *req;
|
||||
|
||||
req = smb2_get_msg(work->request_buf);
|
||||
if (req->InfoType == SMB2_O_INFO_FILE &&
|
||||
(req->FileInfoClass == FILE_FULL_EA_INFORMATION ||
|
||||
req->FileInfoClass == FILE_ALL_INFORMATION))
|
||||
if ((req->InfoType == SMB2_O_INFO_FILE &&
|
||||
(req->FileInfoClass == FILE_FULL_EA_INFORMATION ||
|
||||
req->FileInfoClass == FILE_ALL_INFORMATION)) ||
|
||||
req->InfoType == SMB2_O_INFO_SECURITY)
|
||||
sz = large_sz;
|
||||
}
|
||||
|
||||
@ -588,10 +589,12 @@ int smb2_check_user_session(struct ksmbd_work *work)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void destroy_previous_session(struct ksmbd_user *user, u64 id)
|
||||
static void destroy_previous_session(struct ksmbd_conn *conn,
|
||||
struct ksmbd_user *user, u64 id)
|
||||
{
|
||||
struct ksmbd_session *prev_sess = ksmbd_session_lookup_slowpath(id);
|
||||
struct ksmbd_user *prev_user;
|
||||
struct channel *chann;
|
||||
|
||||
if (!prev_sess)
|
||||
return;
|
||||
@ -601,13 +604,14 @@ static void destroy_previous_session(struct ksmbd_user *user, u64 id)
|
||||
if (!prev_user ||
|
||||
strcmp(user->name, prev_user->name) ||
|
||||
user->passkey_sz != prev_user->passkey_sz ||
|
||||
memcmp(user->passkey, prev_user->passkey, user->passkey_sz)) {
|
||||
put_session(prev_sess);
|
||||
memcmp(user->passkey, prev_user->passkey, user->passkey_sz))
|
||||
return;
|
||||
}
|
||||
|
||||
put_session(prev_sess);
|
||||
ksmbd_session_destroy(prev_sess);
|
||||
prev_sess->state = SMB2_SESSION_EXPIRED;
|
||||
write_lock(&prev_sess->chann_lock);
|
||||
list_for_each_entry(chann, &prev_sess->ksmbd_chann_list, chann_list)
|
||||
chann->conn->status = KSMBD_SESS_EXITING;
|
||||
write_unlock(&prev_sess->chann_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1139,12 +1143,16 @@ int smb2_handle_negotiate(struct ksmbd_work *work)
|
||||
status);
|
||||
rsp->hdr.Status = status;
|
||||
rc = -EINVAL;
|
||||
kfree(conn->preauth_info);
|
||||
conn->preauth_info = NULL;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
rc = init_smb3_11_server(conn);
|
||||
if (rc < 0) {
|
||||
rsp->hdr.Status = STATUS_INVALID_PARAMETER;
|
||||
kfree(conn->preauth_info);
|
||||
conn->preauth_info = NULL;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
@ -1439,7 +1447,7 @@ static int ntlm_authenticate(struct ksmbd_work *work)
|
||||
/* Check for previous session */
|
||||
prev_id = le64_to_cpu(req->PreviousSessionId);
|
||||
if (prev_id && prev_id != sess->id)
|
||||
destroy_previous_session(user, prev_id);
|
||||
destroy_previous_session(conn, user, prev_id);
|
||||
|
||||
if (sess->state == SMB2_SESSION_VALID) {
|
||||
/*
|
||||
@ -1493,7 +1501,7 @@ static int ntlm_authenticate(struct ksmbd_work *work)
|
||||
|
||||
if (smb3_encryption_negotiated(conn) &&
|
||||
!(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) {
|
||||
rc = conn->ops->generate_encryptionkey(sess);
|
||||
rc = conn->ops->generate_encryptionkey(conn, sess);
|
||||
if (rc) {
|
||||
ksmbd_debug(SMB,
|
||||
"SMB3 encryption key generation failed\n");
|
||||
@ -1510,7 +1518,9 @@ static int ntlm_authenticate(struct ksmbd_work *work)
|
||||
|
||||
binding_session:
|
||||
if (conn->dialect >= SMB30_PROT_ID) {
|
||||
read_lock(&sess->chann_lock);
|
||||
chann = lookup_chann_list(sess, conn);
|
||||
read_unlock(&sess->chann_lock);
|
||||
if (!chann) {
|
||||
chann = kmalloc(sizeof(struct channel), GFP_KERNEL);
|
||||
if (!chann)
|
||||
@ -1518,7 +1528,9 @@ binding_session:
|
||||
|
||||
chann->conn = conn;
|
||||
INIT_LIST_HEAD(&chann->chann_list);
|
||||
write_lock(&sess->chann_lock);
|
||||
list_add(&chann->chann_list, &sess->ksmbd_chann_list);
|
||||
write_unlock(&sess->chann_lock);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1561,7 +1573,7 @@ static int krb5_authenticate(struct ksmbd_work *work)
|
||||
/* Check previous session */
|
||||
prev_sess_id = le64_to_cpu(req->PreviousSessionId);
|
||||
if (prev_sess_id && prev_sess_id != sess->id)
|
||||
destroy_previous_session(sess->user, prev_sess_id);
|
||||
destroy_previous_session(conn, sess->user, prev_sess_id);
|
||||
|
||||
if (sess->state == SMB2_SESSION_VALID)
|
||||
ksmbd_free_user(sess->user);
|
||||
@ -1580,7 +1592,7 @@ static int krb5_authenticate(struct ksmbd_work *work)
|
||||
sess->sign = true;
|
||||
|
||||
if (smb3_encryption_negotiated(conn)) {
|
||||
retval = conn->ops->generate_encryptionkey(sess);
|
||||
retval = conn->ops->generate_encryptionkey(conn, sess);
|
||||
if (retval) {
|
||||
ksmbd_debug(SMB,
|
||||
"SMB3 encryption key generation failed\n");
|
||||
@ -1592,7 +1604,9 @@ static int krb5_authenticate(struct ksmbd_work *work)
|
||||
}
|
||||
|
||||
if (conn->dialect >= SMB30_PROT_ID) {
|
||||
read_lock(&sess->chann_lock);
|
||||
chann = lookup_chann_list(sess, conn);
|
||||
read_unlock(&sess->chann_lock);
|
||||
if (!chann) {
|
||||
chann = kmalloc(sizeof(struct channel), GFP_KERNEL);
|
||||
if (!chann)
|
||||
@ -1600,7 +1614,9 @@ static int krb5_authenticate(struct ksmbd_work *work)
|
||||
|
||||
chann->conn = conn;
|
||||
INIT_LIST_HEAD(&chann->chann_list);
|
||||
write_lock(&sess->chann_lock);
|
||||
list_add(&chann->chann_list, &sess->ksmbd_chann_list);
|
||||
write_unlock(&sess->chann_lock);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1650,7 +1666,9 @@ int smb2_sess_setup(struct ksmbd_work *work)
|
||||
goto out_err;
|
||||
}
|
||||
rsp->hdr.SessionId = cpu_to_le64(sess->id);
|
||||
ksmbd_session_register(conn, sess);
|
||||
rc = ksmbd_session_register(conn, sess);
|
||||
if (rc)
|
||||
goto out_err;
|
||||
} else if (conn->dialect >= SMB30_PROT_ID &&
|
||||
(server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) &&
|
||||
req->Flags & SMB2_SESSION_REQ_FLAG_BINDING) {
|
||||
@ -1662,7 +1680,7 @@ int smb2_sess_setup(struct ksmbd_work *work)
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (conn->dialect != sess->conn->dialect) {
|
||||
if (conn->dialect != sess->dialect) {
|
||||
rc = -EINVAL;
|
||||
goto out_err;
|
||||
}
|
||||
@ -1672,7 +1690,7 @@ int smb2_sess_setup(struct ksmbd_work *work)
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (strncmp(conn->ClientGUID, sess->conn->ClientGUID,
|
||||
if (strncmp(conn->ClientGUID, sess->ClientGUID,
|
||||
SMB2_CLIENT_GUID_SIZE)) {
|
||||
rc = -ENOENT;
|
||||
goto out_err;
|
||||
@ -1828,6 +1846,7 @@ out_err:
|
||||
if (sess->user && sess->user->flags & KSMBD_USER_FLAG_DELAY_SESSION)
|
||||
try_delay = true;
|
||||
|
||||
xa_erase(&conn->sessions, sess->id);
|
||||
ksmbd_session_destroy(sess);
|
||||
work->sess = NULL;
|
||||
if (try_delay)
|
||||
@ -1873,7 +1892,7 @@ int smb2_tree_connect(struct ksmbd_work *work)
|
||||
ksmbd_debug(SMB, "tree connect request for tree %s treename %s\n",
|
||||
name, treename);
|
||||
|
||||
status = ksmbd_tree_conn_connect(sess, name);
|
||||
status = ksmbd_tree_conn_connect(conn, sess, name);
|
||||
if (status.ret == KSMBD_TREE_CONN_STATUS_OK)
|
||||
rsp->hdr.Id.SyncId.TreeId = cpu_to_le32(status.tree_conn->id);
|
||||
else
|
||||
@ -2039,6 +2058,7 @@ int smb2_tree_disconnect(struct ksmbd_work *work)
|
||||
|
||||
ksmbd_close_tree_conn_fds(work);
|
||||
ksmbd_tree_conn_disconnect(sess, tcon);
|
||||
work->tcon = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2969,7 +2989,7 @@ int smb2_open(struct ksmbd_work *work)
|
||||
goto err_out;
|
||||
|
||||
rc = build_sec_desc(user_ns,
|
||||
pntsd, NULL,
|
||||
pntsd, NULL, 0,
|
||||
OWNER_SECINFO |
|
||||
GROUP_SECINFO |
|
||||
DACL_SECINFO,
|
||||
@ -3814,6 +3834,15 @@ static int verify_info_level(int info_level)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smb2_resp_buf_len(struct ksmbd_work *work, unsigned short hdr2_len)
|
||||
{
|
||||
int free_len;
|
||||
|
||||
free_len = (int)(work->response_sz -
|
||||
(get_rfc1002_len(work->response_buf) + 4)) - hdr2_len;
|
||||
return free_len;
|
||||
}
|
||||
|
||||
static int smb2_calc_max_out_buf_len(struct ksmbd_work *work,
|
||||
unsigned short hdr2_len,
|
||||
unsigned int out_buf_len)
|
||||
@ -3823,9 +3852,7 @@ static int smb2_calc_max_out_buf_len(struct ksmbd_work *work,
|
||||
if (out_buf_len > work->conn->vals->max_trans_size)
|
||||
return -EINVAL;
|
||||
|
||||
free_len = (int)(work->response_sz -
|
||||
(get_rfc1002_len(work->response_buf) + 4)) -
|
||||
hdr2_len;
|
||||
free_len = smb2_resp_buf_len(work, hdr2_len);
|
||||
if (free_len < 0)
|
||||
return -EINVAL;
|
||||
|
||||
@ -4858,7 +4885,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
|
||||
struct smb2_query_info_rsp *rsp)
|
||||
{
|
||||
struct ksmbd_session *sess = work->sess;
|
||||
struct ksmbd_conn *conn = sess->conn;
|
||||
struct ksmbd_conn *conn = work->conn;
|
||||
struct ksmbd_share_config *share = work->tcon->share_conf;
|
||||
int fsinfoclass = 0;
|
||||
struct kstatfs stfs;
|
||||
@ -5088,10 +5115,10 @@ static int smb2_get_info_sec(struct ksmbd_work *work,
|
||||
struct smb_ntsd *pntsd = (struct smb_ntsd *)rsp->Buffer, *ppntsd = NULL;
|
||||
struct smb_fattr fattr = {{0}};
|
||||
struct inode *inode;
|
||||
__u32 secdesclen;
|
||||
__u32 secdesclen = 0;
|
||||
unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID;
|
||||
int addition_info = le32_to_cpu(req->AdditionalInformation);
|
||||
int rc;
|
||||
int rc = 0, ppntsd_size = 0;
|
||||
|
||||
if (addition_info & ~(OWNER_SECINFO | GROUP_SECINFO | DACL_SECINFO |
|
||||
PROTECTED_DACL_SECINFO |
|
||||
@ -5137,11 +5164,14 @@ static int smb2_get_info_sec(struct ksmbd_work *work,
|
||||
|
||||
if (test_share_config_flag(work->tcon->share_conf,
|
||||
KSMBD_SHARE_FLAG_ACL_XATTR))
|
||||
ksmbd_vfs_get_sd_xattr(work->conn, user_ns,
|
||||
fp->filp->f_path.dentry, &ppntsd);
|
||||
ppntsd_size = ksmbd_vfs_get_sd_xattr(work->conn, user_ns,
|
||||
fp->filp->f_path.dentry,
|
||||
&ppntsd);
|
||||
|
||||
rc = build_sec_desc(user_ns, pntsd, ppntsd, addition_info,
|
||||
&secdesclen, &fattr);
|
||||
/* Check if sd buffer size exceeds response buffer size */
|
||||
if (smb2_resp_buf_len(work, 8) > ppntsd_size)
|
||||
rc = build_sec_desc(user_ns, pntsd, ppntsd, ppntsd_size,
|
||||
addition_info, &secdesclen, &fattr);
|
||||
posix_acl_release(fattr.cf_acls);
|
||||
posix_acl_release(fattr.cf_dacls);
|
||||
kfree(ppntsd);
|
||||
@ -5776,7 +5806,7 @@ static int set_rename_info(struct ksmbd_work *work, struct ksmbd_file *fp,
|
||||
}
|
||||
next:
|
||||
return smb2_rename(work, fp, user_ns, rename_info,
|
||||
work->sess->conn->local_nls);
|
||||
work->conn->local_nls);
|
||||
}
|
||||
|
||||
static int set_file_disposition_info(struct ksmbd_file *fp,
|
||||
@ -5908,7 +5938,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
|
||||
return smb2_create_link(work, work->tcon->share_conf,
|
||||
(struct smb2_file_link_info *)req->Buffer,
|
||||
buf_len, fp->filp,
|
||||
work->sess->conn->local_nls);
|
||||
work->conn->local_nls);
|
||||
}
|
||||
case FILE_DISPOSITION_INFORMATION:
|
||||
{
|
||||
@ -6495,14 +6525,12 @@ int smb2_write(struct ksmbd_work *work)
|
||||
writethrough = true;
|
||||
|
||||
if (is_rdma_channel == false) {
|
||||
if ((u64)le16_to_cpu(req->DataOffset) + length >
|
||||
get_rfc1002_len(work->request_buf)) {
|
||||
pr_err("invalid write data offset %u, smb_len %u\n",
|
||||
le16_to_cpu(req->DataOffset),
|
||||
get_rfc1002_len(work->request_buf));
|
||||
if (le16_to_cpu(req->DataOffset) <
|
||||
offsetof(struct smb2_write_req, Buffer)) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
data_buf = (char *)(((char *)&req->hdr.ProtocolId) +
|
||||
le16_to_cpu(req->DataOffset));
|
||||
|
||||
@ -8356,10 +8384,14 @@ int smb3_check_sign_req(struct ksmbd_work *work)
|
||||
if (le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) {
|
||||
signing_key = work->sess->smb3signingkey;
|
||||
} else {
|
||||
read_lock(&work->sess->chann_lock);
|
||||
chann = lookup_chann_list(work->sess, conn);
|
||||
if (!chann)
|
||||
if (!chann) {
|
||||
read_unlock(&work->sess->chann_lock);
|
||||
return 0;
|
||||
}
|
||||
signing_key = chann->smb3signingkey;
|
||||
read_unlock(&work->sess->chann_lock);
|
||||
}
|
||||
|
||||
if (!signing_key) {
|
||||
@ -8419,10 +8451,14 @@ void smb3_set_sign_rsp(struct ksmbd_work *work)
|
||||
le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) {
|
||||
signing_key = work->sess->smb3signingkey;
|
||||
} else {
|
||||
read_lock(&work->sess->chann_lock);
|
||||
chann = lookup_chann_list(work->sess, work->conn);
|
||||
if (!chann)
|
||||
if (!chann) {
|
||||
read_unlock(&work->sess->chann_lock);
|
||||
return;
|
||||
}
|
||||
signing_key = chann->smb3signingkey;
|
||||
read_unlock(&work->sess->chann_lock);
|
||||
}
|
||||
|
||||
if (!signing_key)
|
||||
|
@ -421,7 +421,7 @@ struct smb_version_ops {
|
||||
int (*check_sign_req)(struct ksmbd_work *work);
|
||||
void (*set_sign_rsp)(struct ksmbd_work *work);
|
||||
int (*generate_signingkey)(struct ksmbd_session *sess, struct ksmbd_conn *conn);
|
||||
int (*generate_encryptionkey)(struct ksmbd_session *sess);
|
||||
int (*generate_encryptionkey)(struct ksmbd_conn *conn, struct ksmbd_session *sess);
|
||||
bool (*is_transform_hdr)(void *buf);
|
||||
int (*decrypt_req)(struct ksmbd_work *work);
|
||||
int (*encrypt_resp)(struct ksmbd_work *work);
|
||||
|
@ -690,6 +690,7 @@ posix_default_acl:
|
||||
static void set_ntacl_dacl(struct user_namespace *user_ns,
|
||||
struct smb_acl *pndacl,
|
||||
struct smb_acl *nt_dacl,
|
||||
unsigned int aces_size,
|
||||
const struct smb_sid *pownersid,
|
||||
const struct smb_sid *pgrpsid,
|
||||
struct smb_fattr *fattr)
|
||||
@ -703,9 +704,19 @@ static void set_ntacl_dacl(struct user_namespace *user_ns,
|
||||
if (nt_num_aces) {
|
||||
ntace = (struct smb_ace *)((char *)nt_dacl + sizeof(struct smb_acl));
|
||||
for (i = 0; i < nt_num_aces; i++) {
|
||||
memcpy((char *)pndace + size, ntace, le16_to_cpu(ntace->size));
|
||||
size += le16_to_cpu(ntace->size);
|
||||
ntace = (struct smb_ace *)((char *)ntace + le16_to_cpu(ntace->size));
|
||||
unsigned short nt_ace_size;
|
||||
|
||||
if (offsetof(struct smb_ace, access_req) > aces_size)
|
||||
break;
|
||||
|
||||
nt_ace_size = le16_to_cpu(ntace->size);
|
||||
if (nt_ace_size > aces_size)
|
||||
break;
|
||||
|
||||
memcpy((char *)pndace + size, ntace, nt_ace_size);
|
||||
size += nt_ace_size;
|
||||
aces_size -= nt_ace_size;
|
||||
ntace = (struct smb_ace *)((char *)ntace + nt_ace_size);
|
||||
num_aces++;
|
||||
}
|
||||
}
|
||||
@ -878,7 +889,7 @@ int parse_sec_desc(struct user_namespace *user_ns, struct smb_ntsd *pntsd,
|
||||
/* Convert permission bits from mode to equivalent CIFS ACL */
|
||||
int build_sec_desc(struct user_namespace *user_ns,
|
||||
struct smb_ntsd *pntsd, struct smb_ntsd *ppntsd,
|
||||
int addition_info, __u32 *secdesclen,
|
||||
int ppntsd_size, int addition_info, __u32 *secdesclen,
|
||||
struct smb_fattr *fattr)
|
||||
{
|
||||
int rc = 0;
|
||||
@ -938,15 +949,25 @@ int build_sec_desc(struct user_namespace *user_ns,
|
||||
|
||||
if (!ppntsd) {
|
||||
set_mode_dacl(user_ns, dacl_ptr, fattr);
|
||||
} else if (!ppntsd->dacloffset) {
|
||||
goto out;
|
||||
} else {
|
||||
struct smb_acl *ppdacl_ptr;
|
||||
unsigned int dacl_offset = le32_to_cpu(ppntsd->dacloffset);
|
||||
int ppdacl_size, ntacl_size = ppntsd_size - dacl_offset;
|
||||
|
||||
if (!dacl_offset ||
|
||||
(dacl_offset + sizeof(struct smb_acl) > ppntsd_size))
|
||||
goto out;
|
||||
|
||||
ppdacl_ptr = (struct smb_acl *)((char *)ppntsd + dacl_offset);
|
||||
ppdacl_size = le16_to_cpu(ppdacl_ptr->size);
|
||||
if (ppdacl_size > ntacl_size ||
|
||||
ppdacl_size < sizeof(struct smb_acl))
|
||||
goto out;
|
||||
|
||||
ppdacl_ptr = (struct smb_acl *)((char *)ppntsd +
|
||||
le32_to_cpu(ppntsd->dacloffset));
|
||||
set_ntacl_dacl(user_ns, dacl_ptr, ppdacl_ptr,
|
||||
nowner_sid_ptr, ngroup_sid_ptr, fattr);
|
||||
ntacl_size - sizeof(struct smb_acl),
|
||||
nowner_sid_ptr, ngroup_sid_ptr,
|
||||
fattr);
|
||||
}
|
||||
pntsd->dacloffset = cpu_to_le32(offset);
|
||||
offset += le16_to_cpu(dacl_ptr->size);
|
||||
@ -980,24 +1001,31 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
|
||||
struct smb_sid owner_sid, group_sid;
|
||||
struct dentry *parent = path->dentry->d_parent;
|
||||
struct user_namespace *user_ns = mnt_user_ns(path->mnt);
|
||||
int inherited_flags = 0, flags = 0, i, ace_cnt = 0, nt_size = 0;
|
||||
int rc = 0, num_aces, dacloffset, pntsd_type, acl_len;
|
||||
int inherited_flags = 0, flags = 0, i, ace_cnt = 0, nt_size = 0, pdacl_size;
|
||||
int rc = 0, num_aces, dacloffset, pntsd_type, pntsd_size, acl_len, aces_size;
|
||||
char *aces_base;
|
||||
bool is_dir = S_ISDIR(d_inode(path->dentry)->i_mode);
|
||||
|
||||
acl_len = ksmbd_vfs_get_sd_xattr(conn, user_ns,
|
||||
parent, &parent_pntsd);
|
||||
if (acl_len <= 0)
|
||||
pntsd_size = ksmbd_vfs_get_sd_xattr(conn, user_ns,
|
||||
parent, &parent_pntsd);
|
||||
if (pntsd_size <= 0)
|
||||
return -ENOENT;
|
||||
dacloffset = le32_to_cpu(parent_pntsd->dacloffset);
|
||||
if (!dacloffset) {
|
||||
if (!dacloffset || (dacloffset + sizeof(struct smb_acl) > pntsd_size)) {
|
||||
rc = -EINVAL;
|
||||
goto free_parent_pntsd;
|
||||
}
|
||||
|
||||
parent_pdacl = (struct smb_acl *)((char *)parent_pntsd + dacloffset);
|
||||
acl_len = pntsd_size - dacloffset;
|
||||
num_aces = le32_to_cpu(parent_pdacl->num_aces);
|
||||
pntsd_type = le16_to_cpu(parent_pntsd->type);
|
||||
pdacl_size = le16_to_cpu(parent_pdacl->size);
|
||||
|
||||
if (pdacl_size > acl_len || pdacl_size < sizeof(struct smb_acl)) {
|
||||
rc = -EINVAL;
|
||||
goto free_parent_pntsd;
|
||||
}
|
||||
|
||||
aces_base = kmalloc(sizeof(struct smb_ace) * num_aces * 2, GFP_KERNEL);
|
||||
if (!aces_base) {
|
||||
@ -1008,11 +1036,23 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
|
||||
aces = (struct smb_ace *)aces_base;
|
||||
parent_aces = (struct smb_ace *)((char *)parent_pdacl +
|
||||
sizeof(struct smb_acl));
|
||||
aces_size = acl_len - sizeof(struct smb_acl);
|
||||
|
||||
if (pntsd_type & DACL_AUTO_INHERITED)
|
||||
inherited_flags = INHERITED_ACE;
|
||||
|
||||
for (i = 0; i < num_aces; i++) {
|
||||
int pace_size;
|
||||
|
||||
if (offsetof(struct smb_ace, access_req) > aces_size)
|
||||
break;
|
||||
|
||||
pace_size = le16_to_cpu(parent_aces->size);
|
||||
if (pace_size > aces_size)
|
||||
break;
|
||||
|
||||
aces_size -= pace_size;
|
||||
|
||||
flags = parent_aces->flags;
|
||||
if (!smb_inherit_flags(flags, is_dir))
|
||||
goto pass;
|
||||
@ -1057,8 +1097,7 @@ int smb_inherit_dacl(struct ksmbd_conn *conn,
|
||||
aces = (struct smb_ace *)((char *)aces + le16_to_cpu(aces->size));
|
||||
ace_cnt++;
|
||||
pass:
|
||||
parent_aces =
|
||||
(struct smb_ace *)((char *)parent_aces + le16_to_cpu(parent_aces->size));
|
||||
parent_aces = (struct smb_ace *)((char *)parent_aces + pace_size);
|
||||
}
|
||||
|
||||
if (nt_size > 0) {
|
||||
@ -1153,7 +1192,7 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, struct path *path,
|
||||
struct smb_ntsd *pntsd = NULL;
|
||||
struct smb_acl *pdacl;
|
||||
struct posix_acl *posix_acls;
|
||||
int rc = 0, acl_size;
|
||||
int rc = 0, pntsd_size, acl_size, aces_size, pdacl_size, dacl_offset;
|
||||
struct smb_sid sid;
|
||||
int granted = le32_to_cpu(*pdaccess & ~FILE_MAXIMAL_ACCESS_LE);
|
||||
struct smb_ace *ace;
|
||||
@ -1162,37 +1201,33 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, struct path *path,
|
||||
struct smb_ace *others_ace = NULL;
|
||||
struct posix_acl_entry *pa_entry;
|
||||
unsigned int sid_type = SIDOWNER;
|
||||
char *end_of_acl;
|
||||
unsigned short ace_size;
|
||||
|
||||
ksmbd_debug(SMB, "check permission using windows acl\n");
|
||||
acl_size = ksmbd_vfs_get_sd_xattr(conn, user_ns,
|
||||
path->dentry, &pntsd);
|
||||
if (acl_size <= 0 || !pntsd || !pntsd->dacloffset) {
|
||||
kfree(pntsd);
|
||||
return 0;
|
||||
}
|
||||
pntsd_size = ksmbd_vfs_get_sd_xattr(conn, user_ns,
|
||||
path->dentry, &pntsd);
|
||||
if (pntsd_size <= 0 || !pntsd)
|
||||
goto err_out;
|
||||
|
||||
dacl_offset = le32_to_cpu(pntsd->dacloffset);
|
||||
if (!dacl_offset ||
|
||||
(dacl_offset + sizeof(struct smb_acl) > pntsd_size))
|
||||
goto err_out;
|
||||
|
||||
pdacl = (struct smb_acl *)((char *)pntsd + le32_to_cpu(pntsd->dacloffset));
|
||||
end_of_acl = ((char *)pntsd) + acl_size;
|
||||
if (end_of_acl <= (char *)pdacl) {
|
||||
kfree(pntsd);
|
||||
return 0;
|
||||
}
|
||||
acl_size = pntsd_size - dacl_offset;
|
||||
pdacl_size = le16_to_cpu(pdacl->size);
|
||||
|
||||
if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size) ||
|
||||
le16_to_cpu(pdacl->size) < sizeof(struct smb_acl)) {
|
||||
kfree(pntsd);
|
||||
return 0;
|
||||
}
|
||||
if (pdacl_size > acl_size || pdacl_size < sizeof(struct smb_acl))
|
||||
goto err_out;
|
||||
|
||||
if (!pdacl->num_aces) {
|
||||
if (!(le16_to_cpu(pdacl->size) - sizeof(struct smb_acl)) &&
|
||||
if (!(pdacl_size - sizeof(struct smb_acl)) &&
|
||||
*pdaccess & ~(FILE_READ_CONTROL_LE | FILE_WRITE_DAC_LE)) {
|
||||
rc = -EACCES;
|
||||
goto err_out;
|
||||
}
|
||||
kfree(pntsd);
|
||||
return 0;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (*pdaccess & FILE_MAXIMAL_ACCESS_LE) {
|
||||
@ -1200,11 +1235,16 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, struct path *path,
|
||||
DELETE;
|
||||
|
||||
ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl));
|
||||
aces_size = acl_size - sizeof(struct smb_acl);
|
||||
for (i = 0; i < le32_to_cpu(pdacl->num_aces); i++) {
|
||||
if (offsetof(struct smb_ace, access_req) > aces_size)
|
||||
break;
|
||||
ace_size = le16_to_cpu(ace->size);
|
||||
if (ace_size > aces_size)
|
||||
break;
|
||||
aces_size -= ace_size;
|
||||
granted |= le32_to_cpu(ace->access_req);
|
||||
ace = (struct smb_ace *)((char *)ace + le16_to_cpu(ace->size));
|
||||
if (end_of_acl < (char *)ace)
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (!pdacl->num_aces)
|
||||
@ -1216,7 +1256,15 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, struct path *path,
|
||||
id_to_sid(uid, sid_type, &sid);
|
||||
|
||||
ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl));
|
||||
aces_size = acl_size - sizeof(struct smb_acl);
|
||||
for (i = 0; i < le32_to_cpu(pdacl->num_aces); i++) {
|
||||
if (offsetof(struct smb_ace, access_req) > aces_size)
|
||||
break;
|
||||
ace_size = le16_to_cpu(ace->size);
|
||||
if (ace_size > aces_size)
|
||||
break;
|
||||
aces_size -= ace_size;
|
||||
|
||||
if (!compare_sids(&sid, &ace->sid) ||
|
||||
!compare_sids(&sid_unix_NFS_mode, &ace->sid)) {
|
||||
found = 1;
|
||||
@ -1226,8 +1274,6 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, struct path *path,
|
||||
others_ace = ace;
|
||||
|
||||
ace = (struct smb_ace *)((char *)ace + le16_to_cpu(ace->size));
|
||||
if (end_of_acl < (char *)ace)
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (*pdaccess & FILE_MAXIMAL_ACCESS_LE && found) {
|
||||
|
@ -193,7 +193,7 @@ struct posix_acl_state {
|
||||
int parse_sec_desc(struct user_namespace *user_ns, struct smb_ntsd *pntsd,
|
||||
int acl_len, struct smb_fattr *fattr);
|
||||
int build_sec_desc(struct user_namespace *user_ns, struct smb_ntsd *pntsd,
|
||||
struct smb_ntsd *ppntsd, int addition_info,
|
||||
struct smb_ntsd *ppntsd, int ppntsd_size, int addition_info,
|
||||
__u32 *secdesclen, struct smb_fattr *fattr);
|
||||
int init_acl_state(struct posix_acl_state *state, int cnt);
|
||||
void free_acl_state(struct posix_acl_state *state);
|
||||
|
@ -481,12 +481,11 @@ 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)
|
||||
{
|
||||
struct ksmbd_session *sess = work->sess;
|
||||
struct file *filp;
|
||||
loff_t offset = *pos;
|
||||
int err = 0;
|
||||
|
||||
if (sess->conn->connection_type) {
|
||||
if (work->conn->connection_type) {
|
||||
if (!(fp->daccess & FILE_WRITE_DATA_LE)) {
|
||||
pr_err("no right to write(%pd)\n",
|
||||
fp->filp->f_path.dentry);
|
||||
@ -1540,6 +1539,11 @@ int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn,
|
||||
}
|
||||
|
||||
*pntsd = acl.sd_buf;
|
||||
if (acl.sd_size < sizeof(struct smb_ntsd)) {
|
||||
pr_err("sd size is invalid\n");
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
(*pntsd)->osidoffset = cpu_to_le32(le32_to_cpu((*pntsd)->osidoffset) -
|
||||
NDR_NTSD_OFFSETOF);
|
||||
(*pntsd)->gsidoffset = cpu_to_le32(le32_to_cpu((*pntsd)->gsidoffset) -
|
||||
|
@ -569,7 +569,7 @@ struct ksmbd_file *ksmbd_open_fd(struct ksmbd_work *work, struct file *filp)
|
||||
atomic_set(&fp->refcount, 1);
|
||||
|
||||
fp->filp = filp;
|
||||
fp->conn = work->sess->conn;
|
||||
fp->conn = work->conn;
|
||||
fp->tcon = work->tcon;
|
||||
fp->volatile_id = KSMBD_NO_FID;
|
||||
fp->persistent_id = KSMBD_NO_FID;
|
||||
|
Loading…
x
Reference in New Issue
Block a user