Commit 2e1e1337 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag '6.4-rc-ksmbd-server-fixes-part2' of git://git.samba.org/ksmbd

Pull ksmbd server fixes from Steve French:
 "Ten ksmbd server fixes, including some important security fixes:

   - Two use after free fixes

   - Fix RCU callback race

   - Deadlock fix

   - Three patches to prevent session setup attacks

   - Prevent guest users from establishing multichannel sessions

   - Fix null pointer dereference in query FS info

   - Memleak fix"

* tag '6.4-rc-ksmbd-server-fixes-part2' of git://git.samba.org/ksmbd:
  ksmbd: call rcu_barrier() in ksmbd_server_exit()
  ksmbd: fix racy issue under cocurrent smb2 tree disconnect
  ksmbd: fix racy issue from smb2 close and logoff with multichannel
  ksmbd: not allow guest user on multichannel
  ksmbd: fix deadlock in ksmbd_find_crypto_ctx()
  ksmbd: block asynchronous requests when making a delay on session setup
  ksmbd: destroy expired sessions
  ksmbd: fix racy issue from session setup and logoff
  ksmbd: fix NULL pointer dereference in smb2_get_info_filesystem()
  ksmbd: fix memleak in session setup
parents ed23734c eb307d09
...@@ -221,22 +221,22 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess, ...@@ -221,22 +221,22 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
{ {
char ntlmv2_hash[CIFS_ENCPWD_SIZE]; char ntlmv2_hash[CIFS_ENCPWD_SIZE];
char ntlmv2_rsp[CIFS_HMAC_MD5_HASH_SIZE]; char ntlmv2_rsp[CIFS_HMAC_MD5_HASH_SIZE];
struct ksmbd_crypto_ctx *ctx; struct ksmbd_crypto_ctx *ctx = NULL;
char *construct = NULL; char *construct = NULL;
int rc, len; int rc, len;
ctx = ksmbd_crypto_ctx_find_hmacmd5();
if (!ctx) {
ksmbd_debug(AUTH, "could not crypto alloc hmacmd5\n");
return -ENOMEM;
}
rc = calc_ntlmv2_hash(conn, sess, ntlmv2_hash, domain_name); rc = calc_ntlmv2_hash(conn, sess, ntlmv2_hash, domain_name);
if (rc) { if (rc) {
ksmbd_debug(AUTH, "could not get v2 hash rc %d\n", rc); ksmbd_debug(AUTH, "could not get v2 hash rc %d\n", rc);
goto out; goto out;
} }
ctx = ksmbd_crypto_ctx_find_hmacmd5();
if (!ctx) {
ksmbd_debug(AUTH, "could not crypto alloc hmacmd5\n");
return -ENOMEM;
}
rc = crypto_shash_setkey(CRYPTO_HMACMD5_TFM(ctx), rc = crypto_shash_setkey(CRYPTO_HMACMD5_TFM(ctx),
ntlmv2_hash, ntlmv2_hash,
CIFS_HMAC_MD5_HASH_SIZE); CIFS_HMAC_MD5_HASH_SIZE);
...@@ -272,6 +272,8 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess, ...@@ -272,6 +272,8 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
ksmbd_debug(AUTH, "Could not generate md5 hash\n"); ksmbd_debug(AUTH, "Could not generate md5 hash\n");
goto out; goto out;
} }
ksmbd_release_crypto_ctx(ctx);
ctx = NULL;
rc = ksmbd_gen_sess_key(sess, ntlmv2_hash, ntlmv2_rsp); rc = ksmbd_gen_sess_key(sess, ntlmv2_hash, ntlmv2_rsp);
if (rc) { if (rc) {
...@@ -282,7 +284,8 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess, ...@@ -282,7 +284,8 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
if (memcmp(ntlmv2->ntlmv2_hash, ntlmv2_rsp, CIFS_HMAC_MD5_HASH_SIZE) != 0) if (memcmp(ntlmv2->ntlmv2_hash, ntlmv2_rsp, CIFS_HMAC_MD5_HASH_SIZE) != 0)
rc = -EINVAL; rc = -EINVAL;
out: out:
ksmbd_release_crypto_ctx(ctx); if (ctx)
ksmbd_release_crypto_ctx(ctx);
kfree(construct); kfree(construct);
return rc; return rc;
} }
......
...@@ -20,7 +20,7 @@ static DEFINE_MUTEX(init_lock); ...@@ -20,7 +20,7 @@ static DEFINE_MUTEX(init_lock);
static struct ksmbd_conn_ops default_conn_ops; static struct ksmbd_conn_ops default_conn_ops;
LIST_HEAD(conn_list); LIST_HEAD(conn_list);
DEFINE_RWLOCK(conn_list_lock); DECLARE_RWSEM(conn_list_lock);
/** /**
* ksmbd_conn_free() - free resources of the connection instance * ksmbd_conn_free() - free resources of the connection instance
...@@ -32,9 +32,9 @@ DEFINE_RWLOCK(conn_list_lock); ...@@ -32,9 +32,9 @@ DEFINE_RWLOCK(conn_list_lock);
*/ */
void ksmbd_conn_free(struct ksmbd_conn *conn) void ksmbd_conn_free(struct ksmbd_conn *conn)
{ {
write_lock(&conn_list_lock); down_write(&conn_list_lock);
list_del(&conn->conns_list); list_del(&conn->conns_list);
write_unlock(&conn_list_lock); up_write(&conn_list_lock);
xa_destroy(&conn->sessions); xa_destroy(&conn->sessions);
kvfree(conn->request_buf); kvfree(conn->request_buf);
...@@ -56,7 +56,7 @@ struct ksmbd_conn *ksmbd_conn_alloc(void) ...@@ -56,7 +56,7 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
return NULL; return NULL;
conn->need_neg = true; conn->need_neg = true;
conn->status = KSMBD_SESS_NEW; ksmbd_conn_set_new(conn);
conn->local_nls = load_nls("utf8"); conn->local_nls = load_nls("utf8");
if (!conn->local_nls) if (!conn->local_nls)
conn->local_nls = load_nls_default(); conn->local_nls = load_nls_default();
...@@ -84,9 +84,9 @@ struct ksmbd_conn *ksmbd_conn_alloc(void) ...@@ -84,9 +84,9 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
spin_lock_init(&conn->llist_lock); spin_lock_init(&conn->llist_lock);
INIT_LIST_HEAD(&conn->lock_list); INIT_LIST_HEAD(&conn->lock_list);
write_lock(&conn_list_lock); down_write(&conn_list_lock);
list_add(&conn->conns_list, &conn_list); list_add(&conn->conns_list, &conn_list);
write_unlock(&conn_list_lock); up_write(&conn_list_lock);
return conn; return conn;
} }
...@@ -95,7 +95,7 @@ bool ksmbd_conn_lookup_dialect(struct ksmbd_conn *c) ...@@ -95,7 +95,7 @@ bool ksmbd_conn_lookup_dialect(struct ksmbd_conn *c)
struct ksmbd_conn *t; struct ksmbd_conn *t;
bool ret = false; bool ret = false;
read_lock(&conn_list_lock); down_read(&conn_list_lock);
list_for_each_entry(t, &conn_list, conns_list) { list_for_each_entry(t, &conn_list, conns_list) {
if (memcmp(t->ClientGUID, c->ClientGUID, SMB2_CLIENT_GUID_SIZE)) if (memcmp(t->ClientGUID, c->ClientGUID, SMB2_CLIENT_GUID_SIZE))
continue; continue;
...@@ -103,7 +103,7 @@ bool ksmbd_conn_lookup_dialect(struct ksmbd_conn *c) ...@@ -103,7 +103,7 @@ bool ksmbd_conn_lookup_dialect(struct ksmbd_conn *c)
ret = true; ret = true;
break; break;
} }
read_unlock(&conn_list_lock); up_read(&conn_list_lock);
return ret; return ret;
} }
...@@ -147,19 +147,47 @@ int ksmbd_conn_try_dequeue_request(struct ksmbd_work *work) ...@@ -147,19 +147,47 @@ int ksmbd_conn_try_dequeue_request(struct ksmbd_work *work)
return ret; return ret;
} }
static void ksmbd_conn_lock(struct ksmbd_conn *conn) void ksmbd_conn_lock(struct ksmbd_conn *conn)
{ {
mutex_lock(&conn->srv_mutex); 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); 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)
{
struct ksmbd_conn *bind_conn;
wait_event(conn->req_running_q, atomic_read(&conn->req_running) < 2); wait_event(conn->req_running_q, atomic_read(&conn->req_running) < 2);
down_read(&conn_list_lock);
list_for_each_entry(bind_conn, &conn_list, conns_list) {
if (bind_conn == conn)
continue;
if ((bind_conn->binding || xa_load(&bind_conn->sessions, sess_id)) &&
!ksmbd_conn_releasing(bind_conn) &&
atomic_read(&bind_conn->req_running)) {
wait_event(bind_conn->req_running_q,
atomic_read(&bind_conn->req_running) == 0);
}
}
up_read(&conn_list_lock);
} }
int ksmbd_conn_write(struct ksmbd_work *work) int ksmbd_conn_write(struct ksmbd_work *work)
...@@ -243,7 +271,7 @@ bool ksmbd_conn_alive(struct ksmbd_conn *conn) ...@@ -243,7 +271,7 @@ bool ksmbd_conn_alive(struct ksmbd_conn *conn)
if (!ksmbd_server_running()) if (!ksmbd_server_running())
return false; return false;
if (conn->status == KSMBD_SESS_EXITING) if (ksmbd_conn_exiting(conn))
return false; return false;
if (kthread_should_stop()) if (kthread_should_stop())
...@@ -303,7 +331,7 @@ int ksmbd_conn_handler_loop(void *p) ...@@ -303,7 +331,7 @@ int ksmbd_conn_handler_loop(void *p)
pdu_size = get_rfc1002_len(hdr_buf); pdu_size = get_rfc1002_len(hdr_buf);
ksmbd_debug(CONN, "RFC1002 header %u bytes\n", pdu_size); 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 = max_allowed_pdu_size =
SMB3_MAX_MSGSIZE + conn->vals->max_write_size; SMB3_MAX_MSGSIZE + conn->vals->max_write_size;
else else
...@@ -312,7 +340,7 @@ int ksmbd_conn_handler_loop(void *p) ...@@ -312,7 +340,7 @@ int ksmbd_conn_handler_loop(void *p)
if (pdu_size > max_allowed_pdu_size) { if (pdu_size > max_allowed_pdu_size) {
pr_err_ratelimited("PDU length(%u) exceeded 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, pdu_size, max_allowed_pdu_size,
conn->status); READ_ONCE(conn->status));
break; break;
} }
...@@ -360,10 +388,10 @@ int ksmbd_conn_handler_loop(void *p) ...@@ -360,10 +388,10 @@ int ksmbd_conn_handler_loop(void *p)
} }
out: out:
ksmbd_conn_set_releasing(conn);
/* Wait till all reference dropped to the Server object*/ /* Wait till all reference dropped to the Server object*/
wait_event(conn->r_count_q, atomic_read(&conn->r_count) == 0); wait_event(conn->r_count_q, atomic_read(&conn->r_count) == 0);
if (IS_ENABLED(CONFIG_UNICODE)) if (IS_ENABLED(CONFIG_UNICODE))
utf8_unload(conn->um); utf8_unload(conn->um);
unload_nls(conn->local_nls); unload_nls(conn->local_nls);
...@@ -407,7 +435,7 @@ static void stop_sessions(void) ...@@ -407,7 +435,7 @@ static void stop_sessions(void)
struct ksmbd_transport *t; struct ksmbd_transport *t;
again: again:
read_lock(&conn_list_lock); down_read(&conn_list_lock);
list_for_each_entry(conn, &conn_list, conns_list) { list_for_each_entry(conn, &conn_list, conns_list) {
struct task_struct *task; struct task_struct *task;
...@@ -416,14 +444,14 @@ static void stop_sessions(void) ...@@ -416,14 +444,14 @@ static void stop_sessions(void)
if (task) if (task)
ksmbd_debug(CONN, "Stop session handler %s/%d\n", ksmbd_debug(CONN, "Stop session handler %s/%d\n",
task->comm, task_pid_nr(task)); task->comm, task_pid_nr(task));
conn->status = KSMBD_SESS_EXITING; ksmbd_conn_set_exiting(conn);
if (t->ops->shutdown) { if (t->ops->shutdown) {
read_unlock(&conn_list_lock); up_read(&conn_list_lock);
t->ops->shutdown(t); t->ops->shutdown(t);
read_lock(&conn_list_lock); down_read(&conn_list_lock);
} }
} }
read_unlock(&conn_list_lock); up_read(&conn_list_lock);
if (!list_empty(&conn_list)) { if (!list_empty(&conn_list)) {
schedule_timeout_interruptible(HZ / 10); /* 100ms */ schedule_timeout_interruptible(HZ / 10); /* 100ms */
......
...@@ -26,7 +26,8 @@ enum { ...@@ -26,7 +26,8 @@ enum {
KSMBD_SESS_GOOD, KSMBD_SESS_GOOD,
KSMBD_SESS_EXITING, KSMBD_SESS_EXITING,
KSMBD_SESS_NEED_RECONNECT, KSMBD_SESS_NEED_RECONNECT,
KSMBD_SESS_NEED_NEGOTIATE KSMBD_SESS_NEED_NEGOTIATE,
KSMBD_SESS_RELEASING
}; };
struct ksmbd_stats { struct ksmbd_stats {
...@@ -140,10 +141,10 @@ struct ksmbd_transport { ...@@ -140,10 +141,10 @@ struct ksmbd_transport {
#define KSMBD_TCP_PEER_SOCKADDR(c) ((struct sockaddr *)&((c)->peer_addr)) #define KSMBD_TCP_PEER_SOCKADDR(c) ((struct sockaddr *)&((c)->peer_addr))
extern struct list_head conn_list; 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); 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); struct ksmbd_conn *ksmbd_conn_alloc(void);
void ksmbd_conn_free(struct ksmbd_conn *conn); void ksmbd_conn_free(struct ksmbd_conn *conn);
bool ksmbd_conn_lookup_dialect(struct ksmbd_conn *c); bool ksmbd_conn_lookup_dialect(struct ksmbd_conn *c);
...@@ -162,6 +163,8 @@ void ksmbd_conn_init_server_callbacks(struct ksmbd_conn_ops *ops); ...@@ -162,6 +163,8 @@ void ksmbd_conn_init_server_callbacks(struct ksmbd_conn_ops *ops);
int ksmbd_conn_handler_loop(void *p); int ksmbd_conn_handler_loop(void *p);
int ksmbd_conn_transport_init(void); int ksmbd_conn_transport_init(void);
void ksmbd_conn_transport_destroy(void); void ksmbd_conn_transport_destroy(void);
void ksmbd_conn_lock(struct ksmbd_conn *conn);
void ksmbd_conn_unlock(struct ksmbd_conn *conn);
/* /*
* WARNING * WARNING
...@@ -169,43 +172,60 @@ void ksmbd_conn_transport_destroy(void); ...@@ -169,43 +172,60 @@ void ksmbd_conn_transport_destroy(void);
* This is a hack. We will move status to a proper place once we land * This is a hack. We will move status to a proper place once we land
* a multi-sessions support. * 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__ */ #endif /* __CONNECTION_H__ */
...@@ -109,7 +109,15 @@ int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess, ...@@ -109,7 +109,15 @@ int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess,
struct ksmbd_tree_connect *ksmbd_tree_conn_lookup(struct ksmbd_session *sess, struct ksmbd_tree_connect *ksmbd_tree_conn_lookup(struct ksmbd_session *sess,
unsigned int id) unsigned int id)
{ {
return xa_load(&sess->tree_conns, id); struct ksmbd_tree_connect *tcon;
tcon = xa_load(&sess->tree_conns, id);
if (tcon) {
if (test_bit(TREE_CONN_EXPIRE, &tcon->status))
tcon = NULL;
}
return tcon;
} }
struct ksmbd_share_config *ksmbd_tree_conn_share(struct ksmbd_session *sess, struct ksmbd_share_config *ksmbd_tree_conn_share(struct ksmbd_session *sess,
...@@ -129,6 +137,9 @@ int ksmbd_tree_conn_session_logoff(struct ksmbd_session *sess) ...@@ -129,6 +137,9 @@ int ksmbd_tree_conn_session_logoff(struct ksmbd_session *sess)
struct ksmbd_tree_connect *tc; struct ksmbd_tree_connect *tc;
unsigned long id; unsigned long id;
if (!sess)
return -EINVAL;
xa_for_each(&sess->tree_conns, id, tc) xa_for_each(&sess->tree_conns, id, tc)
ret |= ksmbd_tree_conn_disconnect(sess, tc); ret |= ksmbd_tree_conn_disconnect(sess, tc);
xa_destroy(&sess->tree_conns); xa_destroy(&sess->tree_conns);
......
...@@ -14,6 +14,8 @@ struct ksmbd_share_config; ...@@ -14,6 +14,8 @@ struct ksmbd_share_config;
struct ksmbd_user; struct ksmbd_user;
struct ksmbd_conn; struct ksmbd_conn;
#define TREE_CONN_EXPIRE 1
struct ksmbd_tree_connect { struct ksmbd_tree_connect {
int id; int id;
...@@ -25,6 +27,7 @@ struct ksmbd_tree_connect { ...@@ -25,6 +27,7 @@ struct ksmbd_tree_connect {
int maximal_access; int maximal_access;
bool posix_extensions; bool posix_extensions;
unsigned long status;
}; };
struct ksmbd_tree_conn_status { struct ksmbd_tree_conn_status {
......
...@@ -144,10 +144,6 @@ void ksmbd_session_destroy(struct ksmbd_session *sess) ...@@ -144,10 +144,6 @@ void ksmbd_session_destroy(struct ksmbd_session *sess)
if (!sess) if (!sess)
return; return;
down_write(&sessions_table_lock);
hash_del(&sess->hlist);
up_write(&sessions_table_lock);
if (sess->user) if (sess->user)
ksmbd_free_user(sess->user); ksmbd_free_user(sess->user);
...@@ -165,17 +161,39 @@ static struct ksmbd_session *__session_lookup(unsigned long long id) ...@@ -165,17 +161,39 @@ static struct ksmbd_session *__session_lookup(unsigned long long id)
struct ksmbd_session *sess; struct ksmbd_session *sess;
hash_for_each_possible(sessions_table, sess, hlist, id) { hash_for_each_possible(sessions_table, sess, hlist, id) {
if (id == sess->id) if (id == sess->id) {
sess->last_active = jiffies;
return sess; return sess;
}
} }
return NULL; return NULL;
} }
static void ksmbd_expire_session(struct ksmbd_conn *conn)
{
unsigned long id;
struct ksmbd_session *sess;
down_write(&sessions_table_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(&sessions_table_lock);
}
int ksmbd_session_register(struct ksmbd_conn *conn, int ksmbd_session_register(struct ksmbd_conn *conn,
struct ksmbd_session *sess) struct ksmbd_session *sess)
{ {
sess->dialect = conn->dialect; sess->dialect = conn->dialect;
memcpy(sess->ClientGUID, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE); 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)); return xa_err(xa_store(&conn->sessions, sess->id, sess, GFP_KERNEL));
} }
...@@ -188,47 +206,56 @@ static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess) ...@@ -188,47 +206,56 @@ static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess)
return -ENOENT; return -ENOENT;
kfree(chann); kfree(chann);
return 0; return 0;
} }
void ksmbd_sessions_deregister(struct ksmbd_conn *conn) void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
{ {
struct ksmbd_session *sess; struct ksmbd_session *sess;
unsigned long id;
down_write(&sessions_table_lock);
if (conn->binding) { if (conn->binding) {
int bkt; int bkt;
struct hlist_node *tmp;
down_write(&sessions_table_lock); hash_for_each_safe(sessions_table, bkt, tmp, sess, hlist) {
hash_for_each(sessions_table, bkt, sess, hlist) { if (!ksmbd_chann_del(conn, sess) &&
if (!ksmbd_chann_del(conn, sess)) { xa_empty(&sess->ksmbd_chann_list)) {
up_write(&sessions_table_lock); hash_del(&sess->hlist);
goto sess_destroy; ksmbd_session_destroy(sess);
} }
} }
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; 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);
}
sess_destroy: ksmbd_chann_del(conn, sess);
if (xa_empty(&sess->ksmbd_chann_list)) { if (xa_empty(&sess->ksmbd_chann_list)) {
xa_erase(&conn->sessions, sess->id); xa_erase(&conn->sessions, sess->id);
ksmbd_session_destroy(sess); hash_del(&sess->hlist);
ksmbd_session_destroy(sess);
}
} }
up_write(&sessions_table_lock);
} }
struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn, struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
unsigned long long id) unsigned long long id)
{ {
return xa_load(&conn->sessions, id); struct ksmbd_session *sess;
sess = xa_load(&conn->sessions, id);
if (sess)
sess->last_active = jiffies;
return sess;
} }
struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id) struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id)
...@@ -237,6 +264,8 @@ struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id) ...@@ -237,6 +264,8 @@ struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id)
down_read(&sessions_table_lock); down_read(&sessions_table_lock);
sess = __session_lookup(id); sess = __session_lookup(id);
if (sess)
sess->last_active = jiffies;
up_read(&sessions_table_lock); up_read(&sessions_table_lock);
return sess; return sess;
...@@ -315,6 +344,8 @@ static struct ksmbd_session *__session_create(int protocol) ...@@ -315,6 +344,8 @@ static struct ksmbd_session *__session_create(int protocol)
if (ksmbd_init_file_table(&sess->file_table)) if (ksmbd_init_file_table(&sess->file_table))
goto error; goto error;
sess->last_active = jiffies;
sess->state = SMB2_SESSION_IN_PROGRESS;
set_session_flag(sess, protocol); set_session_flag(sess, protocol);
xa_init(&sess->tree_conns); xa_init(&sess->tree_conns);
xa_init(&sess->ksmbd_chann_list); xa_init(&sess->ksmbd_chann_list);
......
...@@ -59,6 +59,7 @@ struct ksmbd_session { ...@@ -59,6 +59,7 @@ struct ksmbd_session {
__u8 smb3signingkey[SMB3_SIGN_KEY_SIZE]; __u8 smb3signingkey[SMB3_SIGN_KEY_SIZE];
struct ksmbd_file_table file_table; struct ksmbd_file_table file_table;
unsigned long last_active;
}; };
static inline int test_session_flag(struct ksmbd_session *sess, int bit) static inline int test_session_flag(struct ksmbd_session *sess, int bit)
......
...@@ -93,7 +93,8 @@ static inline int check_conn_state(struct ksmbd_work *work) ...@@ -93,7 +93,8 @@ static inline int check_conn_state(struct ksmbd_work *work)
{ {
struct smb_hdr *rsp_hdr; 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 = work->response_buf;
rsp_hdr->Status.CifsError = STATUS_CONNECTION_DISCONNECTED; rsp_hdr->Status.CifsError = STATUS_CONNECTION_DISCONNECTED;
return 1; return 1;
...@@ -605,6 +606,7 @@ static int __init ksmbd_server_init(void) ...@@ -605,6 +606,7 @@ static int __init ksmbd_server_init(void)
static void __exit ksmbd_server_exit(void) static void __exit ksmbd_server_exit(void)
{ {
ksmbd_server_shutdown(); ksmbd_server_shutdown();
rcu_barrier();
ksmbd_release_inode_hash(); ksmbd_release_inode_hash();
} }
......
...@@ -248,7 +248,7 @@ int init_smb2_neg_rsp(struct ksmbd_work *work) ...@@ -248,7 +248,7 @@ int init_smb2_neg_rsp(struct ksmbd_work *work)
rsp = smb2_get_msg(work->response_buf); rsp = smb2_get_msg(work->response_buf);
WARN_ON(ksmbd_conn_good(work)); WARN_ON(ksmbd_conn_good(conn));
rsp->StructureSize = cpu_to_le16(65); rsp->StructureSize = cpu_to_le16(65);
ksmbd_debug(SMB, "conn->dialect 0x%x\n", conn->dialect); ksmbd_debug(SMB, "conn->dialect 0x%x\n", conn->dialect);
...@@ -277,7 +277,7 @@ int init_smb2_neg_rsp(struct ksmbd_work *work) ...@@ -277,7 +277,7 @@ int init_smb2_neg_rsp(struct ksmbd_work *work)
rsp->SecurityMode |= SMB2_NEGOTIATE_SIGNING_REQUIRED_LE; rsp->SecurityMode |= SMB2_NEGOTIATE_SIGNING_REQUIRED_LE;
conn->use_spnego = true; conn->use_spnego = true;
ksmbd_conn_set_need_negotiate(work); ksmbd_conn_set_need_negotiate(conn);
return 0; return 0;
} }
...@@ -561,7 +561,7 @@ int smb2_check_user_session(struct ksmbd_work *work) ...@@ -561,7 +561,7 @@ int smb2_check_user_session(struct ksmbd_work *work)
cmd == SMB2_SESSION_SETUP_HE) cmd == SMB2_SESSION_SETUP_HE)
return 0; return 0;
if (!ksmbd_conn_good(work)) if (!ksmbd_conn_good(conn))
return -EINVAL; return -EINVAL;
sess_id = le64_to_cpu(req_hdr->SessionId); sess_id = le64_to_cpu(req_hdr->SessionId);
...@@ -594,7 +594,7 @@ static void destroy_previous_session(struct ksmbd_conn *conn, ...@@ -594,7 +594,7 @@ static void destroy_previous_session(struct ksmbd_conn *conn,
prev_sess->state = SMB2_SESSION_EXPIRED; prev_sess->state = SMB2_SESSION_EXPIRED;
xa_for_each(&prev_sess->ksmbd_chann_list, index, chann) xa_for_each(&prev_sess->ksmbd_chann_list, index, chann)
chann->conn->status = KSMBD_SESS_EXITING; ksmbd_conn_set_exiting(chann->conn);
} }
/** /**
...@@ -1051,7 +1051,7 @@ int smb2_handle_negotiate(struct ksmbd_work *work) ...@@ -1051,7 +1051,7 @@ int smb2_handle_negotiate(struct ksmbd_work *work)
ksmbd_debug(SMB, "Received negotiate request\n"); ksmbd_debug(SMB, "Received negotiate request\n");
conn->need_neg = false; conn->need_neg = false;
if (ksmbd_conn_good(work)) { if (ksmbd_conn_good(conn)) {
pr_err("conn->tcp_status is already in CifsGood State\n"); pr_err("conn->tcp_status is already in CifsGood State\n");
work->send_no_response = 1; work->send_no_response = 1;
return rc; return rc;
...@@ -1205,7 +1205,7 @@ int smb2_handle_negotiate(struct ksmbd_work *work) ...@@ -1205,7 +1205,7 @@ int smb2_handle_negotiate(struct ksmbd_work *work)
} }
conn->srv_sec_mode = le16_to_cpu(rsp->SecurityMode); conn->srv_sec_mode = le16_to_cpu(rsp->SecurityMode);
ksmbd_conn_set_need_negotiate(work); ksmbd_conn_set_need_negotiate(conn);
err_out: err_out:
if (rc < 0) if (rc < 0)
...@@ -1431,7 +1431,7 @@ static int ntlm_authenticate(struct ksmbd_work *work) ...@@ -1431,7 +1431,7 @@ static int ntlm_authenticate(struct ksmbd_work *work)
* Reuse session if anonymous try to connect * Reuse session if anonymous try to connect
* on reauthetication. * on reauthetication.
*/ */
if (ksmbd_anonymous_user(user)) { if (conn->binding == false && ksmbd_anonymous_user(user)) {
ksmbd_free_user(user); ksmbd_free_user(user);
return 0; return 0;
} }
...@@ -1445,7 +1445,7 @@ static int ntlm_authenticate(struct ksmbd_work *work) ...@@ -1445,7 +1445,7 @@ static int ntlm_authenticate(struct ksmbd_work *work)
sess->user = user; sess->user = user;
} }
if (user_guest(sess->user)) { if (conn->binding == false && user_guest(sess->user)) {
rsp->SessionFlags = SMB2_SESSION_FLAG_IS_GUEST_LE; rsp->SessionFlags = SMB2_SESSION_FLAG_IS_GUEST_LE;
} else { } else {
struct authenticate_message *authblob; struct authenticate_message *authblob;
...@@ -1628,6 +1628,7 @@ int smb2_sess_setup(struct ksmbd_work *work) ...@@ -1628,6 +1628,7 @@ int smb2_sess_setup(struct ksmbd_work *work)
rsp->SecurityBufferLength = 0; rsp->SecurityBufferLength = 0;
inc_rfc1001_len(work->response_buf, 9); inc_rfc1001_len(work->response_buf, 9);
ksmbd_conn_lock(conn);
if (!req->hdr.SessionId) { if (!req->hdr.SessionId) {
sess = ksmbd_smb2_session_create(); sess = ksmbd_smb2_session_create();
if (!sess) { if (!sess) {
...@@ -1675,11 +1676,22 @@ int smb2_sess_setup(struct ksmbd_work *work) ...@@ -1675,11 +1676,22 @@ int smb2_sess_setup(struct ksmbd_work *work)
goto out_err; goto out_err;
} }
if (ksmbd_conn_need_reconnect(conn)) {
rc = -EFAULT;
sess = NULL;
goto out_err;
}
if (ksmbd_session_lookup(conn, sess_id)) { if (ksmbd_session_lookup(conn, sess_id)) {
rc = -EACCES; rc = -EACCES;
goto out_err; goto out_err;
} }
if (user_guest(sess->user)) {
rc = -EOPNOTSUPP;
goto out_err;
}
conn->binding = true; conn->binding = true;
} else if ((conn->dialect < SMB30_PROT_ID || } else if ((conn->dialect < SMB30_PROT_ID ||
server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) && server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) &&
...@@ -1694,12 +1706,20 @@ int smb2_sess_setup(struct ksmbd_work *work) ...@@ -1694,12 +1706,20 @@ int smb2_sess_setup(struct ksmbd_work *work)
rc = -ENOENT; rc = -ENOENT;
goto out_err; goto out_err;
} }
if (sess->state == SMB2_SESSION_EXPIRED) {
rc = -EFAULT;
goto out_err;
}
if (ksmbd_conn_need_reconnect(conn)) {
rc = -EFAULT;
sess = NULL;
goto out_err;
}
} }
work->sess = sess; work->sess = sess;
if (sess->state == SMB2_SESSION_EXPIRED)
sess->state = SMB2_SESSION_IN_PROGRESS;
negblob_off = le16_to_cpu(req->SecurityBufferOffset); negblob_off = le16_to_cpu(req->SecurityBufferOffset);
negblob_len = le16_to_cpu(req->SecurityBufferLength); negblob_len = le16_to_cpu(req->SecurityBufferLength);
if (negblob_off < offsetof(struct smb2_sess_setup_req, Buffer) || if (negblob_off < offsetof(struct smb2_sess_setup_req, Buffer) ||
...@@ -1729,8 +1749,10 @@ int smb2_sess_setup(struct ksmbd_work *work) ...@@ -1729,8 +1749,10 @@ int smb2_sess_setup(struct ksmbd_work *work)
goto out_err; goto out_err;
} }
ksmbd_conn_set_good(work); if (!ksmbd_conn_need_reconnect(conn)) {
sess->state = SMB2_SESSION_VALID; ksmbd_conn_set_good(conn);
sess->state = SMB2_SESSION_VALID;
}
kfree(sess->Preauth_HashValue); kfree(sess->Preauth_HashValue);
sess->Preauth_HashValue = NULL; sess->Preauth_HashValue = NULL;
} else if (conn->preferred_auth_mech == KSMBD_AUTH_NTLMSSP) { } else if (conn->preferred_auth_mech == KSMBD_AUTH_NTLMSSP) {
...@@ -1752,8 +1774,10 @@ int smb2_sess_setup(struct ksmbd_work *work) ...@@ -1752,8 +1774,10 @@ int smb2_sess_setup(struct ksmbd_work *work)
if (rc) if (rc)
goto out_err; goto out_err;
ksmbd_conn_set_good(work); if (!ksmbd_conn_need_reconnect(conn)) {
sess->state = SMB2_SESSION_VALID; ksmbd_conn_set_good(conn);
sess->state = SMB2_SESSION_VALID;
}
if (conn->binding) { if (conn->binding) {
struct preauth_session *preauth_sess; struct preauth_session *preauth_sess;
...@@ -1766,6 +1790,10 @@ int smb2_sess_setup(struct ksmbd_work *work) ...@@ -1766,6 +1790,10 @@ int smb2_sess_setup(struct ksmbd_work *work)
} }
kfree(sess->Preauth_HashValue); kfree(sess->Preauth_HashValue);
sess->Preauth_HashValue = NULL; sess->Preauth_HashValue = NULL;
} else {
pr_info_ratelimited("Unknown NTLMSSP message type : 0x%x\n",
le32_to_cpu(negblob->MessageType));
rc = -EINVAL;
} }
} else { } else {
/* TODO: need one more negotiation */ /* TODO: need one more negotiation */
...@@ -1788,6 +1816,8 @@ int smb2_sess_setup(struct ksmbd_work *work) ...@@ -1788,6 +1816,8 @@ int smb2_sess_setup(struct ksmbd_work *work)
rsp->hdr.Status = STATUS_NETWORK_SESSION_EXPIRED; rsp->hdr.Status = STATUS_NETWORK_SESSION_EXPIRED;
else if (rc == -ENOMEM) else if (rc == -ENOMEM)
rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES; rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;
else if (rc == -EOPNOTSUPP)
rsp->hdr.Status = STATUS_NOT_SUPPORTED;
else if (rc) else if (rc)
rsp->hdr.Status = STATUS_LOGON_FAILURE; rsp->hdr.Status = STATUS_LOGON_FAILURE;
...@@ -1815,14 +1845,17 @@ int smb2_sess_setup(struct ksmbd_work *work) ...@@ -1815,14 +1845,17 @@ int smb2_sess_setup(struct ksmbd_work *work)
if (sess->user && sess->user->flags & KSMBD_USER_FLAG_DELAY_SESSION) if (sess->user && sess->user->flags & KSMBD_USER_FLAG_DELAY_SESSION)
try_delay = true; try_delay = true;
xa_erase(&conn->sessions, sess->id); sess->last_active = jiffies;
ksmbd_session_destroy(sess); sess->state = SMB2_SESSION_EXPIRED;
work->sess = NULL; if (try_delay) {
if (try_delay) ksmbd_conn_set_need_reconnect(conn);
ssleep(5); ssleep(5);
ksmbd_conn_set_need_negotiate(conn);
}
} }
} }
ksmbd_conn_unlock(conn);
return rc; return rc;
} }
...@@ -2020,11 +2053,12 @@ int smb2_tree_disconnect(struct ksmbd_work *work) ...@@ -2020,11 +2053,12 @@ int smb2_tree_disconnect(struct ksmbd_work *work)
ksmbd_debug(SMB, "request\n"); ksmbd_debug(SMB, "request\n");
if (!tcon) { if (!tcon || test_and_set_bit(TREE_CONN_EXPIRE, &tcon->status)) {
struct smb2_tree_disconnect_req *req = struct smb2_tree_disconnect_req *req =
smb2_get_msg(work->request_buf); smb2_get_msg(work->request_buf);
ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId); ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId);
rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED; rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;
smb2_set_err_rsp(work); smb2_set_err_rsp(work);
return 0; return 0;
...@@ -2046,21 +2080,25 @@ int smb2_session_logoff(struct ksmbd_work *work) ...@@ -2046,21 +2080,25 @@ int smb2_session_logoff(struct ksmbd_work *work)
{ {
struct ksmbd_conn *conn = work->conn; struct ksmbd_conn *conn = work->conn;
struct smb2_logoff_rsp *rsp = smb2_get_msg(work->response_buf); struct smb2_logoff_rsp *rsp = smb2_get_msg(work->response_buf);
struct ksmbd_session *sess = work->sess; struct ksmbd_session *sess;
struct smb2_logoff_req *req = smb2_get_msg(work->request_buf);
u64 sess_id = le64_to_cpu(req->hdr.SessionId);
rsp->StructureSize = cpu_to_le16(4); rsp->StructureSize = cpu_to_le16(4);
inc_rfc1001_len(work->response_buf, 4); inc_rfc1001_len(work->response_buf, 4);
ksmbd_debug(SMB, "request\n"); ksmbd_debug(SMB, "request\n");
/* setting CifsExiting here may race with start_tcp_sess */ ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_RECONNECT);
ksmbd_conn_set_need_reconnect(work);
ksmbd_close_session_fds(work); ksmbd_close_session_fds(work);
ksmbd_conn_wait_idle(conn); ksmbd_conn_wait_idle(conn, sess_id);
/*
* Re-lookup session to validate if session is deleted
* while waiting request complete
*/
sess = ksmbd_session_lookup_all(conn, sess_id);
if (ksmbd_tree_conn_session_logoff(sess)) { if (ksmbd_tree_conn_session_logoff(sess)) {
struct smb2_logoff_req *req = smb2_get_msg(work->request_buf);
ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId); ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId);
rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED; rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;
smb2_set_err_rsp(work); smb2_set_err_rsp(work);
...@@ -2072,9 +2110,7 @@ int smb2_session_logoff(struct ksmbd_work *work) ...@@ -2072,9 +2110,7 @@ int smb2_session_logoff(struct ksmbd_work *work)
ksmbd_free_user(sess->user); ksmbd_free_user(sess->user);
sess->user = NULL; sess->user = NULL;
ksmbd_all_conn_set_status(sess_id, KSMBD_SESS_NEED_NEGOTIATE);
/* let start_tcp_sess free connection info now */
ksmbd_conn_set_need_negotiate(work);
return 0; return 0;
} }
...@@ -4881,6 +4917,9 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, ...@@ -4881,6 +4917,9 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
int rc = 0, len; int rc = 0, len;
int fs_infoclass_size = 0; int fs_infoclass_size = 0;
if (!share->path)
return -EIO;
rc = kern_path(share->path, LOOKUP_NO_SYMLINKS, &path); rc = kern_path(share->path, LOOKUP_NO_SYMLINKS, &path);
if (rc) { if (rc) {
pr_err("cannot create vfs path\n"); pr_err("cannot create vfs path\n");
...@@ -6826,7 +6865,7 @@ int smb2_lock(struct ksmbd_work *work) ...@@ -6826,7 +6865,7 @@ int smb2_lock(struct ksmbd_work *work)
nolock = 1; nolock = 1;
/* check locks in connection list */ /* check locks in connection list */
read_lock(&conn_list_lock); down_read(&conn_list_lock);
list_for_each_entry(conn, &conn_list, conns_list) { list_for_each_entry(conn, &conn_list, conns_list) {
spin_lock(&conn->llist_lock); spin_lock(&conn->llist_lock);
list_for_each_entry_safe(cmp_lock, tmp2, &conn->lock_list, clist) { list_for_each_entry_safe(cmp_lock, tmp2, &conn->lock_list, clist) {
...@@ -6843,7 +6882,7 @@ int smb2_lock(struct ksmbd_work *work) ...@@ -6843,7 +6882,7 @@ int smb2_lock(struct ksmbd_work *work)
list_del(&cmp_lock->flist); list_del(&cmp_lock->flist);
list_del(&cmp_lock->clist); list_del(&cmp_lock->clist);
spin_unlock(&conn->llist_lock); spin_unlock(&conn->llist_lock);
read_unlock(&conn_list_lock); up_read(&conn_list_lock);
locks_free_lock(cmp_lock->fl); locks_free_lock(cmp_lock->fl);
kfree(cmp_lock); kfree(cmp_lock);
...@@ -6865,7 +6904,7 @@ int smb2_lock(struct ksmbd_work *work) ...@@ -6865,7 +6904,7 @@ int smb2_lock(struct ksmbd_work *work)
cmp_lock->start > smb_lock->start && cmp_lock->start > smb_lock->start &&
cmp_lock->start < smb_lock->end) { cmp_lock->start < smb_lock->end) {
spin_unlock(&conn->llist_lock); spin_unlock(&conn->llist_lock);
read_unlock(&conn_list_lock); up_read(&conn_list_lock);
pr_err("previous lock conflict with zero byte lock range\n"); pr_err("previous lock conflict with zero byte lock range\n");
goto out; goto out;
} }
...@@ -6874,7 +6913,7 @@ int smb2_lock(struct ksmbd_work *work) ...@@ -6874,7 +6913,7 @@ int smb2_lock(struct ksmbd_work *work)
smb_lock->start > cmp_lock->start && smb_lock->start > cmp_lock->start &&
smb_lock->start < cmp_lock->end) { smb_lock->start < cmp_lock->end) {
spin_unlock(&conn->llist_lock); spin_unlock(&conn->llist_lock);
read_unlock(&conn_list_lock); up_read(&conn_list_lock);
pr_err("current lock conflict with zero byte lock range\n"); pr_err("current lock conflict with zero byte lock range\n");
goto out; goto out;
} }
...@@ -6885,14 +6924,14 @@ int smb2_lock(struct ksmbd_work *work) ...@@ -6885,14 +6924,14 @@ int smb2_lock(struct ksmbd_work *work)
cmp_lock->end >= smb_lock->end)) && cmp_lock->end >= smb_lock->end)) &&
!cmp_lock->zero_len && !smb_lock->zero_len) { !cmp_lock->zero_len && !smb_lock->zero_len) {
spin_unlock(&conn->llist_lock); spin_unlock(&conn->llist_lock);
read_unlock(&conn_list_lock); up_read(&conn_list_lock);
pr_err("Not allow lock operation on exclusive lock range\n"); pr_err("Not allow lock operation on exclusive lock range\n");
goto out; goto out;
} }
} }
spin_unlock(&conn->llist_lock); spin_unlock(&conn->llist_lock);
} }
read_unlock(&conn_list_lock); up_read(&conn_list_lock);
out_check_cl: out_check_cl:
if (smb_lock->fl->fl_type == F_UNLCK && nolock) { if (smb_lock->fl->fl_type == F_UNLCK && nolock) {
pr_err("Try to unlock nolocked range\n"); pr_err("Try to unlock nolocked range\n");
......
...@@ -61,6 +61,8 @@ struct preauth_integrity_info { ...@@ -61,6 +61,8 @@ struct preauth_integrity_info {
#define SMB2_SESSION_IN_PROGRESS BIT(0) #define SMB2_SESSION_IN_PROGRESS BIT(0)
#define SMB2_SESSION_VALID BIT(1) #define SMB2_SESSION_VALID BIT(1)
#define SMB2_SESSION_TIMEOUT (10 * HZ)
struct create_durable_req_v2 { struct create_durable_req_v2 {
struct create_context ccontext; struct create_context ccontext;
__u8 Name[8]; __u8 Name[8];
......
...@@ -333,7 +333,7 @@ static int ksmbd_tcp_readv(struct tcp_transport *t, struct kvec *iov_orig, ...@@ -333,7 +333,7 @@ static int ksmbd_tcp_readv(struct tcp_transport *t, struct kvec *iov_orig,
if (length == -EINTR) { if (length == -EINTR) {
total_read = -ESHUTDOWN; total_read = -ESHUTDOWN;
break; break;
} else if (conn->status == KSMBD_SESS_NEED_RECONNECT) { } else if (ksmbd_conn_need_reconnect(conn)) {
total_read = -EAGAIN; total_read = -EAGAIN;
break; break;
} else if (length == -ERESTARTSYS || length == -EAGAIN) { } else if (length == -ERESTARTSYS || length == -EAGAIN) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment