Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+322 -220
+1
MAINTAINERS
··· 11063 11063 L: linux-cifs@vger.kernel.org 11064 11064 S: Maintained 11065 11065 T: git git://git.samba.org/ksmbd.git 11066 + F: Documentation/filesystems/cifs/ksmbd.rst 11066 11067 F: fs/ksmbd/ 11067 11068 F: fs/smbfs_common/ 11068 11069
+31 -25
fs/ksmbd/auth.c
··· 121 121 return rc; 122 122 } 123 123 124 - static int calc_ntlmv2_hash(struct ksmbd_session *sess, char *ntlmv2_hash, 125 - char *dname) 124 + static int calc_ntlmv2_hash(struct ksmbd_conn *conn, struct ksmbd_session *sess, 125 + char *ntlmv2_hash, char *dname) 126 126 { 127 127 int ret, len, conv_len; 128 128 wchar_t *domain = NULL; ··· 158 158 } 159 159 160 160 conv_len = smb_strtoUTF16(uniname, user_name(sess->user), len, 161 - sess->conn->local_nls); 161 + conn->local_nls); 162 162 if (conv_len < 0 || conv_len > len) { 163 163 ret = -EINVAL; 164 164 goto out; ··· 182 182 } 183 183 184 184 conv_len = smb_strtoUTF16((__le16 *)domain, dname, len, 185 - sess->conn->local_nls); 185 + conn->local_nls); 186 186 if (conv_len < 0 || conv_len > len) { 187 187 ret = -EINVAL; 188 188 goto out; ··· 215 215 * 216 216 * Return: 0 on success, error number on error 217 217 */ 218 - int ksmbd_auth_ntlmv2(struct ksmbd_session *sess, struct ntlmv2_resp *ntlmv2, 219 - int blen, char *domain_name, char *cryptkey) 218 + int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess, 219 + struct ntlmv2_resp *ntlmv2, int blen, char *domain_name, 220 + char *cryptkey) 220 221 { 221 222 char ntlmv2_hash[CIFS_ENCPWD_SIZE]; 222 223 char ntlmv2_rsp[CIFS_HMAC_MD5_HASH_SIZE]; ··· 231 230 return -ENOMEM; 232 231 } 233 232 234 - rc = calc_ntlmv2_hash(sess, ntlmv2_hash, domain_name); 233 + rc = calc_ntlmv2_hash(conn, sess, ntlmv2_hash, domain_name); 235 234 if (rc) { 236 235 ksmbd_debug(AUTH, "could not get v2 hash rc %d\n", rc); 237 236 goto out; ··· 334 333 /* process NTLMv2 authentication */ 335 334 ksmbd_debug(AUTH, "decode_ntlmssp_authenticate_blob dname%s\n", 336 335 domain_name); 337 - ret = ksmbd_auth_ntlmv2(sess, (struct ntlmv2_resp *)((char *)authblob + nt_off), 336 + ret = ksmbd_auth_ntlmv2(conn, sess, 337 + (struct ntlmv2_resp *)((char *)authblob + nt_off), 338 338 nt_len - CIFS_ENCPWD_SIZE, 339 339 domain_name, conn->ntlmssp.cryptkey); 340 340 kfree(domain_name); ··· 661 659 bool binding; 662 660 }; 663 661 664 - static int generate_key(struct ksmbd_session *sess, struct kvec label, 665 - struct kvec context, __u8 *key, unsigned int key_size) 662 + static int generate_key(struct ksmbd_conn *conn, struct ksmbd_session *sess, 663 + struct kvec label, struct kvec context, __u8 *key, 664 + unsigned int key_size) 666 665 { 667 666 unsigned char zero = 0x0; 668 667 __u8 i[4] = {0, 0, 0, 1}; ··· 723 720 goto smb3signkey_ret; 724 721 } 725 722 726 - if (sess->conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM || 727 - sess->conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM) 723 + if (conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM || 724 + conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM) 728 725 rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), L256, 4); 729 726 else 730 727 rc = crypto_shash_update(CRYPTO_HMACSHA256(ctx), L128, 4); ··· 759 756 if (!chann) 760 757 return 0; 761 758 762 - if (sess->conn->dialect >= SMB30_PROT_ID && signing->binding) 759 + if (conn->dialect >= SMB30_PROT_ID && signing->binding) 763 760 key = chann->smb3signingkey; 764 761 else 765 762 key = sess->smb3signingkey; 766 763 767 - rc = generate_key(sess, signing->label, signing->context, key, 764 + rc = generate_key(conn, sess, signing->label, signing->context, key, 768 765 SMB3_SIGN_KEY_SIZE); 769 766 if (rc) 770 767 return rc; 771 768 772 - if (!(sess->conn->dialect >= SMB30_PROT_ID && signing->binding)) 769 + if (!(conn->dialect >= SMB30_PROT_ID && signing->binding)) 773 770 memcpy(chann->smb3signingkey, key, SMB3_SIGN_KEY_SIZE); 774 771 775 772 ksmbd_debug(AUTH, "dumping generated AES signing keys\n"); ··· 823 820 struct derivation decryption; 824 821 }; 825 822 826 - static int generate_smb3encryptionkey(struct ksmbd_session *sess, 823 + static int generate_smb3encryptionkey(struct ksmbd_conn *conn, 824 + struct ksmbd_session *sess, 827 825 const struct derivation_twin *ptwin) 828 826 { 829 827 int rc; 830 828 831 - rc = generate_key(sess, ptwin->encryption.label, 829 + rc = generate_key(conn, sess, ptwin->encryption.label, 832 830 ptwin->encryption.context, sess->smb3encryptionkey, 833 831 SMB3_ENC_DEC_KEY_SIZE); 834 832 if (rc) 835 833 return rc; 836 834 837 - rc = generate_key(sess, ptwin->decryption.label, 835 + rc = generate_key(conn, sess, ptwin->decryption.label, 838 836 ptwin->decryption.context, 839 837 sess->smb3decryptionkey, SMB3_ENC_DEC_KEY_SIZE); 840 838 if (rc) 841 839 return rc; 842 840 843 841 ksmbd_debug(AUTH, "dumping generated AES encryption keys\n"); 844 - ksmbd_debug(AUTH, "Cipher type %d\n", sess->conn->cipher_type); 842 + ksmbd_debug(AUTH, "Cipher type %d\n", conn->cipher_type); 845 843 ksmbd_debug(AUTH, "Session Id %llu\n", sess->id); 846 844 ksmbd_debug(AUTH, "Session Key %*ph\n", 847 845 SMB2_NTLMV2_SESSKEY_SIZE, sess->sess_key); 848 - if (sess->conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM || 849 - sess->conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM) { 846 + if (conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM || 847 + conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM) { 850 848 ksmbd_debug(AUTH, "ServerIn Key %*ph\n", 851 849 SMB3_GCM256_CRYPTKEY_SIZE, sess->smb3encryptionkey); 852 850 ksmbd_debug(AUTH, "ServerOut Key %*ph\n", ··· 861 857 return 0; 862 858 } 863 859 864 - int ksmbd_gen_smb30_encryptionkey(struct ksmbd_session *sess) 860 + int ksmbd_gen_smb30_encryptionkey(struct ksmbd_conn *conn, 861 + struct ksmbd_session *sess) 865 862 { 866 863 struct derivation_twin twin; 867 864 struct derivation *d; ··· 879 874 d->context.iov_base = "ServerIn "; 880 875 d->context.iov_len = 10; 881 876 882 - return generate_smb3encryptionkey(sess, &twin); 877 + return generate_smb3encryptionkey(conn, sess, &twin); 883 878 } 884 879 885 - int ksmbd_gen_smb311_encryptionkey(struct ksmbd_session *sess) 880 + int ksmbd_gen_smb311_encryptionkey(struct ksmbd_conn *conn, 881 + struct ksmbd_session *sess) 886 882 { 887 883 struct derivation_twin twin; 888 884 struct derivation *d; ··· 900 894 d->context.iov_base = sess->Preauth_HashValue; 901 895 d->context.iov_len = 64; 902 896 903 - return generate_smb3encryptionkey(sess, &twin); 897 + return generate_smb3encryptionkey(conn, sess, &twin); 904 898 } 905 899 906 900 int ksmbd_gen_preauth_integrity_hash(struct ksmbd_conn *conn, char *buf,
+7 -4
fs/ksmbd/auth.h
··· 38 38 int ksmbd_crypt_message(struct ksmbd_conn *conn, struct kvec *iov, 39 39 unsigned int nvec, int enc); 40 40 void ksmbd_copy_gss_neg_header(void *buf); 41 - int ksmbd_auth_ntlmv2(struct ksmbd_session *sess, struct ntlmv2_resp *ntlmv2, 42 - int blen, char *domain_name, char *cryptkey); 41 + int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess, 42 + struct ntlmv2_resp *ntlmv2, int blen, char *domain_name, 43 + char *cryptkey); 43 44 int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob, 44 45 int blob_len, struct ksmbd_conn *conn, 45 46 struct ksmbd_session *sess); ··· 59 58 struct ksmbd_conn *conn); 60 59 int ksmbd_gen_smb311_signingkey(struct ksmbd_session *sess, 61 60 struct ksmbd_conn *conn); 62 - int ksmbd_gen_smb30_encryptionkey(struct ksmbd_session *sess); 63 - int ksmbd_gen_smb311_encryptionkey(struct ksmbd_session *sess); 61 + int ksmbd_gen_smb30_encryptionkey(struct ksmbd_conn *conn, 62 + struct ksmbd_session *sess); 63 + int ksmbd_gen_smb311_encryptionkey(struct ksmbd_conn *conn, 64 + struct ksmbd_session *sess); 64 65 int ksmbd_gen_preauth_integrity_hash(struct ksmbd_conn *conn, char *buf, 65 66 __u8 *pi_hash); 66 67 int ksmbd_gen_sd_hash(struct ksmbd_conn *conn, char *sd_buf, int len,
+5 -4
fs/ksmbd/connection.c
··· 36 36 list_del(&conn->conns_list); 37 37 write_unlock(&conn_list_lock); 38 38 39 + xa_destroy(&conn->sessions); 39 40 kvfree(conn->request_buf); 40 41 kfree(conn->preauth_info); 41 42 kfree(conn); ··· 66 65 conn->outstanding_credits = 0; 67 66 68 67 init_waitqueue_head(&conn->req_running_q); 68 + init_waitqueue_head(&conn->r_count_q); 69 69 INIT_LIST_HEAD(&conn->conns_list); 70 - INIT_LIST_HEAD(&conn->sessions); 71 70 INIT_LIST_HEAD(&conn->requests); 72 71 INIT_LIST_HEAD(&conn->async_requests); 73 72 spin_lock_init(&conn->request_lock); 74 73 spin_lock_init(&conn->credits_lock); 75 74 ida_init(&conn->async_ida); 75 + xa_init(&conn->sessions); 76 76 77 77 spin_lock_init(&conn->llist_lock); 78 78 INIT_LIST_HEAD(&conn->lock_list); ··· 166 164 struct kvec iov[3]; 167 165 int iov_idx = 0; 168 166 169 - ksmbd_conn_try_dequeue_request(work); 170 167 if (!work->response_buf) { 171 168 pr_err("NULL response header\n"); 172 169 return -EINVAL; ··· 347 346 348 347 out: 349 348 /* Wait till all reference dropped to the Server object*/ 350 - while (atomic_read(&conn->r_count) > 0) 351 - schedule_timeout(HZ); 349 + wait_event(conn->r_count_q, atomic_read(&conn->r_count) == 0); 350 + 352 351 353 352 unload_nls(conn->local_nls); 354 353 if (default_conn_ops.terminate_fn)
+2 -8
fs/ksmbd/connection.h
··· 20 20 21 21 #define KSMBD_SOCKET_BACKLOG 16 22 22 23 - /* 24 - * WARNING 25 - * 26 - * This is nothing but a HACK. Session status should move to channel 27 - * or to session. As of now we have 1 tcp_conn : 1 ksmbd_session, but 28 - * we need to change it to 1 tcp_conn : N ksmbd_sessions. 29 - */ 30 23 enum { 31 24 KSMBD_SESS_NEW = 0, 32 25 KSMBD_SESS_GOOD, ··· 48 55 struct nls_table *local_nls; 49 56 struct list_head conns_list; 50 57 /* smb session 1 per user */ 51 - struct list_head sessions; 58 + struct xarray sessions; 52 59 unsigned long last_active; 53 60 /* How many request are running currently */ 54 61 atomic_t req_running; ··· 58 65 unsigned int outstanding_credits; 59 66 spinlock_t credits_lock; 60 67 wait_queue_head_t req_running_q; 68 + wait_queue_head_t r_count_q; 61 69 /* Lock to protect requests list*/ 62 70 spinlock_t request_lock; 63 71 struct list_head requests;
-14
fs/ksmbd/mgmt/share_config.c
··· 222 222 } 223 223 return false; 224 224 } 225 - 226 - void ksmbd_share_configs_cleanup(void) 227 - { 228 - struct ksmbd_share_config *share; 229 - struct hlist_node *tmp; 230 - int i; 231 - 232 - down_write(&shares_table_lock); 233 - hash_for_each_safe(shares_table, i, tmp, share, hlist) { 234 - hash_del(&share->hlist); 235 - kill_share(share); 236 - } 237 - up_write(&shares_table_lock); 238 - }
-2
fs/ksmbd/mgmt/share_config.h
··· 76 76 struct ksmbd_share_config *ksmbd_share_config_get(char *name); 77 77 bool ksmbd_share_veto_filename(struct ksmbd_share_config *share, 78 78 const char *filename); 79 - void ksmbd_share_configs_cleanup(void); 80 - 81 79 #endif /* __SHARE_CONFIG_MANAGEMENT_H__ */
+3 -2
fs/ksmbd/mgmt/tree_connect.c
··· 16 16 #include "user_session.h" 17 17 18 18 struct ksmbd_tree_conn_status 19 - ksmbd_tree_conn_connect(struct ksmbd_session *sess, char *share_name) 19 + ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess, 20 + char *share_name) 20 21 { 21 22 struct ksmbd_tree_conn_status status = {-EINVAL, NULL}; 22 23 struct ksmbd_tree_connect_response *resp = NULL; ··· 42 41 goto out_error; 43 42 } 44 43 45 - peer_addr = KSMBD_TCP_PEER_SOCKADDR(sess->conn); 44 + peer_addr = KSMBD_TCP_PEER_SOCKADDR(conn); 46 45 resp = ksmbd_ipc_tree_connect_request(sess, 47 46 sc, 48 47 tree_conn,
+3 -1
fs/ksmbd/mgmt/tree_connect.h
··· 12 12 13 13 struct ksmbd_share_config; 14 14 struct ksmbd_user; 15 + struct ksmbd_conn; 15 16 16 17 struct ksmbd_tree_connect { 17 18 int id; ··· 41 40 struct ksmbd_session; 42 41 43 42 struct ksmbd_tree_conn_status 44 - ksmbd_tree_conn_connect(struct ksmbd_session *sess, char *share_name); 43 + ksmbd_tree_conn_connect(struct ksmbd_conn *conn, struct ksmbd_session *sess, 44 + char *share_name); 45 45 46 46 int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess, 47 47 struct ksmbd_tree_connect *tree_conn);
+54 -43
fs/ksmbd/mgmt/user_session.c
··· 32 32 { 33 33 struct channel *chann, *tmp; 34 34 35 + write_lock(&sess->chann_lock); 35 36 list_for_each_entry_safe(chann, tmp, &sess->ksmbd_chann_list, 36 37 chann_list) { 37 38 list_del(&chann->chann_list); 38 39 kfree(chann); 39 40 } 41 + write_unlock(&sess->chann_lock); 40 42 } 41 43 42 44 static void __session_rpc_close(struct ksmbd_session *sess, ··· 151 149 if (!sess) 152 150 return; 153 151 154 - if (!atomic_dec_and_test(&sess->refcnt)) 155 - return; 156 - 157 - list_del(&sess->sessions_entry); 158 - 159 152 down_write(&sessions_table_lock); 160 153 hash_del(&sess->hlist); 161 154 up_write(&sessions_table_lock); ··· 178 181 return NULL; 179 182 } 180 183 181 - void ksmbd_session_register(struct ksmbd_conn *conn, 182 - struct ksmbd_session *sess) 184 + int ksmbd_session_register(struct ksmbd_conn *conn, 185 + struct ksmbd_session *sess) 183 186 { 184 - sess->conn = conn; 185 - list_add(&sess->sessions_entry, &conn->sessions); 187 + sess->dialect = conn->dialect; 188 + memcpy(sess->ClientGUID, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE); 189 + return xa_err(xa_store(&conn->sessions, sess->id, sess, GFP_KERNEL)); 190 + } 191 + 192 + static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess) 193 + { 194 + struct channel *chann, *tmp; 195 + 196 + write_lock(&sess->chann_lock); 197 + list_for_each_entry_safe(chann, tmp, &sess->ksmbd_chann_list, 198 + chann_list) { 199 + if (chann->conn == conn) { 200 + list_del(&chann->chann_list); 201 + kfree(chann); 202 + write_unlock(&sess->chann_lock); 203 + return 0; 204 + } 205 + } 206 + write_unlock(&sess->chann_lock); 207 + 208 + return -ENOENT; 186 209 } 187 210 188 211 void ksmbd_sessions_deregister(struct ksmbd_conn *conn) 189 212 { 190 213 struct ksmbd_session *sess; 191 214 192 - while (!list_empty(&conn->sessions)) { 193 - sess = list_entry(conn->sessions.next, 194 - struct ksmbd_session, 195 - sessions_entry); 215 + if (conn->binding) { 216 + int bkt; 196 217 218 + down_write(&sessions_table_lock); 219 + hash_for_each(sessions_table, bkt, sess, hlist) { 220 + if (!ksmbd_chann_del(conn, sess)) { 221 + up_write(&sessions_table_lock); 222 + goto sess_destroy; 223 + } 224 + } 225 + up_write(&sessions_table_lock); 226 + } else { 227 + unsigned long id; 228 + 229 + xa_for_each(&conn->sessions, id, sess) { 230 + if (!ksmbd_chann_del(conn, sess)) 231 + goto sess_destroy; 232 + } 233 + } 234 + 235 + return; 236 + 237 + sess_destroy: 238 + if (list_empty(&sess->ksmbd_chann_list)) { 239 + xa_erase(&conn->sessions, sess->id); 197 240 ksmbd_session_destroy(sess); 198 241 } 199 - } 200 - 201 - static bool ksmbd_session_id_match(struct ksmbd_session *sess, 202 - unsigned long long id) 203 - { 204 - return sess->id == id; 205 242 } 206 243 207 244 struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn, 208 245 unsigned long long id) 209 246 { 210 - struct ksmbd_session *sess = NULL; 211 - 212 - list_for_each_entry(sess, &conn->sessions, sessions_entry) { 213 - if (ksmbd_session_id_match(sess, id)) 214 - return sess; 215 - } 216 - return NULL; 217 - } 218 - 219 - int get_session(struct ksmbd_session *sess) 220 - { 221 - return atomic_inc_not_zero(&sess->refcnt); 222 - } 223 - 224 - void put_session(struct ksmbd_session *sess) 225 - { 226 - if (atomic_dec_and_test(&sess->refcnt)) 227 - pr_err("get/%s seems to be mismatched.", __func__); 247 + return xa_load(&conn->sessions, id); 228 248 } 229 249 230 250 struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id) ··· 250 236 251 237 down_read(&sessions_table_lock); 252 238 sess = __session_lookup(id); 253 - if (sess) { 254 - if (!get_session(sess)) 255 - sess = NULL; 256 - } 257 239 up_read(&sessions_table_lock); 258 240 259 241 return sess; ··· 263 253 sess = ksmbd_session_lookup(conn, id); 264 254 if (!sess && conn->binding) 265 255 sess = ksmbd_session_lookup_slowpath(id); 256 + if (sess && sess->state != SMB2_SESSION_VALID) 257 + sess = NULL; 266 258 return sess; 267 259 } 268 260 ··· 326 314 goto error; 327 315 328 316 set_session_flag(sess, protocol); 329 - INIT_LIST_HEAD(&sess->sessions_entry); 330 317 xa_init(&sess->tree_conns); 331 318 INIT_LIST_HEAD(&sess->ksmbd_chann_list); 332 319 INIT_LIST_HEAD(&sess->rpc_handle_list); 333 320 sess->sequence_number = 1; 334 - atomic_set(&sess->refcnt, 1); 321 + rwlock_init(&sess->chann_lock); 335 322 336 323 switch (protocol) { 337 324 case CIFDS_SESSION_FLAG_SMB2:
+6 -7
fs/ksmbd/mgmt/user_session.h
··· 33 33 struct ksmbd_session { 34 34 u64 id; 35 35 36 + __u16 dialect; 37 + char ClientGUID[SMB2_CLIENT_GUID_SIZE]; 38 + 36 39 struct ksmbd_user *user; 37 - struct ksmbd_conn *conn; 38 40 unsigned int sequence_number; 39 41 unsigned int flags; 40 42 ··· 50 48 char sess_key[CIFS_KEY_SIZE]; 51 49 52 50 struct hlist_node hlist; 51 + rwlock_t chann_lock; 53 52 struct list_head ksmbd_chann_list; 54 53 struct xarray tree_conns; 55 54 struct ida tree_conn_ida; ··· 60 57 __u8 smb3decryptionkey[SMB3_ENC_DEC_KEY_SIZE]; 61 58 __u8 smb3signingkey[SMB3_SIGN_KEY_SIZE]; 62 59 63 - struct list_head sessions_entry; 64 60 struct ksmbd_file_table file_table; 65 - atomic_t refcnt; 66 61 }; 67 62 68 63 static inline int test_session_flag(struct ksmbd_session *sess, int bit) ··· 85 84 struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id); 86 85 struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn, 87 86 unsigned long long id); 88 - void ksmbd_session_register(struct ksmbd_conn *conn, 89 - struct ksmbd_session *sess); 87 + int ksmbd_session_register(struct ksmbd_conn *conn, 88 + struct ksmbd_session *sess); 90 89 void ksmbd_sessions_deregister(struct ksmbd_conn *conn); 91 90 struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn, 92 91 unsigned long long id); ··· 101 100 int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name); 102 101 void ksmbd_session_rpc_close(struct ksmbd_session *sess, int id); 103 102 int ksmbd_session_rpc_method(struct ksmbd_session *sess, int id); 104 - int get_session(struct ksmbd_session *sess); 105 - void put_session(struct ksmbd_session *sess); 106 103 #endif /* __USER_SESSION_MANAGEMENT_H__ */
+28 -18
fs/ksmbd/oplock.c
··· 30 30 static struct oplock_info *alloc_opinfo(struct ksmbd_work *work, 31 31 u64 id, __u16 Tid) 32 32 { 33 + struct ksmbd_conn *conn = work->conn; 33 34 struct ksmbd_session *sess = work->sess; 34 35 struct oplock_info *opinfo; 35 36 ··· 39 38 return NULL; 40 39 41 40 opinfo->sess = sess; 42 - opinfo->conn = sess->conn; 41 + opinfo->conn = conn; 43 42 opinfo->level = SMB2_OPLOCK_LEVEL_NONE; 44 43 opinfo->op_state = OPLOCK_STATE_NONE; 45 44 opinfo->pending_break = 0; ··· 616 615 struct ksmbd_file *fp; 617 616 618 617 fp = ksmbd_lookup_durable_fd(br_info->fid); 619 - if (!fp) { 620 - atomic_dec(&conn->r_count); 621 - ksmbd_free_work_struct(work); 622 - return; 623 - } 618 + if (!fp) 619 + goto out; 624 620 625 621 if (allocate_oplock_break_buf(work)) { 626 622 pr_err("smb2_allocate_rsp_buf failed! "); 627 - atomic_dec(&conn->r_count); 628 623 ksmbd_fd_put(work, fp); 629 - ksmbd_free_work_struct(work); 630 - return; 624 + goto out; 631 625 } 632 626 633 627 rsp_hdr = smb2_get_msg(work->response_buf); ··· 663 667 664 668 ksmbd_fd_put(work, fp); 665 669 ksmbd_conn_write(work); 670 + 671 + out: 666 672 ksmbd_free_work_struct(work); 667 - atomic_dec(&conn->r_count); 673 + /* 674 + * Checking waitqueue to dropping pending requests on 675 + * disconnection. waitqueue_active is safe because it 676 + * uses atomic operation for condition. 677 + */ 678 + if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q)) 679 + wake_up(&conn->r_count_q); 668 680 } 669 681 670 682 /** ··· 735 731 736 732 if (allocate_oplock_break_buf(work)) { 737 733 ksmbd_debug(OPLOCK, "smb2_allocate_rsp_buf failed! "); 738 - ksmbd_free_work_struct(work); 739 - atomic_dec(&conn->r_count); 740 - return; 734 + goto out; 741 735 } 742 736 743 737 rsp_hdr = smb2_get_msg(work->response_buf); ··· 773 771 inc_rfc1001_len(work->response_buf, 44); 774 772 775 773 ksmbd_conn_write(work); 774 + 775 + out: 776 776 ksmbd_free_work_struct(work); 777 - atomic_dec(&conn->r_count); 777 + /* 778 + * Checking waitqueue to dropping pending requests on 779 + * disconnection. waitqueue_active is safe because it 780 + * uses atomic operation for condition. 781 + */ 782 + if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q)) 783 + wake_up(&conn->r_count_q); 778 784 } 779 785 780 786 /** ··· 982 972 } 983 973 984 974 list_for_each_entry(lb, &lease_table_list, l_entry) { 985 - if (!memcmp(lb->client_guid, sess->conn->ClientGUID, 975 + if (!memcmp(lb->client_guid, sess->ClientGUID, 986 976 SMB2_CLIENT_GUID_SIZE)) 987 977 goto found; 988 978 } ··· 998 988 rcu_read_unlock(); 999 989 if (opinfo->o_fp->f_ci == ci) 1000 990 goto op_next; 1001 - err = compare_guid_key(opinfo, sess->conn->ClientGUID, 991 + err = compare_guid_key(opinfo, sess->ClientGUID, 1002 992 lctx->lease_key); 1003 993 if (err) { 1004 994 err = -EINVAL; ··· 1132 1122 struct oplock_info *m_opinfo; 1133 1123 1134 1124 /* is lease already granted ? */ 1135 - m_opinfo = same_client_has_lease(ci, sess->conn->ClientGUID, 1125 + m_opinfo = same_client_has_lease(ci, sess->ClientGUID, 1136 1126 lctx); 1137 1127 if (m_opinfo) { 1138 1128 copy_lease(m_opinfo, opinfo); ··· 1250 1240 { 1251 1241 struct oplock_info *op, *brk_op; 1252 1242 struct ksmbd_inode *ci; 1253 - struct ksmbd_conn *conn = work->sess->conn; 1243 + struct ksmbd_conn *conn = work->conn; 1254 1244 1255 1245 if (!test_share_config_flag(work->tcon->share_conf, 1256 1246 KSMBD_SHARE_FLAG_OPLOCKS))
+7 -1
fs/ksmbd/server.c
··· 261 261 262 262 ksmbd_conn_try_dequeue_request(work); 263 263 ksmbd_free_work_struct(work); 264 - atomic_dec(&conn->r_count); 264 + /* 265 + * Checking waitqueue to dropping pending requests on 266 + * disconnection. waitqueue_active is safe because it 267 + * uses atomic operation for condition. 268 + */ 269 + if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q)) 270 + wake_up(&conn->r_count_q); 265 271 } 266 272 267 273 /**
+5 -7
fs/ksmbd/smb2misc.c
··· 90 90 *off = 0; 91 91 *len = 0; 92 92 93 - /* error reqeusts do not have data area */ 94 - if (hdr->Status && hdr->Status != STATUS_MORE_PROCESSING_REQUIRED && 95 - (((struct smb2_err_rsp *)hdr)->StructureSize) == SMB2_ERROR_STRUCTURE_SIZE2_LE) 96 - return ret; 97 - 98 93 /* 99 94 * Following commands have data areas so we have to get the location 100 95 * of the data buffer offset and data buffer length for the particular ··· 131 136 *len = le16_to_cpu(((struct smb2_read_req *)hdr)->ReadChannelInfoLength); 132 137 break; 133 138 case SMB2_WRITE: 134 - if (((struct smb2_write_req *)hdr)->DataOffset) { 135 - *off = le16_to_cpu(((struct smb2_write_req *)hdr)->DataOffset); 139 + if (((struct smb2_write_req *)hdr)->DataOffset || 140 + ((struct smb2_write_req *)hdr)->Length) { 141 + *off = max_t(unsigned int, 142 + le16_to_cpu(((struct smb2_write_req *)hdr)->DataOffset), 143 + offsetof(struct smb2_write_req, Buffer)); 136 144 *len = le32_to_cpu(((struct smb2_write_req *)hdr)->Length); 137 145 break; 138 146 }
+73 -37
fs/ksmbd/smb2pdu.c
··· 535 535 struct smb2_query_info_req *req; 536 536 537 537 req = smb2_get_msg(work->request_buf); 538 - if (req->InfoType == SMB2_O_INFO_FILE && 539 - (req->FileInfoClass == FILE_FULL_EA_INFORMATION || 540 - req->FileInfoClass == FILE_ALL_INFORMATION)) 538 + if ((req->InfoType == SMB2_O_INFO_FILE && 539 + (req->FileInfoClass == FILE_FULL_EA_INFORMATION || 540 + req->FileInfoClass == FILE_ALL_INFORMATION)) || 541 + req->InfoType == SMB2_O_INFO_SECURITY) 541 542 sz = large_sz; 542 543 } 543 544 ··· 589 588 return -EINVAL; 590 589 } 591 590 592 - static void destroy_previous_session(struct ksmbd_user *user, u64 id) 591 + static void destroy_previous_session(struct ksmbd_conn *conn, 592 + struct ksmbd_user *user, u64 id) 593 593 { 594 594 struct ksmbd_session *prev_sess = ksmbd_session_lookup_slowpath(id); 595 595 struct ksmbd_user *prev_user; 596 + struct channel *chann; 596 597 597 598 if (!prev_sess) 598 599 return; ··· 604 601 if (!prev_user || 605 602 strcmp(user->name, prev_user->name) || 606 603 user->passkey_sz != prev_user->passkey_sz || 607 - memcmp(user->passkey, prev_user->passkey, user->passkey_sz)) { 608 - put_session(prev_sess); 604 + memcmp(user->passkey, prev_user->passkey, user->passkey_sz)) 609 605 return; 610 - } 611 606 612 - put_session(prev_sess); 613 - ksmbd_session_destroy(prev_sess); 607 + prev_sess->state = SMB2_SESSION_EXPIRED; 608 + write_lock(&prev_sess->chann_lock); 609 + list_for_each_entry(chann, &prev_sess->ksmbd_chann_list, chann_list) 610 + chann->conn->status = KSMBD_SESS_EXITING; 611 + write_unlock(&prev_sess->chann_lock); 614 612 } 615 613 616 614 /** ··· 1143 1139 status); 1144 1140 rsp->hdr.Status = status; 1145 1141 rc = -EINVAL; 1142 + kfree(conn->preauth_info); 1143 + conn->preauth_info = NULL; 1146 1144 goto err_out; 1147 1145 } 1148 1146 1149 1147 rc = init_smb3_11_server(conn); 1150 1148 if (rc < 0) { 1151 1149 rsp->hdr.Status = STATUS_INVALID_PARAMETER; 1150 + kfree(conn->preauth_info); 1151 + conn->preauth_info = NULL; 1152 1152 goto err_out; 1153 1153 } 1154 1154 ··· 1447 1439 /* Check for previous session */ 1448 1440 prev_id = le64_to_cpu(req->PreviousSessionId); 1449 1441 if (prev_id && prev_id != sess->id) 1450 - destroy_previous_session(user, prev_id); 1442 + destroy_previous_session(conn, user, prev_id); 1451 1443 1452 1444 if (sess->state == SMB2_SESSION_VALID) { 1453 1445 /* ··· 1501 1493 1502 1494 if (smb3_encryption_negotiated(conn) && 1503 1495 !(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) { 1504 - rc = conn->ops->generate_encryptionkey(sess); 1496 + rc = conn->ops->generate_encryptionkey(conn, sess); 1505 1497 if (rc) { 1506 1498 ksmbd_debug(SMB, 1507 1499 "SMB3 encryption key generation failed\n"); ··· 1518 1510 1519 1511 binding_session: 1520 1512 if (conn->dialect >= SMB30_PROT_ID) { 1513 + read_lock(&sess->chann_lock); 1521 1514 chann = lookup_chann_list(sess, conn); 1515 + read_unlock(&sess->chann_lock); 1522 1516 if (!chann) { 1523 1517 chann = kmalloc(sizeof(struct channel), GFP_KERNEL); 1524 1518 if (!chann) ··· 1528 1518 1529 1519 chann->conn = conn; 1530 1520 INIT_LIST_HEAD(&chann->chann_list); 1521 + write_lock(&sess->chann_lock); 1531 1522 list_add(&chann->chann_list, &sess->ksmbd_chann_list); 1523 + write_unlock(&sess->chann_lock); 1532 1524 } 1533 1525 } 1534 1526 ··· 1573 1561 /* Check previous session */ 1574 1562 prev_sess_id = le64_to_cpu(req->PreviousSessionId); 1575 1563 if (prev_sess_id && prev_sess_id != sess->id) 1576 - destroy_previous_session(sess->user, prev_sess_id); 1564 + destroy_previous_session(conn, sess->user, prev_sess_id); 1577 1565 1578 1566 if (sess->state == SMB2_SESSION_VALID) 1579 1567 ksmbd_free_user(sess->user); ··· 1592 1580 sess->sign = true; 1593 1581 1594 1582 if (smb3_encryption_negotiated(conn)) { 1595 - retval = conn->ops->generate_encryptionkey(sess); 1583 + retval = conn->ops->generate_encryptionkey(conn, sess); 1596 1584 if (retval) { 1597 1585 ksmbd_debug(SMB, 1598 1586 "SMB3 encryption key generation failed\n"); ··· 1604 1592 } 1605 1593 1606 1594 if (conn->dialect >= SMB30_PROT_ID) { 1595 + read_lock(&sess->chann_lock); 1607 1596 chann = lookup_chann_list(sess, conn); 1597 + read_unlock(&sess->chann_lock); 1608 1598 if (!chann) { 1609 1599 chann = kmalloc(sizeof(struct channel), GFP_KERNEL); 1610 1600 if (!chann) ··· 1614 1600 1615 1601 chann->conn = conn; 1616 1602 INIT_LIST_HEAD(&chann->chann_list); 1603 + write_lock(&sess->chann_lock); 1617 1604 list_add(&chann->chann_list, &sess->ksmbd_chann_list); 1605 + write_unlock(&sess->chann_lock); 1618 1606 } 1619 1607 } 1620 1608 ··· 1666 1650 goto out_err; 1667 1651 } 1668 1652 rsp->hdr.SessionId = cpu_to_le64(sess->id); 1669 - ksmbd_session_register(conn, sess); 1653 + rc = ksmbd_session_register(conn, sess); 1654 + if (rc) 1655 + goto out_err; 1670 1656 } else if (conn->dialect >= SMB30_PROT_ID && 1671 1657 (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) && 1672 1658 req->Flags & SMB2_SESSION_REQ_FLAG_BINDING) { ··· 1680 1662 goto out_err; 1681 1663 } 1682 1664 1683 - if (conn->dialect != sess->conn->dialect) { 1665 + if (conn->dialect != sess->dialect) { 1684 1666 rc = -EINVAL; 1685 1667 goto out_err; 1686 1668 } ··· 1690 1672 goto out_err; 1691 1673 } 1692 1674 1693 - if (strncmp(conn->ClientGUID, sess->conn->ClientGUID, 1675 + if (strncmp(conn->ClientGUID, sess->ClientGUID, 1694 1676 SMB2_CLIENT_GUID_SIZE)) { 1695 1677 rc = -ENOENT; 1696 1678 goto out_err; ··· 1846 1828 if (sess->user && sess->user->flags & KSMBD_USER_FLAG_DELAY_SESSION) 1847 1829 try_delay = true; 1848 1830 1831 + xa_erase(&conn->sessions, sess->id); 1849 1832 ksmbd_session_destroy(sess); 1850 1833 work->sess = NULL; 1851 1834 if (try_delay) ··· 1892 1873 ksmbd_debug(SMB, "tree connect request for tree %s treename %s\n", 1893 1874 name, treename); 1894 1875 1895 - status = ksmbd_tree_conn_connect(sess, name); 1876 + status = ksmbd_tree_conn_connect(conn, sess, name); 1896 1877 if (status.ret == KSMBD_TREE_CONN_STATUS_OK) 1897 1878 rsp->hdr.Id.SyncId.TreeId = cpu_to_le32(status.tree_conn->id); 1898 1879 else ··· 2058 2039 2059 2040 ksmbd_close_tree_conn_fds(work); 2060 2041 ksmbd_tree_conn_disconnect(sess, tcon); 2042 + work->tcon = NULL; 2061 2043 return 0; 2062 2044 } 2063 2045 ··· 2989 2969 goto err_out; 2990 2970 2991 2971 rc = build_sec_desc(user_ns, 2992 - pntsd, NULL, 2972 + pntsd, NULL, 0, 2993 2973 OWNER_SECINFO | 2994 2974 GROUP_SECINFO | 2995 2975 DACL_SECINFO, ··· 3834 3814 return 0; 3835 3815 } 3836 3816 3817 + static int smb2_resp_buf_len(struct ksmbd_work *work, unsigned short hdr2_len) 3818 + { 3819 + int free_len; 3820 + 3821 + free_len = (int)(work->response_sz - 3822 + (get_rfc1002_len(work->response_buf) + 4)) - hdr2_len; 3823 + return free_len; 3824 + } 3825 + 3837 3826 static int smb2_calc_max_out_buf_len(struct ksmbd_work *work, 3838 3827 unsigned short hdr2_len, 3839 3828 unsigned int out_buf_len) ··· 3852 3823 if (out_buf_len > work->conn->vals->max_trans_size) 3853 3824 return -EINVAL; 3854 3825 3855 - free_len = (int)(work->response_sz - 3856 - (get_rfc1002_len(work->response_buf) + 4)) - 3857 - hdr2_len; 3826 + free_len = smb2_resp_buf_len(work, hdr2_len); 3858 3827 if (free_len < 0) 3859 3828 return -EINVAL; 3860 3829 ··· 4885 4858 struct smb2_query_info_rsp *rsp) 4886 4859 { 4887 4860 struct ksmbd_session *sess = work->sess; 4888 - struct ksmbd_conn *conn = sess->conn; 4861 + struct ksmbd_conn *conn = work->conn; 4889 4862 struct ksmbd_share_config *share = work->tcon->share_conf; 4890 4863 int fsinfoclass = 0; 4891 4864 struct kstatfs stfs; ··· 5115 5088 struct smb_ntsd *pntsd = (struct smb_ntsd *)rsp->Buffer, *ppntsd = NULL; 5116 5089 struct smb_fattr fattr = {{0}}; 5117 5090 struct inode *inode; 5118 - __u32 secdesclen; 5091 + __u32 secdesclen = 0; 5119 5092 unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID; 5120 5093 int addition_info = le32_to_cpu(req->AdditionalInformation); 5121 - int rc; 5094 + int rc = 0, ppntsd_size = 0; 5122 5095 5123 5096 if (addition_info & ~(OWNER_SECINFO | GROUP_SECINFO | DACL_SECINFO | 5124 5097 PROTECTED_DACL_SECINFO | ··· 5164 5137 5165 5138 if (test_share_config_flag(work->tcon->share_conf, 5166 5139 KSMBD_SHARE_FLAG_ACL_XATTR)) 5167 - ksmbd_vfs_get_sd_xattr(work->conn, user_ns, 5168 - fp->filp->f_path.dentry, &ppntsd); 5140 + ppntsd_size = ksmbd_vfs_get_sd_xattr(work->conn, user_ns, 5141 + fp->filp->f_path.dentry, 5142 + &ppntsd); 5169 5143 5170 - rc = build_sec_desc(user_ns, pntsd, ppntsd, addition_info, 5171 - &secdesclen, &fattr); 5144 + /* Check if sd buffer size exceeds response buffer size */ 5145 + if (smb2_resp_buf_len(work, 8) > ppntsd_size) 5146 + rc = build_sec_desc(user_ns, pntsd, ppntsd, ppntsd_size, 5147 + addition_info, &secdesclen, &fattr); 5172 5148 posix_acl_release(fattr.cf_acls); 5173 5149 posix_acl_release(fattr.cf_dacls); 5174 5150 kfree(ppntsd); ··· 5806 5776 } 5807 5777 next: 5808 5778 return smb2_rename(work, fp, user_ns, rename_info, 5809 - work->sess->conn->local_nls); 5779 + work->conn->local_nls); 5810 5780 } 5811 5781 5812 5782 static int set_file_disposition_info(struct ksmbd_file *fp, ··· 5938 5908 return smb2_create_link(work, work->tcon->share_conf, 5939 5909 (struct smb2_file_link_info *)req->Buffer, 5940 5910 buf_len, fp->filp, 5941 - work->sess->conn->local_nls); 5911 + work->conn->local_nls); 5942 5912 } 5943 5913 case FILE_DISPOSITION_INFORMATION: 5944 5914 { ··· 6525 6495 writethrough = true; 6526 6496 6527 6497 if (is_rdma_channel == false) { 6528 - if ((u64)le16_to_cpu(req->DataOffset) + length > 6529 - get_rfc1002_len(work->request_buf)) { 6530 - pr_err("invalid write data offset %u, smb_len %u\n", 6531 - le16_to_cpu(req->DataOffset), 6532 - get_rfc1002_len(work->request_buf)); 6498 + if (le16_to_cpu(req->DataOffset) < 6499 + offsetof(struct smb2_write_req, Buffer)) { 6533 6500 err = -EINVAL; 6534 6501 goto out; 6535 6502 } 6503 + 6536 6504 data_buf = (char *)(((char *)&req->hdr.ProtocolId) + 6537 6505 le16_to_cpu(req->DataOffset)); 6538 6506 ··· 8384 8356 if (le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) { 8385 8357 signing_key = work->sess->smb3signingkey; 8386 8358 } else { 8359 + read_lock(&work->sess->chann_lock); 8387 8360 chann = lookup_chann_list(work->sess, conn); 8388 - if (!chann) 8361 + if (!chann) { 8362 + read_unlock(&work->sess->chann_lock); 8389 8363 return 0; 8364 + } 8390 8365 signing_key = chann->smb3signingkey; 8366 + read_unlock(&work->sess->chann_lock); 8391 8367 } 8392 8368 8393 8369 if (!signing_key) { ··· 8451 8419 le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) { 8452 8420 signing_key = work->sess->smb3signingkey; 8453 8421 } else { 8422 + read_lock(&work->sess->chann_lock); 8454 8423 chann = lookup_chann_list(work->sess, work->conn); 8455 - if (!chann) 8424 + if (!chann) { 8425 + read_unlock(&work->sess->chann_lock); 8456 8426 return; 8427 + } 8457 8428 signing_key = chann->smb3signingkey; 8429 + read_unlock(&work->sess->chann_lock); 8458 8430 } 8459 8431 8460 8432 if (!signing_key)
+1 -1
fs/ksmbd/smb_common.h
··· 421 421 int (*check_sign_req)(struct ksmbd_work *work); 422 422 void (*set_sign_rsp)(struct ksmbd_work *work); 423 423 int (*generate_signingkey)(struct ksmbd_session *sess, struct ksmbd_conn *conn); 424 - int (*generate_encryptionkey)(struct ksmbd_session *sess); 424 + int (*generate_encryptionkey)(struct ksmbd_conn *conn, struct ksmbd_session *sess); 425 425 bool (*is_transform_hdr)(void *buf); 426 426 int (*decrypt_req)(struct ksmbd_work *work); 427 427 int (*encrypt_resp)(struct ksmbd_work *work);
+88 -42
fs/ksmbd/smbacl.c
··· 690 690 static void set_ntacl_dacl(struct user_namespace *user_ns, 691 691 struct smb_acl *pndacl, 692 692 struct smb_acl *nt_dacl, 693 + unsigned int aces_size, 693 694 const struct smb_sid *pownersid, 694 695 const struct smb_sid *pgrpsid, 695 696 struct smb_fattr *fattr) ··· 704 703 if (nt_num_aces) { 705 704 ntace = (struct smb_ace *)((char *)nt_dacl + sizeof(struct smb_acl)); 706 705 for (i = 0; i < nt_num_aces; i++) { 707 - memcpy((char *)pndace + size, ntace, le16_to_cpu(ntace->size)); 708 - size += le16_to_cpu(ntace->size); 709 - ntace = (struct smb_ace *)((char *)ntace + le16_to_cpu(ntace->size)); 706 + unsigned short nt_ace_size; 707 + 708 + if (offsetof(struct smb_ace, access_req) > aces_size) 709 + break; 710 + 711 + nt_ace_size = le16_to_cpu(ntace->size); 712 + if (nt_ace_size > aces_size) 713 + break; 714 + 715 + memcpy((char *)pndace + size, ntace, nt_ace_size); 716 + size += nt_ace_size; 717 + aces_size -= nt_ace_size; 718 + ntace = (struct smb_ace *)((char *)ntace + nt_ace_size); 710 719 num_aces++; 711 720 } 712 721 } ··· 889 878 /* Convert permission bits from mode to equivalent CIFS ACL */ 890 879 int build_sec_desc(struct user_namespace *user_ns, 891 880 struct smb_ntsd *pntsd, struct smb_ntsd *ppntsd, 892 - int addition_info, __u32 *secdesclen, 881 + int ppntsd_size, int addition_info, __u32 *secdesclen, 893 882 struct smb_fattr *fattr) 894 883 { 895 884 int rc = 0; ··· 949 938 950 939 if (!ppntsd) { 951 940 set_mode_dacl(user_ns, dacl_ptr, fattr); 952 - } else if (!ppntsd->dacloffset) { 953 - goto out; 954 941 } else { 955 942 struct smb_acl *ppdacl_ptr; 943 + unsigned int dacl_offset = le32_to_cpu(ppntsd->dacloffset); 944 + int ppdacl_size, ntacl_size = ppntsd_size - dacl_offset; 956 945 957 - ppdacl_ptr = (struct smb_acl *)((char *)ppntsd + 958 - le32_to_cpu(ppntsd->dacloffset)); 946 + if (!dacl_offset || 947 + (dacl_offset + sizeof(struct smb_acl) > ppntsd_size)) 948 + goto out; 949 + 950 + ppdacl_ptr = (struct smb_acl *)((char *)ppntsd + dacl_offset); 951 + ppdacl_size = le16_to_cpu(ppdacl_ptr->size); 952 + if (ppdacl_size > ntacl_size || 953 + ppdacl_size < sizeof(struct smb_acl)) 954 + goto out; 955 + 959 956 set_ntacl_dacl(user_ns, dacl_ptr, ppdacl_ptr, 960 - nowner_sid_ptr, ngroup_sid_ptr, fattr); 957 + ntacl_size - sizeof(struct smb_acl), 958 + nowner_sid_ptr, ngroup_sid_ptr, 959 + fattr); 961 960 } 962 961 pntsd->dacloffset = cpu_to_le32(offset); 963 962 offset += le16_to_cpu(dacl_ptr->size); ··· 1001 980 struct smb_sid owner_sid, group_sid; 1002 981 struct dentry *parent = path->dentry->d_parent; 1003 982 struct user_namespace *user_ns = mnt_user_ns(path->mnt); 1004 - int inherited_flags = 0, flags = 0, i, ace_cnt = 0, nt_size = 0; 1005 - int rc = 0, num_aces, dacloffset, pntsd_type, acl_len; 983 + int inherited_flags = 0, flags = 0, i, ace_cnt = 0, nt_size = 0, pdacl_size; 984 + int rc = 0, num_aces, dacloffset, pntsd_type, pntsd_size, acl_len, aces_size; 1006 985 char *aces_base; 1007 986 bool is_dir = S_ISDIR(d_inode(path->dentry)->i_mode); 1008 987 1009 - acl_len = ksmbd_vfs_get_sd_xattr(conn, user_ns, 1010 - parent, &parent_pntsd); 1011 - if (acl_len <= 0) 988 + pntsd_size = ksmbd_vfs_get_sd_xattr(conn, user_ns, 989 + parent, &parent_pntsd); 990 + if (pntsd_size <= 0) 1012 991 return -ENOENT; 1013 992 dacloffset = le32_to_cpu(parent_pntsd->dacloffset); 1014 - if (!dacloffset) { 993 + if (!dacloffset || (dacloffset + sizeof(struct smb_acl) > pntsd_size)) { 1015 994 rc = -EINVAL; 1016 995 goto free_parent_pntsd; 1017 996 } 1018 997 1019 998 parent_pdacl = (struct smb_acl *)((char *)parent_pntsd + dacloffset); 999 + acl_len = pntsd_size - dacloffset; 1020 1000 num_aces = le32_to_cpu(parent_pdacl->num_aces); 1021 1001 pntsd_type = le16_to_cpu(parent_pntsd->type); 1002 + pdacl_size = le16_to_cpu(parent_pdacl->size); 1003 + 1004 + if (pdacl_size > acl_len || pdacl_size < sizeof(struct smb_acl)) { 1005 + rc = -EINVAL; 1006 + goto free_parent_pntsd; 1007 + } 1022 1008 1023 1009 aces_base = kmalloc(sizeof(struct smb_ace) * num_aces * 2, GFP_KERNEL); 1024 1010 if (!aces_base) { ··· 1036 1008 aces = (struct smb_ace *)aces_base; 1037 1009 parent_aces = (struct smb_ace *)((char *)parent_pdacl + 1038 1010 sizeof(struct smb_acl)); 1011 + aces_size = acl_len - sizeof(struct smb_acl); 1039 1012 1040 1013 if (pntsd_type & DACL_AUTO_INHERITED) 1041 1014 inherited_flags = INHERITED_ACE; 1042 1015 1043 1016 for (i = 0; i < num_aces; i++) { 1017 + int pace_size; 1018 + 1019 + if (offsetof(struct smb_ace, access_req) > aces_size) 1020 + break; 1021 + 1022 + pace_size = le16_to_cpu(parent_aces->size); 1023 + if (pace_size > aces_size) 1024 + break; 1025 + 1026 + aces_size -= pace_size; 1027 + 1044 1028 flags = parent_aces->flags; 1045 1029 if (!smb_inherit_flags(flags, is_dir)) 1046 1030 goto pass; ··· 1097 1057 aces = (struct smb_ace *)((char *)aces + le16_to_cpu(aces->size)); 1098 1058 ace_cnt++; 1099 1059 pass: 1100 - parent_aces = 1101 - (struct smb_ace *)((char *)parent_aces + le16_to_cpu(parent_aces->size)); 1060 + parent_aces = (struct smb_ace *)((char *)parent_aces + pace_size); 1102 1061 } 1103 1062 1104 1063 if (nt_size > 0) { ··· 1192 1153 struct smb_ntsd *pntsd = NULL; 1193 1154 struct smb_acl *pdacl; 1194 1155 struct posix_acl *posix_acls; 1195 - int rc = 0, acl_size; 1156 + int rc = 0, pntsd_size, acl_size, aces_size, pdacl_size, dacl_offset; 1196 1157 struct smb_sid sid; 1197 1158 int granted = le32_to_cpu(*pdaccess & ~FILE_MAXIMAL_ACCESS_LE); 1198 1159 struct smb_ace *ace; ··· 1201 1162 struct smb_ace *others_ace = NULL; 1202 1163 struct posix_acl_entry *pa_entry; 1203 1164 unsigned int sid_type = SIDOWNER; 1204 - char *end_of_acl; 1165 + unsigned short ace_size; 1205 1166 1206 1167 ksmbd_debug(SMB, "check permission using windows acl\n"); 1207 - acl_size = ksmbd_vfs_get_sd_xattr(conn, user_ns, 1208 - path->dentry, &pntsd); 1209 - if (acl_size <= 0 || !pntsd || !pntsd->dacloffset) { 1210 - kfree(pntsd); 1211 - return 0; 1212 - } 1168 + pntsd_size = ksmbd_vfs_get_sd_xattr(conn, user_ns, 1169 + path->dentry, &pntsd); 1170 + if (pntsd_size <= 0 || !pntsd) 1171 + goto err_out; 1172 + 1173 + dacl_offset = le32_to_cpu(pntsd->dacloffset); 1174 + if (!dacl_offset || 1175 + (dacl_offset + sizeof(struct smb_acl) > pntsd_size)) 1176 + goto err_out; 1213 1177 1214 1178 pdacl = (struct smb_acl *)((char *)pntsd + le32_to_cpu(pntsd->dacloffset)); 1215 - end_of_acl = ((char *)pntsd) + acl_size; 1216 - if (end_of_acl <= (char *)pdacl) { 1217 - kfree(pntsd); 1218 - return 0; 1219 - } 1179 + acl_size = pntsd_size - dacl_offset; 1180 + pdacl_size = le16_to_cpu(pdacl->size); 1220 1181 1221 - if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size) || 1222 - le16_to_cpu(pdacl->size) < sizeof(struct smb_acl)) { 1223 - kfree(pntsd); 1224 - return 0; 1225 - } 1182 + if (pdacl_size > acl_size || pdacl_size < sizeof(struct smb_acl)) 1183 + goto err_out; 1226 1184 1227 1185 if (!pdacl->num_aces) { 1228 - if (!(le16_to_cpu(pdacl->size) - sizeof(struct smb_acl)) && 1186 + if (!(pdacl_size - sizeof(struct smb_acl)) && 1229 1187 *pdaccess & ~(FILE_READ_CONTROL_LE | FILE_WRITE_DAC_LE)) { 1230 1188 rc = -EACCES; 1231 1189 goto err_out; 1232 1190 } 1233 - kfree(pntsd); 1234 - return 0; 1191 + goto err_out; 1235 1192 } 1236 1193 1237 1194 if (*pdaccess & FILE_MAXIMAL_ACCESS_LE) { ··· 1235 1200 DELETE; 1236 1201 1237 1202 ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl)); 1203 + aces_size = acl_size - sizeof(struct smb_acl); 1238 1204 for (i = 0; i < le32_to_cpu(pdacl->num_aces); i++) { 1205 + if (offsetof(struct smb_ace, access_req) > aces_size) 1206 + break; 1207 + ace_size = le16_to_cpu(ace->size); 1208 + if (ace_size > aces_size) 1209 + break; 1210 + aces_size -= ace_size; 1239 1211 granted |= le32_to_cpu(ace->access_req); 1240 1212 ace = (struct smb_ace *)((char *)ace + le16_to_cpu(ace->size)); 1241 - if (end_of_acl < (char *)ace) 1242 - goto err_out; 1243 1213 } 1244 1214 1245 1215 if (!pdacl->num_aces) ··· 1256 1216 id_to_sid(uid, sid_type, &sid); 1257 1217 1258 1218 ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl)); 1219 + aces_size = acl_size - sizeof(struct smb_acl); 1259 1220 for (i = 0; i < le32_to_cpu(pdacl->num_aces); i++) { 1221 + if (offsetof(struct smb_ace, access_req) > aces_size) 1222 + break; 1223 + ace_size = le16_to_cpu(ace->size); 1224 + if (ace_size > aces_size) 1225 + break; 1226 + aces_size -= ace_size; 1227 + 1260 1228 if (!compare_sids(&sid, &ace->sid) || 1261 1229 !compare_sids(&sid_unix_NFS_mode, &ace->sid)) { 1262 1230 found = 1; ··· 1274 1226 others_ace = ace; 1275 1227 1276 1228 ace = (struct smb_ace *)((char *)ace + le16_to_cpu(ace->size)); 1277 - if (end_of_acl < (char *)ace) 1278 - goto err_out; 1279 1229 } 1280 1230 1281 1231 if (*pdaccess & FILE_MAXIMAL_ACCESS_LE && found) {
+1 -1
fs/ksmbd/smbacl.h
··· 193 193 int parse_sec_desc(struct user_namespace *user_ns, struct smb_ntsd *pntsd, 194 194 int acl_len, struct smb_fattr *fattr); 195 195 int build_sec_desc(struct user_namespace *user_ns, struct smb_ntsd *pntsd, 196 - struct smb_ntsd *ppntsd, int addition_info, 196 + struct smb_ntsd *ppntsd, int ppntsd_size, int addition_info, 197 197 __u32 *secdesclen, struct smb_fattr *fattr); 198 198 int init_acl_state(struct posix_acl_state *state, int cnt); 199 199 void free_acl_state(struct posix_acl_state *state);
+6 -2
fs/ksmbd/vfs.c
··· 481 481 char *buf, size_t count, loff_t *pos, bool sync, 482 482 ssize_t *written) 483 483 { 484 - struct ksmbd_session *sess = work->sess; 485 484 struct file *filp; 486 485 loff_t offset = *pos; 487 486 int err = 0; 488 487 489 - if (sess->conn->connection_type) { 488 + if (work->conn->connection_type) { 490 489 if (!(fp->daccess & FILE_WRITE_DATA_LE)) { 491 490 pr_err("no right to write(%pd)\n", 492 491 fp->filp->f_path.dentry); ··· 1539 1540 } 1540 1541 1541 1542 *pntsd = acl.sd_buf; 1543 + if (acl.sd_size < sizeof(struct smb_ntsd)) { 1544 + pr_err("sd size is invalid\n"); 1545 + goto out_free; 1546 + } 1547 + 1542 1548 (*pntsd)->osidoffset = cpu_to_le32(le32_to_cpu((*pntsd)->osidoffset) - 1543 1549 NDR_NTSD_OFFSETOF); 1544 1550 (*pntsd)->gsidoffset = cpu_to_le32(le32_to_cpu((*pntsd)->gsidoffset) -
+1 -1
fs/ksmbd/vfs_cache.c
··· 569 569 atomic_set(&fp->refcount, 1); 570 570 571 571 fp->filp = filp; 572 - fp->conn = work->sess->conn; 572 + fp->conn = work->conn; 573 573 fp->tcon = work->tcon; 574 574 fp->volatile_id = KSMBD_NO_FID; 575 575 fp->persistent_id = KSMBD_NO_FID;