Skip to content

Commit d0ed69f

Browse files
committed
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
2 parents e728258 + a83307f commit d0ed69f

24 files changed

Lines changed: 438 additions & 392 deletions

fs/smb/client/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ config CIFS
55
select NLS
66
select NLS_UCS2_UTILS
77
select CRYPTO
8-
select CRYPTO_CMAC
98
select CRYPTO_AEAD2
109
select CRYPTO_CCM
1110
select CRYPTO_GCM
1211
select CRYPTO_AES
12+
select CRYPTO_LIB_AES_CBC_MACS
1313
select CRYPTO_LIB_ARC4
1414
select CRYPTO_LIB_MD5
1515
select CRYPTO_LIB_SHA256

fs/smb/client/cached_dir.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,7 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb)
593593
* Invalidate all cached dirs when a TCON has been reset
594594
* due to a session loss.
595595
*/
596-
void invalidate_all_cached_dirs(struct cifs_tcon *tcon)
596+
void invalidate_all_cached_dirs(struct cifs_tcon *tcon, bool sync)
597597
{
598598
struct cached_fids *cfids = tcon->cfids;
599599
struct cached_fid *cfid, *q;
@@ -625,7 +625,8 @@ void invalidate_all_cached_dirs(struct cifs_tcon *tcon)
625625

626626
/* run laundromat unconditionally now as there might have been previously queued work */
627627
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);
629630
}
630631

631632
static void

fs/smb/client/cached_dir.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ void close_cached_dir(struct cached_fid *cfid);
9090
void drop_cached_dir_by_name(const unsigned int xid, struct cifs_tcon *tcon,
9191
const char *name, struct cifs_sb_info *cifs_sb);
9292
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);
9494
bool cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16]);
9595

9696
#endif /* _CACHED_DIR_H */

fs/smb/client/cifs_debug.c

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,9 @@ static int cifs_debug_dirs_proc_show(struct seq_file *m, void *v)
306306
LIST_HEAD(entry);
307307

308308
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 */
309312
seq_puts(m, "# Format:\n");
310313
seq_puts(m, "# <tree id> <sess id> <persistent fid> <lease-key> <path>\n");
311314

@@ -353,6 +356,51 @@ static int cifs_debug_dirs_proc_show(struct seq_file *m, void *v)
353356
return 0;
354357
}
355358

359+
#ifdef CONFIG_CIFS_DEBUG
360+
static int cifs_debug_dirs_proc_open(struct inode *inode, struct file *file)
361+
{
362+
return single_open(file, cifs_debug_dirs_proc_show, NULL);
363+
}
364+
365+
/* Drop all cached directory entries across all CIFS mounts. */
366+
static ssize_t cifs_debug_dirs_proc_write(struct file *file, const char __user *buffer,
367+
size_t count, loff_t *ppos)
368+
{
369+
int rc, v;
370+
371+
rc = kstrtoint_from_user(buffer, count, 10, &v);
372+
if (rc)
373+
return rc;
374+
375+
if (v == 0) {
376+
struct TCP_Server_Info *server;
377+
struct cifs_ses *ses;
378+
struct cifs_tcon *tcon;
379+
380+
spin_lock(&cifs_tcp_ses_lock);
381+
list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
382+
list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
383+
if (cifs_ses_exiting(ses))
384+
continue;
385+
list_for_each_entry(tcon, &ses->tcon_list, tcon_list)
386+
invalidate_all_cached_dirs(tcon, false);
387+
}
388+
}
389+
spin_unlock(&cifs_tcp_ses_lock);
390+
}
391+
392+
return count;
393+
}
394+
395+
static const struct proc_ops cifs_debug_dirs_proc_ops = {
396+
.proc_open = cifs_debug_dirs_proc_open,
397+
.proc_read = seq_read,
398+
.proc_lseek = seq_lseek,
399+
.proc_release = single_release,
400+
.proc_write = cifs_debug_dirs_proc_write,
401+
};
402+
#endif /* CONFIG_CIFS_DEBUG */
403+
356404
static __always_inline const char *compression_alg_str(__le16 alg)
357405
{
358406
switch (alg) {
@@ -885,9 +933,11 @@ cifs_proc_init(void)
885933
proc_create_single("open_files", 0400, proc_fs_cifs,
886934
cifs_debug_files_proc_show);
887935

888-
proc_create_single("open_dirs", 0400, proc_fs_cifs,
889-
cifs_debug_dirs_proc_show);
890-
936+
#ifdef CONFIG_CIFS_DEBUG
937+
proc_create("open_dirs", 0600, proc_fs_cifs, &cifs_debug_dirs_proc_ops);
938+
#else /* CONFIG_CIFS_DEBUG */
939+
proc_create_single("open_dirs", 0400, proc_fs_cifs, cifs_debug_dirs_proc_show);
940+
#endif /* !CONFIG_CIFS_DEBUG */
891941
proc_create("Stats", 0644, proc_fs_cifs, &cifs_stats_proc_ops);
892942
proc_create("cifsFYI", 0644, proc_fs_cifs, &cifsFYI_proc_ops);
893943
proc_create("traceSMB", 0644, proc_fs_cifs, &traceSMB_proc_ops);

fs/smb/client/cifs_unicode.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77
#include <linux/fs.h>
88
#include <linux/slab.h>
9+
#include <linux/unaligned.h>
910
#include "cifs_fs_sb.h"
1011
#include "cifs_unicode.h"
1112
#include "cifsglob.h"

fs/smb/client/cifsacl.c

Lines changed: 85 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,77 @@ static void dump_ace(struct smb_ace *pace, char *end_of_acl)
758758
}
759759
#endif
760760

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+
761832
static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl,
762833
struct smb_sid *pownersid, struct smb_sid *pgrpsid,
763834
struct cifs_fattr *fattr, bool mode_from_special_sid)
@@ -777,12 +848,8 @@ static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl,
777848
return;
778849
}
779850

780-
/* validate that we do not go past end of acl */
781-
if (end_of_acl < (char *)pdacl + sizeof(struct smb_acl) ||
782-
end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
783-
cifs_dbg(VFS, "ACL too small to parse DACL\n");
851+
if (validate_dacl(pdacl, end_of_acl))
784852
return;
785-
}
786853

787854
cifs_dbg(NOISY, "DACL revision %d size %d num aces %d\n",
788855
le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
@@ -800,37 +867,19 @@ static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl,
800867
if (num_aces > 0) {
801868
umode_t denied_mode = 0;
802869

803-
if (num_aces > (le16_to_cpu(pdacl->size) - sizeof(struct smb_acl)) /
804-
(offsetof(struct smb_ace, sid) +
805-
offsetof(struct smb_sid, sub_auth) + sizeof(__le16)))
806-
return;
807-
808870
ppace = kmalloc_objs(struct smb_ace *, num_aces);
809871
if (!ppace)
810872
return;
811873

812874
for (i = 0; i < num_aces; ++i) {
813-
if (end_of_acl - acl_base < acl_size)
814-
break;
815-
816875
ppace[i] = (struct smb_ace *) (acl_base + acl_size);
817-
acl_base = (char *)ppace[i];
818-
acl_size = offsetof(struct smb_ace, sid) +
819-
offsetof(struct smb_sid, sub_auth);
820-
821-
if (end_of_acl - acl_base < acl_size ||
822-
ppace[i]->sid.num_subauth == 0 ||
823-
ppace[i]->sid.num_subauth > SID_MAX_SUB_AUTHORITIES ||
824-
(end_of_acl - acl_base <
825-
acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth) ||
826-
(le16_to_cpu(ppace[i]->size) <
827-
acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth))
828-
break;
829876

830877
#ifdef CONFIG_CIFS_DEBUG2
831-
dump_ace(ppace[i], end_of_acl);
878+
dump_ace(ppace[i],
879+
(char *)pdacl + le16_to_cpu(pdacl->size));
832880
#endif
833881
if (mode_from_special_sid &&
882+
ppace[i]->sid.num_subauth >= 3 &&
834883
(compare_sids(&(ppace[i]->sid),
835884
&sid_unix_NFS_mode) == 0)) {
836885
/*
@@ -870,6 +919,7 @@ static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl,
870919
(void *)ppace[i],
871920
sizeof(struct smb_ace)); */
872921

922+
acl_base = (char *)ppace[i];
873923
acl_size = le16_to_cpu(ppace[i]->size);
874924
}
875925

@@ -1293,10 +1343,9 @@ static int build_sec_desc(struct smb_ntsd *pntsd, struct smb_ntsd *pnntsd,
12931343
dacloffset = le32_to_cpu(pntsd->dacloffset);
12941344
if (dacloffset) {
12951345
dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
1296-
if (end_of_acl < (char *)dacl_ptr + le16_to_cpu(dacl_ptr->size)) {
1297-
cifs_dbg(VFS, "Server returned illegal ACL size\n");
1298-
return -EINVAL;
1299-
}
1346+
rc = validate_dacl(dacl_ptr, end_of_acl);
1347+
if (rc)
1348+
return rc;
13001349
}
13011350

13021351
owner_sid_ptr = (struct smb_sid *)((char *)pntsd +
@@ -1662,6 +1711,12 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
16621711
dacloffset = le32_to_cpu(pntsd->dacloffset);
16631712
if (dacloffset) {
16641713
dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset);
1714+
rc = validate_dacl(dacl_ptr, (char *)pntsd + secdesclen);
1715+
if (rc) {
1716+
kfree(pntsd);
1717+
cifs_put_tlink(tlink);
1718+
return rc;
1719+
}
16651720
if (mode_from_sid)
16661721
nsecdesclen +=
16671722
le16_to_cpu(dacl_ptr->num_aces) * sizeof(struct smb_ace);

fs/smb/client/cifsencrypt.c

Lines changed: 20 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -22,49 +22,33 @@
2222
#include <linux/fips.h>
2323
#include <linux/iov_iter.h>
2424
#include <crypto/aead.h>
25+
#include <crypto/aes-cbc-macs.h>
2526
#include <crypto/arc4.h>
2627
#include <crypto/md5.h>
2728
#include <crypto/sha2.h>
2829

29-
static int cifs_sig_update(struct cifs_calc_sig_ctx *ctx,
30-
const u8 *data, size_t len)
30+
static size_t cifs_sig_step(void *iter_base, size_t progress, size_t len,
31+
void *priv, void *priv2)
3132
{
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);
33+
struct cifs_calc_sig_ctx *ctx = priv;
34+
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. */
4142
}
4243

43-
static int cifs_sig_final(struct cifs_calc_sig_ctx *ctx, u8 *out)
44+
static void cifs_sig_final(struct cifs_calc_sig_ctx *ctx, u8 *out)
4445
{
45-
if (ctx->md5) {
46+
if (ctx->md5)
4647
md5_final(ctx->md5, out);
47-
return 0;
48-
}
49-
if (ctx->hmac) {
48+
else if (ctx->hmac)
5049
hmac_sha256_final(ctx->hmac, out);
51-
return 0;
52-
}
53-
return crypto_shash_final(ctx->shash, out);
54-
}
55-
56-
static size_t cifs_sig_step(void *iter_base, size_t progress, size_t len,
57-
void *priv, void *priv2)
58-
{
59-
struct cifs_calc_sig_ctx *ctx = priv;
60-
int ret, *pret = priv2;
61-
62-
ret = cifs_sig_update(ctx, iter_base, len);
63-
if (ret < 0) {
64-
*pret = ret;
65-
return len;
66-
}
67-
return 0;
50+
else
51+
aes_cmac_final(ctx->cmac, out);
6852
}
6953

7054
/*
@@ -75,9 +59,8 @@ static int cifs_sig_iter(const struct iov_iter *iter, size_t maxsize,
7559
{
7660
struct iov_iter tmp_iter = *iter;
7761
size_t did;
78-
int err;
7962

80-
did = iterate_and_advance_kernel(&tmp_iter, maxsize, ctx, &err,
63+
did = iterate_and_advance_kernel(&tmp_iter, maxsize, ctx, NULL,
8164
cifs_sig_step);
8265
if (did != maxsize)
8366
return smb_EIO2(smb_eio_trace_sig_iter, did, maxsize);
@@ -108,11 +91,8 @@ int __cifs_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
10891
if (rc < 0)
10992
return rc;
11093

111-
rc = cifs_sig_final(ctx, signature);
112-
if (rc)
113-
cifs_dbg(VFS, "%s: Could not generate hash\n", __func__);
114-
115-
return rc;
94+
cifs_sig_final(ctx, signature);
95+
return 0;
11696
}
11797

11898
/* Build a proper attribute value/target info pairs blob.
@@ -523,8 +503,6 @@ calc_seckey(struct cifs_ses *ses)
523503
void
524504
cifs_crypto_secmech_release(struct TCP_Server_Info *server)
525505
{
526-
cifs_free_hash(&server->secmech.aes_cmac);
527-
528506
if (server->secmech.enc) {
529507
crypto_free_aead(server->secmech.enc);
530508
server->secmech.enc = NULL;

0 commit comments

Comments
 (0)