Skip to content

Commit

Permalink
Merge tag '5.20-rc-ksmbd-server-fixes' of git://git.samba.org/ksmbd
Browse files Browse the repository at this point in the history
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
  • Loading branch information
torvalds committed Aug 9, 2022
2 parents f30adc0 + 8f05411 commit eb555cb
Show file tree
Hide file tree
Showing 20 changed files with 322 additions and 220 deletions.
1 change: 1 addition & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -11063,6 +11063,7 @@ R: Sergey Senozhatsky <[email protected]>
L: [email protected]
S: Maintained
T: git git://git.samba.org/ksmbd.git
F: Documentation/filesystems/cifs/ksmbd.rst
F: fs/ksmbd/
F: fs/smbfs_common/

Expand Down
56 changes: 31 additions & 25 deletions fs/ksmbd/auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ static int ksmbd_gen_sess_key(struct ksmbd_session *sess, char *hash,
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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -215,8 +215,9 @@ static int calc_ntlmv2_hash(struct ksmbd_session *sess, char *ntlmv2_hash,
*
* 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];
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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};
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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",
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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,
Expand Down
11 changes: 7 additions & 4 deletions fs/ksmbd/auth.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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,
Expand Down
9 changes: 5 additions & 4 deletions fs/ksmbd/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down
10 changes: 2 additions & 8 deletions fs/ksmbd/connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
14 changes: 0 additions & 14 deletions fs/ksmbd/mgmt/share_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
2 changes: 0 additions & 2 deletions fs/ksmbd/mgmt/share_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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__ */
5 changes: 3 additions & 2 deletions fs/ksmbd/mgmt/tree_connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,
Expand Down
4 changes: 3 additions & 1 deletion fs/ksmbd/mgmt/tree_connect.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

struct ksmbd_share_config;
struct ksmbd_user;
struct ksmbd_conn;

struct ksmbd_tree_connect {
int id;
Expand Down Expand Up @@ -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);
Expand Down
Loading

0 comments on commit eb555cb

Please sign in to comment.