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 'v7.1-rc1-part3-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull smb client fixes from Steve French:

- Four bug fixes: OOB read in ioctl query info, 3 ACL fixes

- SMB1 Unix extensions mount fix

- Four crypto improvements: move to AES-CMAC library, simpler and faster

- Remove drop_dir_cache to avoid potential crash, and move to /procfs

- Seven SMB3.1.1 compression fixes

* tag 'v7.1-rc1-part3-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6:
smb: client: Drop 'allocate_crypto' arg from smb*_calc_signature()
smb: client: Make generate_key() return void
smb: client: Remove obsolete cmac(aes) allocation
smb: client: Use AES-CMAC library for SMB3 signature calculation
smb: common: add SMB3_COMPRESS_MAX_ALGS
smb: client: compress: add code docs to lz77.c
smb: client: compress: LZ77 optimizations
smb: client: compress: increase LZ77_MATCH_MAX_DIST
smb: client: compress: fix counting in LZ77 match finding
smb: client: compress: fix buffer overrun in lz77_compress()
smb: client: scope end_of_dacl to CIFS_DEBUG2 use in parse_dacl
smb: client: fix (remove) drop_dir_cache module parameter
smb: client: require a full NFS mode SID before reading mode bits
smb: client: validate the whole DACL before rewriting it in cifsacl
smb: client: fix OOB read in smb2_ioctl_query_info QUERY_INFO path
cifs: update internal module version number
smb: client: compress: fix bad encoding on last LZ77 flag
smb: client: fix dir separator in SMB1 UNIX mounts

+437 -391
+1 -1
fs/smb/client/Kconfig
··· 5 5 select NLS 6 6 select NLS_UCS2_UTILS 7 7 select CRYPTO 8 - select CRYPTO_CMAC 9 8 select CRYPTO_AEAD2 10 9 select CRYPTO_CCM 11 10 select CRYPTO_GCM 12 11 select CRYPTO_AES 12 + select CRYPTO_LIB_AES_CBC_MACS 13 13 select CRYPTO_LIB_ARC4 14 14 select CRYPTO_LIB_MD5 15 15 select CRYPTO_LIB_SHA256
+3 -2
fs/smb/client/cached_dir.c
··· 593 593 * Invalidate all cached dirs when a TCON has been reset 594 594 * due to a session loss. 595 595 */ 596 - void invalidate_all_cached_dirs(struct cifs_tcon *tcon) 596 + void invalidate_all_cached_dirs(struct cifs_tcon *tcon, bool sync) 597 597 { 598 598 struct cached_fids *cfids = tcon->cfids; 599 599 struct cached_fid *cfid, *q; ··· 625 625 626 626 /* run laundromat unconditionally now as there might have been previously queued work */ 627 627 mod_delayed_work(cfid_put_wq, &cfids->laundromat_work, 0); 628 - flush_delayed_work(&cfids->laundromat_work); 628 + if (sync) 629 + flush_delayed_work(&cfids->laundromat_work); 629 630 } 630 631 631 632 static void
+1 -1
fs/smb/client/cached_dir.h
··· 90 90 void drop_cached_dir_by_name(const unsigned int xid, struct cifs_tcon *tcon, 91 91 const char *name, struct cifs_sb_info *cifs_sb); 92 92 void close_all_cached_dirs(struct cifs_sb_info *cifs_sb); 93 - void invalidate_all_cached_dirs(struct cifs_tcon *tcon); 93 + void invalidate_all_cached_dirs(struct cifs_tcon *tcon, bool sync); 94 94 bool cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16]); 95 95 96 96 #endif /* _CACHED_DIR_H */
+53 -3
fs/smb/client/cifs_debug.c
··· 306 306 LIST_HEAD(entry); 307 307 308 308 seq_puts(m, "# Version:1\n"); 309 + #ifdef CONFIG_CIFS_DEBUG 310 + seq_puts(m, "# Write 0 to this file to drop all cached directory entries\n"); 311 + #endif /* CONFIG_CIFS_DEBUG */ 309 312 seq_puts(m, "# Format:\n"); 310 313 seq_puts(m, "# <tree id> <sess id> <persistent fid> <lease-key> <path>\n"); 311 314 ··· 355 352 seq_putc(m, '\n'); 356 353 return 0; 357 354 } 355 + 356 + #ifdef CONFIG_CIFS_DEBUG 357 + static int cifs_debug_dirs_proc_open(struct inode *inode, struct file *file) 358 + { 359 + return single_open(file, cifs_debug_dirs_proc_show, NULL); 360 + } 361 + 362 + /* Drop all cached directory entries across all CIFS mounts. */ 363 + static ssize_t cifs_debug_dirs_proc_write(struct file *file, const char __user *buffer, 364 + size_t count, loff_t *ppos) 365 + { 366 + int rc, v; 367 + 368 + rc = kstrtoint_from_user(buffer, count, 10, &v); 369 + if (rc) 370 + return rc; 371 + 372 + if (v == 0) { 373 + struct TCP_Server_Info *server; 374 + struct cifs_ses *ses; 375 + struct cifs_tcon *tcon; 376 + 377 + spin_lock(&cifs_tcp_ses_lock); 378 + list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { 379 + list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { 380 + if (cifs_ses_exiting(ses)) 381 + continue; 382 + list_for_each_entry(tcon, &ses->tcon_list, tcon_list) 383 + invalidate_all_cached_dirs(tcon, false); 384 + } 385 + } 386 + spin_unlock(&cifs_tcp_ses_lock); 387 + } 388 + 389 + return count; 390 + } 391 + 392 + static const struct proc_ops cifs_debug_dirs_proc_ops = { 393 + .proc_open = cifs_debug_dirs_proc_open, 394 + .proc_read = seq_read, 395 + .proc_lseek = seq_lseek, 396 + .proc_release = single_release, 397 + .proc_write = cifs_debug_dirs_proc_write, 398 + }; 399 + #endif /* CONFIG_CIFS_DEBUG */ 358 400 359 401 static __always_inline const char *compression_alg_str(__le16 alg) 360 402 { ··· 933 885 proc_create_single("open_files", 0400, proc_fs_cifs, 934 886 cifs_debug_files_proc_show); 935 887 936 - proc_create_single("open_dirs", 0400, proc_fs_cifs, 937 - cifs_debug_dirs_proc_show); 938 - 888 + #ifdef CONFIG_CIFS_DEBUG 889 + proc_create("open_dirs", 0600, proc_fs_cifs, &cifs_debug_dirs_proc_ops); 890 + #else /* CONFIG_CIFS_DEBUG */ 891 + proc_create_single("open_dirs", 0400, proc_fs_cifs, cifs_debug_dirs_proc_show); 892 + #endif /* !CONFIG_CIFS_DEBUG */ 939 893 proc_create("Stats", 0644, proc_fs_cifs, &cifs_stats_proc_ops); 940 894 proc_create("cifsFYI", 0644, proc_fs_cifs, &cifsFYI_proc_ops); 941 895 proc_create("traceSMB", 0644, proc_fs_cifs, &traceSMB_proc_ops);
+1
fs/smb/client/cifs_unicode.c
··· 6 6 */ 7 7 #include <linux/fs.h> 8 8 #include <linux/slab.h> 9 + #include <linux/unaligned.h> 9 10 #include "cifs_fs_sb.h" 10 11 #include "cifs_unicode.h" 11 12 #include "cifsglob.h"
+85 -30
fs/smb/client/cifsacl.c
··· 758 758 } 759 759 #endif 760 760 761 + static int validate_dacl(struct smb_acl *pdacl, char *end_of_acl) 762 + { 763 + int i, ace_hdr_size, ace_size, min_ace_size; 764 + u16 dacl_size, num_aces; 765 + char *acl_base, *end_of_dacl; 766 + struct smb_ace *pace; 767 + 768 + if (!pdacl) 769 + return 0; 770 + 771 + if (end_of_acl < (char *)pdacl + sizeof(struct smb_acl)) { 772 + cifs_dbg(VFS, "ACL too small to parse DACL\n"); 773 + return -EINVAL; 774 + } 775 + 776 + dacl_size = le16_to_cpu(pdacl->size); 777 + if (dacl_size < sizeof(struct smb_acl) || 778 + end_of_acl < (char *)pdacl + dacl_size) { 779 + cifs_dbg(VFS, "ACL too small to parse DACL\n"); 780 + return -EINVAL; 781 + } 782 + 783 + num_aces = le16_to_cpu(pdacl->num_aces); 784 + if (!num_aces) 785 + return 0; 786 + 787 + ace_hdr_size = offsetof(struct smb_ace, sid) + 788 + offsetof(struct smb_sid, sub_auth); 789 + min_ace_size = ace_hdr_size + sizeof(__le32); 790 + if (num_aces > (dacl_size - sizeof(struct smb_acl)) / min_ace_size) { 791 + cifs_dbg(VFS, "ACL too small to parse DACL\n"); 792 + return -EINVAL; 793 + } 794 + 795 + end_of_dacl = (char *)pdacl + dacl_size; 796 + acl_base = (char *)pdacl; 797 + ace_size = sizeof(struct smb_acl); 798 + 799 + for (i = 0; i < num_aces; ++i) { 800 + if (end_of_dacl - acl_base < ace_size) { 801 + cifs_dbg(VFS, "ACL too small to parse ACE\n"); 802 + return -EINVAL; 803 + } 804 + 805 + pace = (struct smb_ace *)(acl_base + ace_size); 806 + acl_base = (char *)pace; 807 + 808 + if (end_of_dacl - acl_base < ace_hdr_size || 809 + pace->sid.num_subauth == 0 || 810 + pace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES) { 811 + cifs_dbg(VFS, "ACL too small to parse ACE\n"); 812 + return -EINVAL; 813 + } 814 + 815 + ace_size = ace_hdr_size + sizeof(__le32) * pace->sid.num_subauth; 816 + if (end_of_dacl - acl_base < ace_size || 817 + le16_to_cpu(pace->size) < ace_size) { 818 + cifs_dbg(VFS, "ACL too small to parse ACE\n"); 819 + return -EINVAL; 820 + } 821 + 822 + ace_size = le16_to_cpu(pace->size); 823 + if (end_of_dacl - acl_base < ace_size) { 824 + cifs_dbg(VFS, "ACL too small to parse ACE\n"); 825 + return -EINVAL; 826 + } 827 + } 828 + 829 + return 0; 830 + } 831 + 761 832 static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl, 762 833 struct smb_sid *pownersid, struct smb_sid *pgrpsid, 763 834 struct cifs_fattr *fattr, bool mode_from_special_sid) ··· 848 777 return; 849 778 } 850 779 851 - /* validate that we do not go past end of acl */ 852 - if (end_of_acl < (char *)pdacl + sizeof(struct smb_acl) || 853 - end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) { 854 - cifs_dbg(VFS, "ACL too small to parse DACL\n"); 780 + if (validate_dacl(pdacl, end_of_acl)) 855 781 return; 856 - } 857 782 858 783 cifs_dbg(NOISY, "DACL revision %d size %d num aces %d\n", 859 784 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size), ··· 867 800 if (num_aces > 0) { 868 801 umode_t denied_mode = 0; 869 802 870 - if (num_aces > (le16_to_cpu(pdacl->size) - sizeof(struct smb_acl)) / 871 - (offsetof(struct smb_ace, sid) + 872 - offsetof(struct smb_sid, sub_auth) + sizeof(__le16))) 873 - return; 874 - 875 803 ppace = kmalloc_objs(struct smb_ace *, num_aces); 876 804 if (!ppace) 877 805 return; 878 806 879 807 for (i = 0; i < num_aces; ++i) { 880 - if (end_of_acl - acl_base < acl_size) 881 - break; 882 - 883 808 ppace[i] = (struct smb_ace *) (acl_base + acl_size); 884 - acl_base = (char *)ppace[i]; 885 - acl_size = offsetof(struct smb_ace, sid) + 886 - offsetof(struct smb_sid, sub_auth); 887 - 888 - if (end_of_acl - acl_base < acl_size || 889 - ppace[i]->sid.num_subauth == 0 || 890 - ppace[i]->sid.num_subauth > SID_MAX_SUB_AUTHORITIES || 891 - (end_of_acl - acl_base < 892 - acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth) || 893 - (le16_to_cpu(ppace[i]->size) < 894 - acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth)) 895 - break; 896 809 897 810 #ifdef CONFIG_CIFS_DEBUG2 898 - dump_ace(ppace[i], end_of_acl); 811 + dump_ace(ppace[i], 812 + (char *)pdacl + le16_to_cpu(pdacl->size)); 899 813 #endif 900 814 if (mode_from_special_sid && 815 + ppace[i]->sid.num_subauth >= 3 && 901 816 (compare_sids(&(ppace[i]->sid), 902 817 &sid_unix_NFS_mode) == 0)) { 903 818 /* ··· 919 870 (void *)ppace[i], 920 871 sizeof(struct smb_ace)); */ 921 872 873 + acl_base = (char *)ppace[i]; 922 874 acl_size = le16_to_cpu(ppace[i]->size); 923 875 } 924 876 ··· 1343 1293 dacloffset = le32_to_cpu(pntsd->dacloffset); 1344 1294 if (dacloffset) { 1345 1295 dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset); 1346 - if (end_of_acl < (char *)dacl_ptr + le16_to_cpu(dacl_ptr->size)) { 1347 - cifs_dbg(VFS, "Server returned illegal ACL size\n"); 1348 - return -EINVAL; 1349 - } 1296 + rc = validate_dacl(dacl_ptr, end_of_acl); 1297 + if (rc) 1298 + return rc; 1350 1299 } 1351 1300 1352 1301 owner_sid_ptr = (struct smb_sid *)((char *)pntsd + ··· 1711 1662 dacloffset = le32_to_cpu(pntsd->dacloffset); 1712 1663 if (dacloffset) { 1713 1664 dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset); 1665 + rc = validate_dacl(dacl_ptr, (char *)pntsd + secdesclen); 1666 + if (rc) { 1667 + kfree(pntsd); 1668 + cifs_put_tlink(tlink); 1669 + return rc; 1670 + } 1714 1671 if (mode_from_sid) 1715 1672 nsecdesclen += 1716 1673 le16_to_cpu(dacl_ptr->num_aces) * sizeof(struct smb_ace);
+21 -43
fs/smb/client/cifsencrypt.c
··· 22 22 #include <linux/fips.h> 23 23 #include <linux/iov_iter.h> 24 24 #include <crypto/aead.h> 25 + #include <crypto/aes-cbc-macs.h> 25 26 #include <crypto/arc4.h> 26 27 #include <crypto/md5.h> 27 28 #include <crypto/sha2.h> 28 - 29 - static int cifs_sig_update(struct cifs_calc_sig_ctx *ctx, 30 - const u8 *data, size_t len) 31 - { 32 - if (ctx->md5) { 33 - md5_update(ctx->md5, data, len); 34 - return 0; 35 - } 36 - if (ctx->hmac) { 37 - hmac_sha256_update(ctx->hmac, data, len); 38 - return 0; 39 - } 40 - return crypto_shash_update(ctx->shash, data, len); 41 - } 42 - 43 - static int cifs_sig_final(struct cifs_calc_sig_ctx *ctx, u8 *out) 44 - { 45 - if (ctx->md5) { 46 - md5_final(ctx->md5, out); 47 - return 0; 48 - } 49 - if (ctx->hmac) { 50 - hmac_sha256_final(ctx->hmac, out); 51 - return 0; 52 - } 53 - return crypto_shash_final(ctx->shash, out); 54 - } 55 29 56 30 static size_t cifs_sig_step(void *iter_base, size_t progress, size_t len, 57 31 void *priv, void *priv2) 58 32 { 59 33 struct cifs_calc_sig_ctx *ctx = priv; 60 - int ret, *pret = priv2; 61 34 62 - ret = cifs_sig_update(ctx, iter_base, len); 63 - if (ret < 0) { 64 - *pret = ret; 65 - return len; 66 - } 67 - return 0; 35 + if (ctx->md5) 36 + md5_update(ctx->md5, iter_base, len); 37 + else if (ctx->hmac) 38 + hmac_sha256_update(ctx->hmac, iter_base, len); 39 + else 40 + aes_cmac_update(ctx->cmac, iter_base, len); 41 + return 0; /* Return value is length *not* processed, i.e. 0. */ 42 + } 43 + 44 + static void cifs_sig_final(struct cifs_calc_sig_ctx *ctx, u8 *out) 45 + { 46 + if (ctx->md5) 47 + md5_final(ctx->md5, out); 48 + else if (ctx->hmac) 49 + hmac_sha256_final(ctx->hmac, out); 50 + else 51 + aes_cmac_final(ctx->cmac, out); 68 52 } 69 53 70 54 /* ··· 59 75 { 60 76 struct iov_iter tmp_iter = *iter; 61 77 size_t did; 62 - int err; 63 78 64 - did = iterate_and_advance_kernel(&tmp_iter, maxsize, ctx, &err, 79 + did = iterate_and_advance_kernel(&tmp_iter, maxsize, ctx, NULL, 65 80 cifs_sig_step); 66 81 if (did != maxsize) 67 82 return smb_EIO2(smb_eio_trace_sig_iter, did, maxsize); ··· 91 108 if (rc < 0) 92 109 return rc; 93 110 94 - rc = cifs_sig_final(ctx, signature); 95 - if (rc) 96 - cifs_dbg(VFS, "%s: Could not generate hash\n", __func__); 97 - 98 - return rc; 111 + cifs_sig_final(ctx, signature); 112 + return 0; 99 113 } 100 114 101 115 /* Build a proper attribute value/target info pairs blob. ··· 503 523 void 504 524 cifs_crypto_secmech_release(struct TCP_Server_Info *server) 505 525 { 506 - cifs_free_hash(&server->secmech.aes_cmac); 507 - 508 526 if (server->secmech.enc) { 509 527 crypto_free_aead(server->secmech.enc); 510 528 server->secmech.enc = NULL;
-38
fs/smb/client/cifsfs.c
··· 127 127 atomic_t cifs_sillycounter; 128 128 atomic_t cifs_tmpcounter; 129 129 130 - /* 131 - * Write-only module parameter to drop all cached directory entries across 132 - * all CIFS mounts. Echo a non-zero value to trigger. 133 - */ 134 - static void cifs_drop_all_dir_caches(void) 135 - { 136 - struct TCP_Server_Info *server; 137 - struct cifs_ses *ses; 138 - struct cifs_tcon *tcon; 139 - 140 - spin_lock(&cifs_tcp_ses_lock); 141 - list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { 142 - list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { 143 - if (cifs_ses_exiting(ses)) 144 - continue; 145 - list_for_each_entry(tcon, &ses->tcon_list, tcon_list) 146 - invalidate_all_cached_dirs(tcon); 147 - } 148 - } 149 - spin_unlock(&cifs_tcp_ses_lock); 150 - } 151 - 152 - static int cifs_param_set_drop_dir_cache(const char *val, const struct kernel_param *kp) 153 - { 154 - bool bv; 155 - int rc = kstrtobool(val, &bv); 156 - 157 - if (rc) 158 - return rc; 159 - if (bv) 160 - cifs_drop_all_dir_caches(); 161 - return 0; 162 - } 163 - 164 - module_param_call(drop_dir_cache, cifs_param_set_drop_dir_cache, NULL, NULL, 0200); 165 - MODULE_PARM_DESC(drop_dir_cache, "Write 1 to drop all cached directory entries across all CIFS mounts"); 166 - 167 130 #ifdef CONFIG_CIFS_STATS2 168 131 unsigned int slow_rsp_threshold = 1; 169 132 module_param(slow_rsp_threshold, uint, 0644); ··· 2123 2160 MODULE_VERSION(CIFS_VERSION); 2124 2161 MODULE_SOFTDEP("nls"); 2125 2162 MODULE_SOFTDEP("aes"); 2126 - MODULE_SOFTDEP("cmac"); 2127 2163 MODULE_SOFTDEP("aead2"); 2128 2164 MODULE_SOFTDEP("ccm"); 2129 2165 MODULE_SOFTDEP("gcm");
+2 -2
fs/smb/client/cifsfs.h
··· 161 161 #endif /* CONFIG_CIFS_NFSD_EXPORT */ 162 162 163 163 /* when changing internal version - update following two lines at same time */ 164 - #define SMB3_PRODUCT_BUILD 59 165 - #define CIFS_VERSION "2.59" 164 + #define SMB3_PRODUCT_BUILD 60 165 + #define CIFS_VERSION "2.60" 166 166 #endif /* _CIFSFS_H */
+2 -5
fs/smb/client/cifsglob.h
··· 23 23 #include <linux/fcntl.h> 24 24 #include "cifs_fs_sb.h" 25 25 #include "cifsacl.h" 26 - #include <crypto/internal/hash.h> 27 26 #include <uapi/linux/cifs/cifs_mount.h> 28 27 #include "../common/smbglob.h" 29 28 #include "../common/smb2pdu.h" ··· 220 221 char *response; 221 222 }; 222 223 223 - /* crypto hashing related structure/fields, not specific to a sec mech */ 224 + /* encryption related structure/fields, not specific to a sec mech */ 224 225 struct cifs_secmech { 225 - struct shash_desc *aes_cmac; /* block-cipher based MAC function, for SMB3 signatures */ 226 - 227 226 struct crypto_aead *enc; /* smb3 encryption AEAD TFM (AES-CCM and AES-GCM) */ 228 227 struct crypto_aead *dec; /* smb3 decryption AEAD TFM (AES-CCM and AES-GCM) */ 229 228 }; ··· 2321 2324 struct cifs_calc_sig_ctx { 2322 2325 struct md5_ctx *md5; 2323 2326 struct hmac_sha256_ctx *hmac; 2324 - struct shash_desc *shash; 2327 + struct aes_cmac_ctx *cmac; 2325 2328 }; 2326 2329 2327 2330 #define CIFS_RECONN_DELAY_SECS 30
-3
fs/smb/client/cifsproto.h
··· 351 351 enum securityEnum cifs_select_sectype(struct TCP_Server_Info *server, 352 352 enum securityEnum requested); 353 353 354 - int cifs_alloc_hash(const char *name, struct shash_desc **sdesc); 355 - void cifs_free_hash(struct shash_desc **sdesc); 356 - 357 354 int cifs_try_adding_channels(struct cifs_ses *ses); 358 355 int smb3_update_ses_channels(struct cifs_ses *ses, 359 356 struct TCP_Server_Info *server,
+1 -5
fs/smb/client/compress.c
··· 329 329 goto err_free; 330 330 } 331 331 332 - /* 333 - * This is just overprovisioning, as the algorithm will error out if @dst reaches 7/8 334 - * of @slen. 335 - */ 336 - dlen = slen; 332 + dlen = lz77_compressed_alloc_size(slen); 337 333 dst = kvzalloc(dlen, GFP_KERNEL); 338 334 if (!dst) { 339 335 ret = -ENOMEM;
+185 -85
fs/smb/client/compress/lz77.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-only 2 2 /* 3 - * Copyright (C) 2024, SUSE LLC 3 + * Copyright (C) 2024-2026, SUSE LLC 4 4 * 5 5 * Authors: Enzo Matsumiya <ematsumiya@suse.de> 6 6 * ··· 15 15 16 16 /* 17 17 * Compression parameters. 18 + * 19 + * LZ77_MATCH_MAX_DIST: Farthest back a match can be from current position (can be 1 - 8K). 20 + * LZ77_HASH_LOG: 21 + * LZ77_HASH_SIZE: ilog2 hash size (recommended to be 13 - 18, default 15 (hash size 22 + * 32k)). 23 + * LZ77_RSTEP_SIZE: Number of bytes to read from input buffer for hashing and initial 24 + * match check (default 4 bytes, this effectivelly makes this the min 25 + * match len). 26 + * LZ77_MSTEP_SIZE: Number of bytes to extend-compare a found match (default 8 bytes). 27 + * LZ77_SKIP_TRIGGER: ilog2 value for adaptive skipping, i.e. to progressively skip input 28 + * bytes when we can't find matches. Default is 4. 29 + * Higher values (>0) will decrease compression time, but will result 30 + * in worse compression ratio. Lower values will give better 31 + * compression ratio (more matches found), but will increase time. 18 32 */ 19 - #define LZ77_MATCH_MIN_LEN 4 20 - #define LZ77_MATCH_MIN_DIST 1 21 - #define LZ77_MATCH_MAX_DIST SZ_1K 33 + #define LZ77_MATCH_MAX_DIST SZ_8K 22 34 #define LZ77_HASH_LOG 15 23 35 #define LZ77_HASH_SIZE (1 << LZ77_HASH_LOG) 24 - #define LZ77_STEP_SIZE sizeof(u64) 36 + #define LZ77_RSTEP_SIZE sizeof(u32) 37 + #define LZ77_MSTEP_SIZE sizeof(u64) 38 + #define LZ77_SKIP_TRIGGER 4 39 + 40 + #define LZ77_PREFETCH(ptr) __builtin_prefetch((ptr), 0, 3) 41 + #define LZ77_FLAG_MAX 32 25 42 26 43 static __always_inline u8 lz77_read8(const u8 *ptr) 44 + { 45 + return get_unaligned(ptr); 46 + } 47 + 48 + static __always_inline u32 lz77_read32(const u32 *ptr) 27 49 { 28 50 return get_unaligned(ptr); 29 51 } ··· 70 48 put_unaligned_le32(v, ptr); 71 49 } 72 50 73 - static __always_inline u32 lz77_match_len(const void *wnd, const void *cur, const void *end) 51 + static __always_inline u32 lz77_match_len(const void *match, const void *cur, const void *end) 74 52 { 75 53 const void *start = cur; 76 - u64 diff; 77 54 78 55 /* Safe for a do/while because otherwise we wouldn't reach here from the main loop. */ 79 56 do { 80 - diff = lz77_read64(cur) ^ lz77_read64(wnd); 57 + const u64 diff = lz77_read64(cur) ^ lz77_read64(match); 58 + 81 59 if (!diff) { 82 - cur += LZ77_STEP_SIZE; 83 - wnd += LZ77_STEP_SIZE; 60 + cur += LZ77_MSTEP_SIZE; 61 + match += LZ77_MSTEP_SIZE; 84 62 85 63 continue; 86 64 } ··· 89 67 cur += count_trailing_zeros(diff) >> 3; 90 68 91 69 return (cur - start); 92 - } while (likely(cur + LZ77_STEP_SIZE < end)); 70 + } while (likely(cur + LZ77_MSTEP_SIZE <= end)); 93 71 94 - while (cur < end && lz77_read8(cur++) == lz77_read8(wnd++)) 95 - ; 72 + /* Fallback to byte-by-byte comparison for last <8 bytes. */ 73 + while (cur < end && lz77_read8(cur) == lz77_read8(match)) { 74 + cur++; 75 + match++; 76 + } 96 77 97 78 return (cur - start); 98 79 } 99 80 100 - static __always_inline void *lz77_write_match(void *dst, void **nib, u32 dist, u32 len) 81 + /** 82 + * lz77_encode_match() - Match encoding. 83 + * @dst: compressed buffer 84 + * @nib: pointer to an address in @dst 85 + * @dist: match distance 86 + * @len: match length 87 + * 88 + * Assumes all args were previously checked. 89 + * 90 + * Return: @dst advanced to new position 91 + * 92 + * Ref: MS-XCA 2.3.4 "Plain LZ77 Compression Algorithm Details" - "Processing" 93 + */ 94 + static __always_inline void *lz77_encode_match(void *dst, void **nib, u16 dist, u32 len) 101 95 { 102 96 len -= 3; 103 97 dist--; ··· 122 84 if (len < 7) { 123 85 lz77_write16(dst, dist + len); 124 86 125 - return dst + 2; 87 + return dst + sizeof(u16); 126 88 } 127 89 128 90 dist |= 7; 129 91 lz77_write16(dst, dist); 130 - dst += 2; 92 + dst += sizeof(u16); 131 93 len -= 7; 132 94 133 95 if (!*nib) { ··· 157 119 if (len <= 0xffff) { 158 120 lz77_write16(dst, len); 159 121 160 - return dst + 2; 122 + return dst + sizeof(u16); 161 123 } 162 124 163 125 lz77_write16(dst, 0); 164 - dst += 2; 126 + dst += sizeof(u16); 165 127 lz77_write32(dst, len); 166 128 167 - return dst + 4; 129 + return dst + sizeof(u32); 168 130 } 169 131 170 - noinline int lz77_compress(const void *src, u32 slen, void *dst, u32 *dlen) 132 + /** 133 + * lz77_encode_literals() - Literals encoding. 134 + * @start: where to start copying literals (uncompressed buffer) 135 + * @end: when to stop copying (uncompressed buffer) 136 + * @dst: compressed buffer 137 + * @f: pointer to current flag value 138 + * @fc: pointer to current flag count 139 + * @fp: pointer to current flag address 140 + * 141 + * Batch copy literals from @start to @dst, updating flag values accordingly. 142 + * Assumes all args were previously checked. 143 + * 144 + * Return: @dst advanced to new position 145 + * 146 + * MS-XCA 2.3.4 "Plain LZ77 Compression Algorithm Details" - "Processing" 147 + */ 148 + static __always_inline void *lz77_encode_literals(const void *start, const void *end, void *dst, 149 + long *f, u32 *fc, void **fp) 171 150 { 172 - const void *srcp, *end; 173 - void *dstp, *nib, *flag_pos; 174 - u32 flag_count = 0; 175 - long flag = 0; 176 - u64 *htable; 151 + if (start >= end) 152 + return dst; 177 153 178 - srcp = src; 179 - end = src + slen; 154 + do { 155 + const u32 len = umin(end - start, LZ77_FLAG_MAX - *fc); 156 + 157 + memcpy(dst, start, len); 158 + 159 + dst += len; 160 + start += len; 161 + 162 + *f <<= len; 163 + *fc += len; 164 + if (*fc == LZ77_FLAG_MAX) { 165 + lz77_write32(*fp, *f); 166 + *fc = 0; 167 + *fp = dst; 168 + dst += sizeof(u32); 169 + } 170 + } while (start < end); 171 + 172 + return dst; 173 + } 174 + 175 + static __always_inline u32 lz77_hash(const u32 v) 176 + { 177 + return ((v ^ 0x9E3779B9) * 0x85EBCA6B) >> (32 - LZ77_HASH_LOG); 178 + } 179 + 180 + noinline int lz77_compress(const void *src, const u32 slen, void *dst, u32 *dlen) 181 + { 182 + const void *srcp, *rlim, *end, *anchor; 183 + u32 *htable, hash, flag_count = 0; 184 + void *dstp, *nib, *flag_pos; 185 + long flag = 0; 186 + 187 + /* This is probably a bug, so throw a warning. */ 188 + if (WARN_ON_ONCE(*dlen < lz77_compressed_alloc_size(slen))) 189 + return -EINVAL; 190 + 191 + srcp = anchor = src; 192 + end = srcp + slen; /* absolute end */ 193 + rlim = end - LZ77_MSTEP_SIZE; /* read limit (for lz77_match_len()) */ 180 194 dstp = dst; 181 - nib = NULL; 182 195 flag_pos = dstp; 183 - dstp += 4; 196 + dstp += sizeof(u32); 197 + nib = NULL; 184 198 185 199 htable = kvcalloc(LZ77_HASH_SIZE, sizeof(*htable), GFP_KERNEL); 186 200 if (!htable) 187 201 return -ENOMEM; 188 202 189 - /* Main loop. */ 203 + LZ77_PREFETCH(srcp + LZ77_RSTEP_SIZE); 204 + 205 + /* 206 + * Adjust @srcp so we don't get a false positive match on first iteration. 207 + * Then prepare hash for first loop iteration (don't advance @srcp again). 208 + */ 209 + hash = lz77_hash(lz77_read32(srcp++)); 210 + htable[hash] = 0; 211 + hash = lz77_hash(lz77_read32(srcp)); 212 + 213 + /* 214 + * Main loop. 215 + * 216 + * @dlen is >= lz77_compressed_alloc_size(), so run without bound-checking @dstp. 217 + * 218 + * This code was crafted in a way to best utilise fetch-decode-execute CPU flow. 219 + * Any attempt to optimize it, or even organize it, can lead to huge performance loss. 220 + */ 190 221 do { 191 - u32 dist, len = 0; 192 - const void *wnd; 193 - u64 hash; 222 + const void *match, *next = srcp; 223 + u32 len, step = 1, skip = 1U << LZ77_SKIP_TRIGGER; 194 224 195 - hash = ((lz77_read64(srcp) << 24) * 889523592379ULL) >> (64 - LZ77_HASH_LOG); 196 - wnd = src + htable[hash]; 197 - htable[hash] = srcp - src; 198 - dist = srcp - wnd; 225 + /* Match finding (hot path -- don't change the read/check/write order). */ 226 + do { 227 + const u32 cur_hash = hash; 199 228 200 - if (dist && dist < LZ77_MATCH_MAX_DIST) 201 - len = lz77_match_len(wnd, srcp, end); 229 + srcp = next; 230 + next += step; 202 231 203 - if (len < LZ77_MATCH_MIN_LEN) { 204 - lz77_write8(dstp, lz77_read8(srcp)); 232 + /* 233 + * Adaptive skipping. 234 + * 235 + * Increment @step every (1 << LZ77_SKIP_TRIGGER, 16 in our case) bytes 236 + * without a match. 237 + * Reset to 1 when a match is found. 238 + */ 239 + step = (skip++ >> LZ77_SKIP_TRIGGER); 240 + if (unlikely(next > rlim)) 241 + goto out; 205 242 206 - dstp++; 207 - srcp++; 208 - 209 - flag <<= 1; 210 - flag_count++; 211 - if (flag_count == 32) { 212 - lz77_write32(flag_pos, flag); 213 - flag_count = 0; 214 - flag_pos = dstp; 215 - dstp += 4; 216 - } 217 - 218 - continue; 219 - } 243 + hash = lz77_hash(lz77_read32(next)); 244 + match = src + htable[cur_hash]; 245 + htable[cur_hash] = srcp - src; 246 + } while (likely(match + LZ77_MATCH_MAX_DIST < srcp) || 247 + lz77_read32(match) != lz77_read32(srcp)); 220 248 221 249 /* 222 - * Bail out if @dstp reached >= 7/8 of @slen -- already compressed badly, not worth 223 - * going further. 250 + * Match found. Warm/cold path; begin parsing @srcp and writing to @dstp: 251 + * - flush literals 252 + * - compute match length (*) 253 + * - encode match 254 + * 255 + * (*) Current minimum match length is defined by the memory read size above, so 256 + * here we already know that we have 4 matching bytes, but it's just faster to 257 + * redundantly compute it again in lz77_match_len() than to adjust pointers/len. 224 258 */ 225 - if (unlikely(dstp - dst >= slen - (slen >> 3))) { 226 - *dlen = slen; 227 - goto out; 228 - } 229 - 230 - dstp = lz77_write_match(dstp, &nib, dist, len); 259 + dstp = lz77_encode_literals(anchor, srcp, dstp, &flag, &flag_count, &flag_pos); 260 + len = lz77_match_len(match, srcp, end); 261 + dstp = lz77_encode_match(dstp, &nib, srcp - match, len); 231 262 srcp += len; 263 + anchor = srcp; 264 + 265 + LZ77_PREFETCH(srcp); 232 266 233 267 flag = (flag << 1) | 1; 234 268 flag_count++; 235 - if (flag_count == 32) { 269 + if (flag_count == LZ77_FLAG_MAX) { 236 270 lz77_write32(flag_pos, flag); 237 271 flag_count = 0; 238 272 flag_pos = dstp; 239 - dstp += 4; 273 + dstp += sizeof(u32); 240 274 } 241 - } while (likely(srcp + LZ77_STEP_SIZE < end)); 242 275 243 - while (srcp < end) { 244 - u32 c = umin(end - srcp, 32 - flag_count); 276 + if (unlikely(srcp > rlim)) 277 + break; 245 278 246 - memcpy(dstp, srcp, c); 279 + /* Prepare for next loop. */ 280 + hash = lz77_hash(lz77_read32(srcp)); 281 + } while (srcp < end); 282 + out: 283 + dstp = lz77_encode_literals(anchor, end, dstp, &flag, &flag_count, &flag_pos); 247 284 248 - dstp += c; 249 - srcp += c; 250 - 251 - flag <<= c; 252 - flag_count += c; 253 - if (flag_count == 32) { 254 - lz77_write32(flag_pos, flag); 255 - flag_count = 0; 256 - flag_pos = dstp; 257 - dstp += 4; 258 - } 259 - } 260 - 261 - flag <<= (32 - flag_count); 262 - flag |= (1 << (32 - flag_count)) - 1; 285 + flag_count = LZ77_FLAG_MAX - flag_count; 286 + flag <<= flag_count; 287 + flag |= (1UL << flag_count) - 1; 263 288 lz77_write32(flag_pos, flag); 264 289 265 290 *dlen = dstp - dst; 266 - out: 267 291 kvfree(htable); 268 292 269 293 if (*dlen < slen)
+30 -2
fs/smb/client/compress/lz77.h
··· 1 1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 2 /* 3 - * Copyright (C) 2024, SUSE LLC 3 + * Copyright (C) 2024-2026, SUSE LLC 4 4 * 5 5 * Authors: Enzo Matsumiya <ematsumiya@suse.de> 6 6 * ··· 11 11 12 12 #include <linux/kernel.h> 13 13 14 - int lz77_compress(const void *src, u32 slen, void *dst, u32 *dlen); 14 + /** 15 + * lz77_compressed_alloc_size() - Compute compressed buffer size. 16 + * @size: uncompressed (src) size 17 + * 18 + * Compute allocation size for the compressed buffer based on uncompressed size. 19 + * Accounts for metadata and overprovision for the worst case scenario. 20 + * 21 + * LZ77 metadata is a 4-byte flag that is written: 22 + * - on dst begin (pos 0) 23 + * - every 32 literals or matches 24 + * - on end-of-stream (possibly, if last write was another flag) 25 + * 26 + * Worst case scenario is an all-literal compression, which means: 27 + * metadata bytes = 4 + ((@size / 32) * 4) + 4, or, simplified, (@size >> 3) + 8 28 + * 29 + * The worst case scenario rarely happens, but such overprovisioning also allows lz77_compress() 30 + * main loop to run without ever bound checking dst, which is a huge perf improvement, while also 31 + * being safe when compression goes bad. 32 + * 33 + * Return: required (*) allocation size for compressed buffer. 34 + * 35 + * (*) checked once in the beginning of lz77_compress() 36 + */ 37 + static __always_inline u32 lz77_compressed_alloc_size(const u32 size) 38 + { 39 + return size + (size >> 3) + 8; 40 + } 41 + 42 + int lz77_compress(const void *src, const u32 slen, void *dst, u32 *dlen); 15 43 #endif /* _SMB_COMPRESS_LZ77_H */
+5 -5
fs/smb/client/connect.c
··· 3609 3609 server = mnt_ctx->server; 3610 3610 ctx = mnt_ctx->fs_ctx; 3611 3611 cifs_sb = mnt_ctx->cifs_sb; 3612 - sbflags = cifs_sb_flags(cifs_sb); 3613 3612 3614 3613 /* search for existing tcon to this server share */ 3615 3614 tcon = cifs_get_tcon(mnt_ctx->ses, ctx); ··· 3623 3624 * path (i.e., do not remap / and \ and do not map any special characters) 3624 3625 */ 3625 3626 if (tcon->posix_extensions) { 3626 - sbflags |= CIFS_MOUNT_POSIX_PATHS; 3627 - sbflags &= ~(CIFS_MOUNT_MAP_SFM_CHR | 3628 - CIFS_MOUNT_MAP_SPECIAL_CHR); 3627 + atomic_or(CIFS_MOUNT_POSIX_PATHS, &cifs_sb->mnt_cifs_flags); 3628 + atomic_andnot(CIFS_MOUNT_MAP_SFM_CHR | 3629 + CIFS_MOUNT_MAP_SPECIAL_CHR, 3630 + &cifs_sb->mnt_cifs_flags); 3629 3631 } 3630 3632 3631 3633 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY ··· 3650 3650 #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 3651 3651 tcon->unix_ext = 0; /* server does not support them */ 3652 3652 3653 + sbflags = cifs_sb_flags(cifs_sb); 3653 3654 /* do not care if a following call succeed - informational */ 3654 3655 if (!tcon->pipe && server->ops->qfs_tcon) { 3655 3656 server->ops->qfs_tcon(mnt_ctx->xid, tcon, cifs_sb); ··· 3675 3674 3676 3675 out: 3677 3676 mnt_ctx->tcon = tcon; 3678 - atomic_set(&cifs_sb->mnt_cifs_flags, sbflags); 3679 3677 return rc; 3680 3678 } 3681 3679
+1 -1
fs/smb/client/file.c
··· 393 393 } 394 394 spin_unlock(&tcon->open_file_lock); 395 395 396 - invalidate_all_cached_dirs(tcon); 396 + invalidate_all_cached_dirs(tcon, true); 397 397 spin_lock(&tcon->tc_lock); 398 398 if (tcon->status == TID_IN_FILES_INVALIDATE) 399 399 tcon->status = TID_NEED_TCON;
-57
fs/smb/client/misc.c
··· 785 785 return rc; 786 786 } 787 787 788 - /** 789 - * cifs_alloc_hash - allocate hash and hash context together 790 - * @name: The name of the crypto hash algo 791 - * @sdesc: SHASH descriptor where to put the pointer to the hash TFM 792 - * 793 - * The caller has to make sure @sdesc is initialized to either NULL or 794 - * a valid context. It can be freed via cifs_free_hash(). 795 - */ 796 - int 797 - cifs_alloc_hash(const char *name, struct shash_desc **sdesc) 798 - { 799 - int rc = 0; 800 - struct crypto_shash *alg = NULL; 801 - 802 - if (*sdesc) 803 - return 0; 804 - 805 - alg = crypto_alloc_shash(name, 0, 0); 806 - if (IS_ERR(alg)) { 807 - cifs_dbg(VFS, "Could not allocate shash TFM '%s'\n", name); 808 - rc = PTR_ERR(alg); 809 - *sdesc = NULL; 810 - return rc; 811 - } 812 - 813 - *sdesc = kmalloc(sizeof(struct shash_desc) + crypto_shash_descsize(alg), GFP_KERNEL); 814 - if (*sdesc == NULL) { 815 - cifs_dbg(VFS, "no memory left to allocate shash TFM '%s'\n", name); 816 - crypto_free_shash(alg); 817 - return -ENOMEM; 818 - } 819 - 820 - (*sdesc)->tfm = alg; 821 - return 0; 822 - } 823 - 824 - /** 825 - * cifs_free_hash - free hash and hash context together 826 - * @sdesc: Where to find the pointer to the hash TFM 827 - * 828 - * Freeing a NULL descriptor is safe. 829 - */ 830 - void 831 - cifs_free_hash(struct shash_desc **sdesc) 832 - { 833 - if (unlikely(!sdesc) || !*sdesc) 834 - return; 835 - 836 - if ((*sdesc)->tfm) { 837 - crypto_free_shash((*sdesc)->tfm); 838 - (*sdesc)->tfm = NULL; 839 - } 840 - 841 - kfree_sensitive(*sdesc); 842 - *sdesc = NULL; 843 - } 844 - 845 788 void extract_unc_hostname(const char *unc, const char **h, size_t *len) 846 789 { 847 790 const char *end;
-11
fs/smb/client/sess.c
··· 595 595 spin_unlock(&ses->chan_lock); 596 596 597 597 mutex_lock(&ses->session_mutex); 598 - /* 599 - * We need to allocate the server crypto now as we will need 600 - * to sign packets before we generate the channel signing key 601 - * (we sign with the session key) 602 - */ 603 - rc = smb3_crypto_shash_allocate(chan->server); 604 - if (rc) { 605 - cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__); 606 - mutex_unlock(&ses->session_mutex); 607 - goto out; 608 - } 609 598 610 599 rc = cifs_negotiate_protocol(xid, ses, chan->server); 611 600 if (!rc)
+8 -11
fs/smb/client/smb1ops.c
··· 49 49 50 50 if (!CIFSSMBQFSUnixInfo(xid, tcon)) { 51 51 __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability); 52 - unsigned int sbflags; 53 52 54 53 cifs_dbg(FYI, "unix caps which server supports %lld\n", cap); 55 54 /* ··· 75 76 if (cap & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP) 76 77 cifs_dbg(VFS, "per-share encryption not supported yet\n"); 77 78 78 - if (cifs_sb) 79 - sbflags = cifs_sb_flags(cifs_sb); 80 - 81 79 cap &= CIFS_UNIX_CAP_MASK; 82 80 if (ctx && ctx->no_psx_acl) 83 81 cap &= ~CIFS_UNIX_POSIX_ACL_CAP; 84 82 else if (CIFS_UNIX_POSIX_ACL_CAP & cap) { 85 83 cifs_dbg(FYI, "negotiated posix acl support\n"); 86 - if (cifs_sb) 87 - sbflags |= CIFS_MOUNT_POSIXACL; 84 + if (cifs_sb) { 85 + atomic_or(CIFS_MOUNT_POSIXACL, 86 + &cifs_sb->mnt_cifs_flags); 87 + } 88 88 } 89 89 90 90 if (ctx && ctx->posix_paths == 0) 91 91 cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP; 92 92 else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) { 93 93 cifs_dbg(FYI, "negotiate posix pathnames\n"); 94 - if (cifs_sb) 95 - sbflags |= CIFS_MOUNT_POSIX_PATHS; 94 + if (cifs_sb) { 95 + atomic_or(CIFS_MOUNT_POSIX_PATHS, 96 + &cifs_sb->mnt_cifs_flags); 97 + } 96 98 } 97 - 98 - if (cifs_sb) 99 - atomic_set(&cifs_sb->mnt_cifs_flags, sbflags); 100 99 101 100 cifs_dbg(FYI, "Negotiate caps 0x%x\n", (int)cap); 102 101 #ifdef CONFIG_CIFS_DEBUG2
+6
fs/smb/client/smb2ops.c
··· 1783 1783 qi_rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base; 1784 1784 if (le32_to_cpu(qi_rsp->OutputBufferLength) < qi.input_buffer_length) 1785 1785 qi.input_buffer_length = le32_to_cpu(qi_rsp->OutputBufferLength); 1786 + if (qi.input_buffer_length > 0 && 1787 + struct_size(qi_rsp, Buffer, qi.input_buffer_length) > 1788 + rsp_iov[1].iov_len) { 1789 + rc = -EFAULT; 1790 + goto out; 1791 + } 1786 1792 if (copy_to_user(&pqi->input_buffer_length, 1787 1793 &qi.input_buffer_length, 1788 1794 sizeof(qi.input_buffer_length))) {
+1 -1
fs/smb/client/smb2pdu.c
··· 2257 2257 } 2258 2258 spin_unlock(&ses->chan_lock); 2259 2259 2260 - invalidate_all_cached_dirs(tcon); 2260 + invalidate_all_cached_dirs(tcon, true); 2261 2261 2262 2262 rc = smb2_plain_req_init(SMB2_TREE_DISCONNECT, tcon, server, 2263 2263 (void **) &req,
-1
fs/smb/client/smb2proto.h
··· 257 257 char *data); 258 258 void smb2_copy_fs_info_to_kstatfs(struct smb2_fs_full_size_info *pfs_inf, 259 259 struct kstatfs *kst); 260 - int smb3_crypto_shash_allocate(struct TCP_Server_Info *server); 261 260 void smb311_update_preauth_hash(struct cifs_ses *ses, 262 261 struct TCP_Server_Info *server, 263 262 struct kvec *iov, int nvec);
+29 -84
fs/smb/client/smb2transport.c
··· 19 19 #include <linux/mempool.h> 20 20 #include <linux/highmem.h> 21 21 #include <crypto/aead.h> 22 + #include <crypto/aes-cbc-macs.h> 22 23 #include <crypto/sha2.h> 23 24 #include <crypto/utils.h> 24 25 #include "cifsglob.h" ··· 28 27 #include "cifs_debug.h" 29 28 #include "../common/smb2status.h" 30 29 #include "smb2glob.h" 31 - 32 - int 33 - smb3_crypto_shash_allocate(struct TCP_Server_Info *server) 34 - { 35 - struct cifs_secmech *p = &server->secmech; 36 - 37 - return cifs_alloc_hash("cmac(aes)", &p->aes_cmac); 38 - } 39 30 40 31 static 41 32 int smb3_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key) ··· 204 211 } 205 212 206 213 static int 207 - smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server, 208 - bool allocate_crypto) 214 + smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) 209 215 { 210 216 int rc; 211 217 unsigned char smb2_signature[SMB2_HMACSHA256_SIZE]; ··· 250 258 return rc; 251 259 } 252 260 253 - static int generate_key(struct cifs_ses *ses, struct kvec label, 254 - struct kvec context, __u8 *key, unsigned int key_size) 261 + static void generate_key(struct cifs_ses *ses, struct kvec label, 262 + struct kvec context, __u8 *key, unsigned int key_size) 255 263 { 256 264 unsigned char zero = 0x0; 257 265 __u8 i[4] = {0, 0, 0, 1}; 258 266 __u8 L128[4] = {0, 0, 0, 128}; 259 267 __u8 L256[4] = {0, 0, 1, 0}; 260 - int rc = 0; 261 268 unsigned char prfhash[SMB2_HMACSHA256_SIZE]; 262 269 struct TCP_Server_Info *server = ses->server; 263 270 struct hmac_sha256_ctx hmac_ctx; 264 271 265 272 memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE); 266 273 memset(key, 0x0, key_size); 267 - 268 - rc = smb3_crypto_shash_allocate(server); 269 - if (rc) { 270 - cifs_server_dbg(VFS, "%s: crypto alloc failed\n", __func__); 271 - return rc; 272 - } 273 274 274 275 hmac_sha256_init_usingrawkey(&hmac_ctx, ses->auth_key.response, 275 276 SMB2_NTLMV2_SESSKEY_SIZE); ··· 280 295 hmac_sha256_final(&hmac_ctx, prfhash); 281 296 282 297 memcpy(key, prfhash, key_size); 283 - return 0; 284 298 } 285 299 286 300 struct derivation { ··· 298 314 struct TCP_Server_Info *server, 299 315 const struct derivation_triplet *ptriplet) 300 316 { 301 - int rc; 302 317 bool is_binding = false; 303 318 int chan_index = 0; 304 319 ··· 328 345 */ 329 346 330 347 if (is_binding) { 331 - rc = generate_key(ses, ptriplet->signing.label, 332 - ptriplet->signing.context, 333 - ses->chans[chan_index].signkey, 334 - SMB3_SIGN_KEY_SIZE); 335 - if (rc) 336 - return rc; 348 + generate_key(ses, ptriplet->signing.label, 349 + ptriplet->signing.context, 350 + ses->chans[chan_index].signkey, 351 + SMB3_SIGN_KEY_SIZE); 337 352 } else { 338 - rc = generate_key(ses, ptriplet->signing.label, 339 - ptriplet->signing.context, 340 - ses->smb3signingkey, 341 - SMB3_SIGN_KEY_SIZE); 342 - if (rc) 343 - return rc; 353 + generate_key(ses, ptriplet->signing.label, 354 + ptriplet->signing.context, 355 + ses->smb3signingkey, SMB3_SIGN_KEY_SIZE); 344 356 345 357 /* safe to access primary channel, since it will never go away */ 346 358 spin_lock(&ses->chan_lock); ··· 343 365 SMB3_SIGN_KEY_SIZE); 344 366 spin_unlock(&ses->chan_lock); 345 367 346 - rc = generate_key(ses, ptriplet->encryption.label, 347 - ptriplet->encryption.context, 348 - ses->smb3encryptionkey, 349 - SMB3_ENC_DEC_KEY_SIZE); 350 - if (rc) 351 - return rc; 352 - rc = generate_key(ses, ptriplet->decryption.label, 353 - ptriplet->decryption.context, 354 - ses->smb3decryptionkey, 355 - SMB3_ENC_DEC_KEY_SIZE); 356 - if (rc) 357 - return rc; 368 + generate_key(ses, ptriplet->encryption.label, 369 + ptriplet->encryption.context, 370 + ses->smb3encryptionkey, SMB3_ENC_DEC_KEY_SIZE); 371 + generate_key(ses, ptriplet->decryption.label, 372 + ptriplet->decryption.context, 373 + ses->smb3decryptionkey, SMB3_ENC_DEC_KEY_SIZE); 358 374 } 359 375 360 376 #ifdef CONFIG_CIFS_DEBUG_DUMP_KEYS ··· 377 405 SMB3_GCM128_CRYPTKEY_SIZE, ses->smb3decryptionkey); 378 406 } 379 407 #endif 380 - return rc; 408 + return 0; 381 409 } 382 410 383 411 int ··· 439 467 } 440 468 441 469 static int 442 - smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server, 443 - bool allocate_crypto) 470 + smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) 444 471 { 445 472 int rc; 446 473 unsigned char smb3_signature[SMB2_CMACAES_SIZE]; 447 474 struct kvec *iov = rqst->rq_iov; 448 475 struct smb2_hdr *shdr = (struct smb2_hdr *)iov[0].iov_base; 449 - struct shash_desc *shash = NULL; 476 + struct aes_cmac_key cmac_key; 477 + struct aes_cmac_ctx cmac_ctx; 450 478 struct smb_rqst drqst; 451 479 u8 key[SMB3_SIGN_KEY_SIZE]; 452 480 453 481 if (server->vals->protocol_id <= SMB21_PROT_ID) 454 - return smb2_calc_signature(rqst, server, allocate_crypto); 482 + return smb2_calc_signature(rqst, server); 455 483 456 484 rc = smb3_get_sign_key(le64_to_cpu(shdr->SessionId), server, key); 457 485 if (unlikely(rc)) { ··· 459 487 return rc; 460 488 } 461 489 462 - if (allocate_crypto) { 463 - rc = cifs_alloc_hash("cmac(aes)", &shash); 464 - if (rc) 465 - return rc; 466 - } else { 467 - shash = server->secmech.aes_cmac; 468 - } 469 - 470 490 memset(smb3_signature, 0x0, SMB2_CMACAES_SIZE); 471 491 memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE); 472 492 473 - rc = crypto_shash_setkey(shash->tfm, key, SMB2_CMACAES_SIZE); 493 + rc = aes_cmac_preparekey(&cmac_key, key, SMB2_CMACAES_SIZE); 474 494 if (rc) { 475 495 cifs_server_dbg(VFS, "%s: Could not set key for cmac aes\n", __func__); 476 - goto out; 496 + return rc; 477 497 } 478 498 479 - /* 480 - * we already allocate aes_cmac when we init smb3 signing key, 481 - * so unlike smb2 case we do not have to check here if secmech are 482 - * initialized 483 - */ 484 - rc = crypto_shash_init(shash); 485 - if (rc) { 486 - cifs_server_dbg(VFS, "%s: Could not init cmac aes\n", __func__); 487 - goto out; 488 - } 499 + aes_cmac_init(&cmac_ctx, &cmac_key); 489 500 490 501 /* 491 502 * For SMB2+, __cifs_calc_signature() expects to sign only the actual ··· 479 524 */ 480 525 drqst = *rqst; 481 526 if (drqst.rq_nvec >= 2 && iov[0].iov_len == 4) { 482 - rc = crypto_shash_update(shash, iov[0].iov_base, 483 - iov[0].iov_len); 484 - if (rc) { 485 - cifs_server_dbg(VFS, "%s: Could not update with payload\n", 486 - __func__); 487 - goto out; 488 - } 527 + aes_cmac_update(&cmac_ctx, iov[0].iov_base, iov[0].iov_len); 489 528 drqst.rq_iov++; 490 529 drqst.rq_nvec--; 491 530 } 492 531 493 532 rc = __cifs_calc_signature( 494 533 &drqst, server, smb3_signature, 495 - &(struct cifs_calc_sig_ctx){ .shash = shash }); 534 + &(struct cifs_calc_sig_ctx){ .cmac = &cmac_ctx }); 496 535 if (!rc) 497 536 memcpy(shdr->Signature, smb3_signature, SMB2_SIGNATURE_SIZE); 498 - 499 - out: 500 - if (allocate_crypto) 501 - cifs_free_hash(&shash); 502 537 return rc; 503 538 } 504 539 ··· 522 577 return 0; 523 578 } 524 579 525 - return smb3_calc_signature(rqst, server, false); 580 + return smb3_calc_signature(rqst, server); 526 581 } 527 582 528 583 int ··· 558 613 559 614 memset(shdr->Signature, 0, SMB2_SIGNATURE_SIZE); 560 615 561 - rc = smb3_calc_signature(rqst, server, true); 616 + rc = smb3_calc_signature(rqst, server); 562 617 563 618 if (rc) 564 619 return rc;
+2
fs/smb/common/smb2pdu.h
··· 510 510 /* Pattern scanning algorithm See MS-SMB2 3.1.4.4.1 */ 511 511 #define SMB3_COMPRESS_PATTERN cpu_to_le16(0x0004) /* Pattern_V1 */ 512 512 #define SMB3_COMPRESS_LZ4 cpu_to_le16(0x0005) 513 + /* Account for NONE for easier array indexing */ 514 + #define SMB3_COMPRESS_MAX_ALGS 6 513 515 514 516 /* Compression Flags */ 515 517 #define SMB2_COMPRESSION_CAPABILITIES_FLAG_NONE cpu_to_le32(0x00000000)