summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNamjae Jeon <linkinjeon@kernel.org>2026-07-26 22:49:45 +0900
committerNamjae Jeon <linkinjeon@kernel.org>2026-08-17 15:00:54 +0900
commita47634cd729b42dfe372048b056d98ba4e128eaa (patch)
treee05a679ca16f7fb719435c1643f89a2276cabb50
parent84c41b731b019f1e5a97c21ac1a4a4c63b6be38f (diff)
ksmbd: expire SMB sessions when Kerberos tickets expire
Store the expiry time from the Kerberos authentication response in the session and reject requests after that time with STATUS_NETWORK_SESSION_EXPIRED. Allow an expired Kerberos session to be reauthenticated. Keep the old SMB signing key until its SESSION_SETUP response has been signed, then install the new session key and regenerate the SMB3 keys. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
-rw-r--r--fs/smb/server/auth.c18
-rw-r--r--fs/smb/server/ksmbd_netlink.h1
-rw-r--r--fs/smb/server/ksmbd_work.h1
-rw-r--r--fs/smb/server/mgmt/user_session.c14
-rw-r--r--fs/smb/server/mgmt/user_session.h3
-rw-r--r--fs/smb/server/server.c9
-rw-r--r--fs/smb/server/smb2pdu.c270
7 files changed, 236 insertions, 80 deletions
diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c
index f2100e3ec54c..d51f32095ada 100644
--- a/fs/smb/server/auth.c
+++ b/fs/smb/server/auth.c
@@ -463,6 +463,7 @@ int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob,
memcpy(out_blob, resp->payload + resp->session_key_len,
resp->spnego_blob_len);
*out_len = resp->spnego_blob_len;
+ sess->kerberos_expiry = resp->session_expiry;
retval = 0;
out:
kvfree(resp);
@@ -717,8 +718,21 @@ static int ksmbd_get_encryption_key(struct ksmbd_work *work, __u64 ses_id,
if (enc)
sess = work->sess;
- else
- sess = ksmbd_session_lookup_all(work->conn, ses_id);
+ else {
+ /*
+ * An encrypted SESSION_SETUP request may reauthenticate an expired
+ * Kerberos session. Keep using the established decryption key so
+ * that the command can reach the session setup handler. Other
+ * commands are rejected there with STATUS_NETWORK_SESSION_EXPIRED.
+ */
+ sess = ksmbd_session_lookup(work->conn, ses_id);
+ if (sess && sess->state != SMB2_SESSION_VALID &&
+ (sess->state != SMB2_SESSION_EXPIRED ||
+ !sess->kerberos_expiry)) {
+ ksmbd_user_session_put(sess);
+ sess = NULL;
+ }
+ }
if (!sess)
return -EINVAL;
diff --git a/fs/smb/server/ksmbd_netlink.h b/fs/smb/server/ksmbd_netlink.h
index 1ea0a367b396..af1e760453d9 100644
--- a/fs/smb/server/ksmbd_netlink.h
+++ b/fs/smb/server/ksmbd_netlink.h
@@ -286,6 +286,7 @@ struct ksmbd_spnego_authen_response {
* stored in SecurityBuffer of SMB2 SESSION
* SETUP response
*/
+ __u64 session_expiry; /* Kerberos ticket expiry time */
__u8 payload[]; /* session key + AP_REP */
};
diff --git a/fs/smb/server/ksmbd_work.h b/fs/smb/server/ksmbd_work.h
index 52d0c4dee65c..5f1d3ebab4fb 100644
--- a/fs/smb/server/ksmbd_work.h
+++ b/fs/smb/server/ksmbd_work.h
@@ -95,6 +95,7 @@ struct ksmbd_work {
bool owns_conn_ref:1;
bool need_invalidate_rkey:1;
bool request_open_chseq_tracked:1;
+ bool session_setup_reauth:1;
unsigned int remote_key;
/* cancel works */
diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c
index 65f3ce3c6e95..0a87a1378791 100644
--- a/fs/smb/server/mgmt/user_session.c
+++ b/fs/smb/server/mgmt/user_session.c
@@ -547,8 +547,8 @@ struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id)
return sess;
}
-struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,
- unsigned long long id)
+struct ksmbd_session *ksmbd_session_lookup_all_states(struct ksmbd_conn *conn,
+ unsigned long long id)
{
struct ksmbd_session *sess;
@@ -560,6 +560,15 @@ struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,
sess = NULL;
}
}
+ return sess;
+}
+
+struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,
+ unsigned long long id)
+{
+ struct ksmbd_session *sess;
+
+ sess = ksmbd_session_lookup_all_states(conn, id);
if (sess && sess->state != SMB2_SESSION_VALID) {
ksmbd_user_session_put(sess);
sess = NULL;
@@ -639,6 +648,7 @@ void destroy_previous_session(struct ksmbd_conn *conn,
}
ksmbd_destroy_file_table(prev_sess);
+ prev_sess->kerberos_expiry = 0;
prev_sess->state = SMB2_SESSION_EXPIRED;
ksmbd_all_conn_set_status(id, KSMBD_SESS_NEED_SETUP);
ksmbd_launch_ksmbd_durable_scavenger();
diff --git a/fs/smb/server/mgmt/user_session.h b/fs/smb/server/mgmt/user_session.h
index 2a0168e08328..f8a24c33f7fe 100644
--- a/fs/smb/server/mgmt/user_session.h
+++ b/fs/smb/server/mgmt/user_session.h
@@ -47,6 +47,7 @@ struct ksmbd_session {
__u8 *Preauth_HashValue;
char sess_key[CIFS_KEY_SIZE];
+ u64 kerberos_expiry;
struct hlist_node hlist;
struct rw_semaphore chann_lock;
@@ -100,6 +101,8 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn);
struct ksmbd_session *__session_lookup(unsigned long long id);
struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,
unsigned long long id);
+struct ksmbd_session *ksmbd_session_lookup_all_states(struct ksmbd_conn *conn,
+ unsigned long long id);
void destroy_previous_session(struct ksmbd_conn *conn,
struct ksmbd_user *user, u64 id);
struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn,
diff --git a/fs/smb/server/server.c b/fs/smb/server/server.c
index 5b38406129b5..18c20a669307 100644
--- a/fs/smb/server/server.c
+++ b/fs/smb/server/server.c
@@ -208,6 +208,9 @@ static void __handle_ksmbd_work(struct ksmbd_work *work,
if (rc == -EINVAL)
conn->ops->set_rsp_status(work,
STATUS_INVALID_PARAMETER);
+ else if (rc == -EKEYEXPIRED)
+ conn->ops->set_rsp_status(work,
+ STATUS_NETWORK_SESSION_EXPIRED);
else
conn->ops->set_rsp_status(work,
STATUS_USER_SESSION_DELETED);
@@ -215,7 +218,11 @@ static void __handle_ksmbd_work(struct ksmbd_work *work,
struct smb2_hdr *rsp_hdr;
rsp_hdr = ksmbd_resp_buf_curr(work);
- rsp_hdr->Flags |= SMB2_FLAGS_SIGNED;
+ if (rc == -EKEYEXPIRED && work->sess &&
+ conn->ops->set_sign_rsp)
+ conn->ops->set_sign_rsp(work);
+ else
+ rsp_hdr->Flags |= SMB2_FLAGS_SIGNED;
}
goto send;
} else if (rc > 0) {
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index ed6fb63d4a6d..77c9e027d6aa 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -15,6 +15,7 @@
#include <linux/mount.h>
#include <linux/filelock.h>
#include <linux/fileattr.h>
+#include <linux/timekeeping.h>
#include "glob.h"
#include "../common/smbfsctl.h"
@@ -55,6 +56,10 @@ static void __wbuf(struct ksmbd_work *work, void **req, void **rsp)
}
}
+static struct ksmbd_work *smb2_notify_cancel_claim(void **argv);
+static void smb2_notify_cancel_fn(void **argv);
+static void smb2_complete_notify_cancel(struct ksmbd_work *in_work);
+
#define WORK_BUFFERS(w, rq, rs) __wbuf((w), (void **)&(rq), (void **)&(rs))
#define SMB2_CREATE_FILE_ATTRIBUTE_MASK \
@@ -67,29 +72,6 @@ static void __wbuf(struct ksmbd_work *work, void **req, void **rsp)
/* MAXFILESIZE in [MS-FSA] 2.1.5.3 Server Requests a Write. */
#define SMB2_MAX_FILE_SIZE 0xfffffff0000ULL
-/**
- * check_session_id() - check for valid session id in smb header
- * @conn: connection instance
- * @id: session id from smb header
- *
- * Return: 1 if valid session id, otherwise 0
- */
-static inline bool check_session_id(struct ksmbd_conn *conn, u64 id)
-{
- struct ksmbd_session *sess;
-
- if (id == 0 || id == -1)
- return false;
-
- sess = ksmbd_session_lookup_all(conn, id);
- if (sess) {
- ksmbd_user_session_put(sess);
- return true;
- }
- pr_err("Invalid user session id: %llu\n", id);
- return false;
-}
-
struct channel *lookup_chann_list(struct ksmbd_session *sess, struct ksmbd_conn *conn)
{
struct channel *chann;
@@ -899,6 +881,47 @@ int smb2_allocate_rsp_buf(struct ksmbd_work *work)
return 0;
}
+static bool smb2_session_expired_cmd_allowed(struct ksmbd_work *work,
+ unsigned int cmd)
+{
+ struct smb2_lock_req *req;
+ unsigned int len, lock_count, i;
+
+ if (cmd == SMB2_CANCEL_HE || cmd == SMB2_CLOSE_HE ||
+ cmd == SMB2_LOGOFF_HE)
+ return true;
+ if (cmd != SMB2_LOCK_HE)
+ return false;
+
+ req = ksmbd_req_buf_next(work);
+ if (req->hdr.NextCommand)
+ len = le32_to_cpu(req->hdr.NextCommand);
+ else {
+ len = get_rfc1002_len(work->request_buf);
+ if (len < work->next_smb2_rcv_hdr_off)
+ return false;
+ len -= work->next_smb2_rcv_hdr_off;
+ }
+
+ lock_count = le16_to_cpu(req->LockCount);
+ if (!lock_count || len < offsetof(struct smb2_lock_req, locks) ||
+ lock_count > (len - offsetof(struct smb2_lock_req, locks)) /
+ sizeof(struct smb2_lock_element))
+ return false;
+
+ for (i = 0; i < lock_count; i++) {
+ if (le32_to_cpu(req->locks[i].Flags) != SMB2_LOCKFLAG_UNLOCK)
+ return false;
+ }
+ return true;
+}
+
+static bool smb2_session_kerberos_expired(struct ksmbd_session *sess)
+{
+ return sess->kerberos_expiry &&
+ ktime_get_real_seconds() >= sess->kerberos_expiry;
+}
+
/**
* smb2_check_user_session() - check for valid session for a user
* @work: smb work containing smb request buffer
@@ -913,19 +936,37 @@ int smb2_check_user_session(struct ksmbd_work *work)
unsigned long long sess_id;
/*
- * SMB2_ECHO, SMB2_NEGOTIATE, SMB2_SESSION_SETUP command do not
- * require a session id, so no need to validate user session's for
- * these commands.
+ * SMB2_NEGOTIATE and SMB2_SESSION_SETUP do not require a session id.
+ * SMB2_ECHO may omit it, but an echo carrying a session id still needs
+ * the session attached to work so that its signature can be checked and
+ * the response can be signed, including after Kerberos expiry.
*/
- if (cmd == SMB2_ECHO_HE || cmd == SMB2_NEGOTIATE_HE ||
- cmd == SMB2_SESSION_SETUP_HE)
+ if (cmd == SMB2_NEGOTIATE_HE || cmd == SMB2_SESSION_SETUP_HE)
return 0;
+ sess_id = le64_to_cpu(req_hdr->SessionId);
+ if (cmd == SMB2_ECHO_HE) {
+ /*
+ * ECHO remains valid without a live session, including after
+ * LOGOFF. Attach an existing session only to authenticate a signed
+ * ECHO and sign its response; a stale SessionId is not an error.
+ */
+ if (!work->next_smb2_rcv_hdr_off && sess_id)
+ work->sess = ksmbd_session_lookup_all_states(conn, sess_id);
+ if (work->sess) {
+ if (smb2_session_kerberos_expired(work->sess)) {
+ work->sess->state = SMB2_SESSION_EXPIRED;
+ } else if (work->sess->state != SMB2_SESSION_VALID) {
+ ksmbd_user_session_put(work->sess);
+ work->sess = NULL;
+ }
+ }
+ return 0;
+ }
+
if (!ksmbd_conn_good(conn))
return -EIO;
- sess_id = le64_to_cpu(req_hdr->SessionId);
-
/*
* If request is not the first in Compound request,
* Just validate session id in header with work->sess->id.
@@ -940,18 +981,35 @@ int smb2_check_user_session(struct ksmbd_work *work)
sess_id, work->sess->id);
return -EINVAL;
}
+ if (smb2_session_kerberos_expired(work->sess))
+ work->sess->state = SMB2_SESSION_EXPIRED;
if (work->sess->state != SMB2_SESSION_VALID) {
pr_err("compound request on a non-valid session (state %d)\n",
work->sess->state);
- return -EINVAL;
+ if (smb2_session_kerberos_expired(work->sess) &&
+ smb2_session_expired_cmd_allowed(work, cmd))
+ return 1;
+ return smb2_session_kerberos_expired(work->sess) ?
+ -EKEYEXPIRED : -EINVAL;
}
return 1;
}
/* Check for validity of user session */
- work->sess = ksmbd_session_lookup_all(conn, sess_id);
- if (work->sess)
+ work->sess = ksmbd_session_lookup_all_states(conn, sess_id);
+ if (work->sess) {
+ if (smb2_session_kerberos_expired(work->sess)) {
+ work->sess->state = SMB2_SESSION_EXPIRED;
+ return smb2_session_expired_cmd_allowed(work, cmd) ?
+ 1 : -EKEYEXPIRED;
+ }
+ if (work->sess->state != SMB2_SESSION_VALID) {
+ ksmbd_user_session_put(work->sess);
+ work->sess = NULL;
+ return -ENOENT;
+ }
return 1;
+ }
ksmbd_debug(SMB, "Invalid user session, Uid %llu\n", sess_id);
return -ENOENT;
}
@@ -2082,7 +2140,9 @@ static int krb5_authenticate(struct ksmbd_work *work,
struct ksmbd_session *sess = work->sess;
char *in_blob, *out_blob;
char channel_key[CIFS_KEY_SIZE] = {};
- char *auth_key = conn->binding ? channel_key : sess->sess_key;
+ char reauth_key[CIFS_KEY_SIZE] = {};
+ char *auth_key = conn->binding ? channel_key :
+ (work->session_setup_reauth ? reauth_key : sess->sess_key);
u64 prev_sess_id;
bool binding = conn->binding;
int in_len, out_len;
@@ -2101,7 +2161,7 @@ static int krb5_authenticate(struct ksmbd_work *work,
if (retval) {
ksmbd_debug(SMB, "krb5 authentication failed\n");
if (retval != -EKEYREJECTED)
- retval = -EINVAL;
+ retval = -EPERM;
goto out;
}
@@ -2117,12 +2177,21 @@ static int krb5_authenticate(struct ksmbd_work *work,
* that it is reauthentication. And the user/password
* has been verified, so return it here.
*/
- if (sess->state == SMB2_SESSION_VALID) {
+ if (sess->state == SMB2_SESSION_VALID && !work->session_setup_reauth) {
if (conn->binding)
goto binding_session;
return 0;
}
+ /*
+ * Reauthentication verifies the new Kerberos credentials but keeps
+ * the established SMB session keys.
+ */
+ if (work->session_setup_reauth) {
+ retval = 0;
+ goto out;
+ }
+
if ((rsp->SessionFlags != SMB2_SESSION_FLAG_IS_GUEST_LE &&
(conn->sign || server_conf.enforced_signing)) ||
(req->SecurityMode & SMB2_NEGOTIATE_SIGNING_REQUIRED))
@@ -2160,6 +2229,7 @@ binding_session:
}
retval = 0;
out:
+ memzero_explicit(reauth_key, sizeof(reauth_key));
if (binding)
memzero_explicit(channel_key, sizeof(channel_key));
return retval;
@@ -2318,8 +2388,13 @@ int smb2_sess_setup(struct ksmbd_work *work)
}
if (sess->state == SMB2_SESSION_EXPIRED) {
- rc = -EFAULT;
- goto out_err;
+ if (sess->kerberos_expiry &&
+ ktime_get_real_seconds() >= sess->kerberos_expiry) {
+ work->session_setup_reauth = true;
+ } else {
+ rc = -EFAULT;
+ goto out_err;
+ }
}
if (ksmbd_conn_need_reconnect(conn)) {
@@ -2363,10 +2438,8 @@ int smb2_sess_setup(struct ksmbd_work *work)
if (conn->preferred_auth_mech &
(KSMBD_AUTH_KRB5 | KSMBD_AUTH_MSKRB5)) {
rc = krb5_authenticate(work, req, rsp);
- if (rc) {
- rc = -EINVAL;
+ if (rc)
goto out_err;
- }
if (!ksmbd_conn_need_reconnect(conn)) {
ksmbd_conn_set_good(conn);
@@ -2477,6 +2550,7 @@ out_err:
*/
if (!(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) {
sess->last_active = jiffies;
+ sess->kerberos_expiry = 0;
sess->state = SMB2_SESSION_EXPIRED;
}
/*
@@ -2824,6 +2898,7 @@ int smb2_session_logoff(struct ksmbd_work *work)
}
down_write(&conn->session_lock);
+ sess->kerberos_expiry = 0;
sess->state = SMB2_SESSION_EXPIRED;
up_write(&conn->session_lock);
@@ -7404,7 +7479,6 @@ int smb2_close(struct ksmbd_work *work)
u64 sess_id;
struct smb2_close_req *req;
struct smb2_close_rsp *rsp;
- struct ksmbd_conn *conn = work->conn;
struct ksmbd_file *fp;
u64 time;
int err = 0;
@@ -7427,7 +7501,7 @@ int smb2_close(struct ksmbd_work *work)
sess_id = work->compound_sid;
work->compound_sid = 0;
- if (check_session_id(conn, sess_id)) {
+ if (work->sess && work->sess->id == sess_id) {
work->compound_sid = sess_id;
} else {
rsp->hdr.Status = STATUS_USER_SESSION_DELETED;
@@ -8914,6 +8988,7 @@ int smb2_cancel(struct ksmbd_work *work)
struct smb2_hdr *hdr = smb_get_msg(work->request_buf);
struct smb2_hdr *chdr;
struct ksmbd_work *iter;
+ struct ksmbd_work *cancelled_notify = NULL;
struct list_head *command_list;
if (work->next_smb2_rcv_hdr_off)
@@ -8951,11 +9026,23 @@ int smb2_cancel(struct ksmbd_work *work)
le64_to_cpu(hdr->Id.AsyncId),
le16_to_cpu(chdr->Command));
iter->state = KSMBD_WORK_CANCELLED;
- if (iter->cancel_fn)
+ if (iter->cancel_fn == smb2_notify_cancel_fn)
+ cancelled_notify =
+ smb2_notify_cancel_claim(iter->cancel_argv);
+ else if (iter->cancel_fn)
iter->cancel_fn(iter->cancel_argv);
break;
}
spin_unlock(&conn->request_lock);
+
+ /*
+ * Complete a cancelled notify before this CANCEL handler returns.
+ * Deferring it to the system workqueue lets a following request and
+ * its response overtake STATUS_CANCELLED, leaving clients waiting
+ * for the original notify even though the cancellation was accepted.
+ */
+ if (cancelled_notify)
+ smb2_complete_notify_cancel(cancelled_notify);
} else {
command_list = &conn->requests;
@@ -10905,37 +10992,54 @@ int smb2_oplock_break(struct ksmbd_work *work)
* it from here would self-deadlock the very thread processing the
* client's CANCEL command. ksmbd_conn_write() can also sleep (it takes
* conn's write mutex). So: do only the non-sleeping, no-relock cleanup
- * inline here (the async_requests removal itself is safe without
- * re-locking, since the caller already holds that lock), and defer the
- * actual response send + work-struct free to a workqueue, matching the
- * minimal, non-blocking style of the existing smb2_remove_blocked_lock()
- * cancel_fn (which only wakes a waiter, never sends network data itself).
+ * inline here. smb2_cancel() sends and frees the claimed notify after it
+ * drops request_lock, preserving response order for a client CANCEL. The
+ * connection teardown caller has no such post-unlock path, so its wrapper
+ * defers the send and free to a workqueue.
*/
struct notify_cancel_ctx {
struct work_struct work;
struct ksmbd_work *in_work;
};
+static void smb2_send_notify_cancelled(struct ksmbd_work *work)
+{
+ struct smb2_hdr *hdr = smb_get_msg(work->response_buf);
+ struct ksmbd_conn *conn = work->conn;
+ struct ksmbd_session *sess;
+
+ sess = ksmbd_session_lookup(conn, le64_to_cpu(hdr->SessionId));
+ if (sess) {
+ work->sess = sess;
+ if (work->encrypted && sess->enc && conn->ops->encrypt_resp) {
+ conn->ops->encrypt_resp(work);
+ } else if (conn->ops->is_sign_req && conn->ops->set_sign_rsp &&
+ conn->ops->is_sign_req(work,
+ conn->ops->get_cmd_val(work))) {
+ conn->ops->set_sign_rsp(work);
+ }
+ }
+
+ ksmbd_conn_write(work);
+ if (sess) {
+ ksmbd_user_session_put(sess);
+ work->sess = NULL;
+ }
+}
+
static void smb2_notify_cancel_deferred(struct work_struct *w)
{
struct notify_cancel_ctx *ctx =
container_of(w, struct notify_cancel_ctx, work);
- struct ksmbd_work *in_work = ctx->in_work;
- struct smb2_hdr *in_hdr;
- in_hdr = smb_get_msg(in_work->response_buf);
- in_hdr->Status = STATUS_CANCELLED;
- ksmbd_conn_write(in_work);
- ksmbd_free_work_struct(in_work);
+ smb2_complete_notify_cancel(ctx->in_work);
kfree(ctx);
}
-static void smb2_notify_cancel_fn(void **argv)
+static struct ksmbd_work *smb2_notify_cancel_claim(void **argv)
{
struct ksmbd_work *in_work = (struct ksmbd_work *)argv[0];
struct ksmbd_file *fp = (struct ksmbd_file *)argv[1];
- struct ksmbd_conn *conn = in_work->conn;
- struct notify_cancel_ctx *ctx;
bool claimed;
spin_lock(&fp->f_lock);
@@ -10945,22 +11049,44 @@ static void smb2_notify_cancel_fn(void **argv)
spin_unlock(&fp->f_lock);
if (!claimed)
- return;
+ return NULL;
- /* conn->request_lock is already held by the caller (smb2_cancel()). */
- list_del_init(&in_work->async_request_entry);
- in_work->asynchronous = false;
+ /* conn->request_lock is held by smb2_cancel() or connection teardown. */
in_work->cancel_fn = NULL;
kfree(in_work->cancel_argv);
in_work->cancel_argv = NULL;
- if (in_work->async_id) {
- ksmbd_release_id(&conn->async_ida, in_work->async_id);
- in_work->async_id = 0;
- }
+ return in_work;
+}
+
+static void smb2_complete_notify_cancel(struct ksmbd_work *in_work)
+{
+ struct smb2_hdr *in_hdr = smb_get_msg(in_work->response_buf);
+
+ in_hdr->Status = STATUS_CANCELLED;
+ smb2_send_notify_cancelled(in_work);
+ release_async_work(in_work);
+ ksmbd_free_work_struct(in_work);
+}
+
+static void smb2_notify_cancel_fn(void **argv)
+{
+ struct ksmbd_work *in_work = smb2_notify_cancel_claim(argv);
+ struct ksmbd_conn *conn;
+ struct notify_cancel_ctx *ctx;
+
+ if (!in_work)
+ return;
+ conn = in_work->conn;
ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC);
if (!ctx) {
/* Can't defer the response -- free without sending one. */
+ list_del_init(&in_work->async_request_entry);
+ in_work->asynchronous = false;
+ if (in_work->async_id) {
+ ksmbd_release_id(&conn->async_ida, in_work->async_id);
+ in_work->async_id = 0;
+ }
ksmbd_free_work_struct(in_work);
return;
}
@@ -11081,6 +11207,8 @@ int smb2_notify(struct ksmbd_work *work)
smb2_set_err_rsp(work);
return 0;
}
+ memcpy(smb_get_msg(in_work->request_buf), req,
+ __SMB2_HEADER_STRUCTURE_SIZE);
if (setup_async_work(work, NULL, NULL)) {
ksmbd_free_work_struct(in_work);
@@ -11095,6 +11223,7 @@ int smb2_notify(struct ksmbd_work *work)
/* Keep the async IDA alive until the deferred work is released. */
in_work->conn = ksmbd_conn_get(work->conn);
in_work->owns_conn_ref = true;
+ in_work->encrypted = work->encrypted;
in_hdr = smb_get_msg(in_work->response_buf);
memcpy(in_hdr, ksmbd_resp_buf_next(work), __SMB2_HEADER_STRUCTURE_SIZE);
in_hdr->Flags |= SMB2_FLAGS_ASYNC_COMMAND;
@@ -11460,7 +11589,6 @@ bool smb3_is_transform_hdr(void *buf)
int smb3_decrypt_req(struct ksmbd_work *work)
{
- struct ksmbd_session *sess;
char *buf = work->request_buf;
unsigned int pdu_length = get_rfc1002_len(buf);
struct kvec iov[2];
@@ -11480,14 +11608,6 @@ int smb3_decrypt_req(struct ksmbd_work *work)
return -ECONNABORTED;
}
- sess = ksmbd_session_lookup_all(work->conn, le64_to_cpu(tr_hdr->SessionId));
- if (!sess) {
- pr_err("invalid session id(%llx) in transform header\n",
- le64_to_cpu(tr_hdr->SessionId));
- return -ECONNABORTED;
- }
- ksmbd_user_session_put(sess);
-
iov[0].iov_base = buf;
iov[0].iov_len = sizeof(struct smb2_transform_hdr) + 4;
iov[1].iov_base = buf + sizeof(struct smb2_transform_hdr) + 4;