Skip to content

Commit 1e16624

Browse files
committed
Merge tag '5.14-rc-smb3-fixes-part2' of git://git.samba.org/sfrench/cifs-2.6
Pull cifs fixes from Steve French: "13 cifs/smb3 fixes. Most are to address minor issues pointed out by Coverity. Also includes a packet signing enhancement and mount improvement" * tag '5.14-rc-smb3-fixes-part2' of git://git.samba.org/sfrench/cifs-2.6: cifs: update internal version number cifs: prevent NULL deref in cifs_compose_mount_options() SMB3.1.1: Add support for negotiating signing algorithm cifs: use helpers when parsing uid/gid mount options and validate them CIFS: Clarify SMB1 code for POSIX Lock CIFS: Clarify SMB1 code for rename open file CIFS: Clarify SMB1 code for delete CIFS: Clarify SMB1 code for SetFileSize smb3: fix typo in header file CIFS: Clarify SMB1 code for UnixSetPathInfo CIFS: Clarify SMB1 code for UnixCreateSymLink cifs: clarify SMB1 code for UnixCreateHardLink cifs: make locking consistent around the server session status
2 parents 67d8d36 + 4d069f6 commit 1e16624

12 files changed

Lines changed: 135 additions & 29 deletions

File tree

fs/cifs/cifs_dfs_ref.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,9 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
151151
return ERR_PTR(-EINVAL);
152152

153153
if (ref) {
154+
if (WARN_ON_ONCE(!ref->node_name || ref->path_consumed < 0))
155+
return ERR_PTR(-EINVAL);
156+
154157
if (strlen(fullpath) - ref->path_consumed) {
155158
prepath = fullpath + ref->path_consumed;
156159
/* skip initial delimiter */

fs/cifs/cifsfs.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ bool lookupCacheEnabled = true;
6565
bool disable_legacy_dialects; /* false by default */
6666
bool enable_gcm_256 = true;
6767
bool require_gcm_256; /* false by default */
68+
bool enable_negotiate_signing; /* false by default */
6869
unsigned int global_secflags = CIFSSEC_DEF;
6970
/* unsigned int ntlmv2_support = 0; */
7071
unsigned int sign_CIFS_PDUs = 1;
@@ -104,6 +105,9 @@ MODULE_PARM_DESC(enable_gcm_256, "Enable requesting strongest (256 bit) GCM encr
104105
module_param(require_gcm_256, bool, 0644);
105106
MODULE_PARM_DESC(require_gcm_256, "Require strongest (256 bit) GCM encryption. Default: n/N/0");
106107

108+
module_param(enable_negotiate_signing, bool, 0644);
109+
MODULE_PARM_DESC(enable_negotiate_signing, "Enable negotiating packet signing algorithm with server. Default: n/N/0");
110+
107111
module_param(disable_legacy_dialects, bool, 0644);
108112
MODULE_PARM_DESC(disable_legacy_dialects, "To improve security it may be "
109113
"helpful to restrict the ability to "

fs/cifs/cifsfs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,5 +153,5 @@ extern struct dentry *cifs_smb3_do_mount(struct file_system_type *fs_type,
153153
extern const struct export_operations cifs_export_ops;
154154
#endif /* CONFIG_CIFS_NFSD_EXPORT */
155155

156-
#define CIFS_VERSION "2.32"
156+
#define CIFS_VERSION "2.33"
157157
#endif /* _CIFSFS_H */

fs/cifs/cifsglob.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,7 @@ struct TCP_Server_Info {
577577
char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
578578
struct smb_version_operations *ops;
579579
struct smb_version_values *vals;
580+
/* updates to tcpStatus protected by GlobalMid_Lock */
580581
enum statusEnum tcpStatus; /* what we think the status is */
581582
char *hostname; /* hostname portion of UNC string */
582583
struct socket *ssocket;
@@ -666,9 +667,11 @@ struct TCP_Server_Info {
666667
unsigned int max_write;
667668
unsigned int min_offload;
668669
__le16 compress_algorithm;
670+
__u16 signing_algorithm;
669671
__le16 cipher_type;
670672
/* save initital negprot hash */
671673
__u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE];
674+
bool signing_negotiated; /* true if valid signing context rcvd from server */
672675
bool posix_ext_supported;
673676
struct delayed_work reconnect; /* reconnect workqueue job */
674677
struct mutex reconnect_mutex; /* prevent simultaneous reconnects */
@@ -1785,7 +1788,7 @@ require use of the stronger protocol */
17851788
* list operations on pending_mid_q and oplockQ
17861789
* updates to XID counters, multiplex id and SMB sequence numbers
17871790
* list operations on global DnotifyReqList
1788-
* updates to ses->status
1791+
* updates to ses->status and TCP_Server_Info->tcpStatus
17891792
* updates to server->CurrentMid
17901793
* tcp_ses_lock protects:
17911794
* list operations on tcp and SMB session lists
@@ -1868,6 +1871,7 @@ extern unsigned int global_secflags; /* if on, session setup sent
18681871
extern unsigned int sign_CIFS_PDUs; /* enable smb packet signing */
18691872
extern bool enable_gcm_256; /* allow optional negotiate of strongest signing (aes-gcm-256) */
18701873
extern bool require_gcm_256; /* require use of strongest signing (aes-gcm-256) */
1874+
extern bool enable_negotiate_signing; /* request use of faster (GMAC) signing if available */
18711875
extern bool linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/
18721876
extern unsigned int CIFSMaxBufSize; /* max size not including hdr */
18731877
extern unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */

fs/cifs/cifspdu.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1785,6 +1785,7 @@ struct smb_com_transaction2_sfi_req {
17851785
__u16 Fid;
17861786
__le16 InformationLevel;
17871787
__u16 Reserved4;
1788+
__u8 payload[];
17881789
} __attribute__((packed));
17891790

17901791
struct smb_com_transaction2_sfi_rsp {

fs/cifs/cifssmb.c

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2537,8 +2537,9 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
25372537
pSMB->TotalDataCount = pSMB->DataCount;
25382538
pSMB->TotalParameterCount = pSMB->ParameterCount;
25392539
pSMB->ParameterOffset = cpu_to_le16(param_offset);
2540+
/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
25402541
parm_data = (struct cifs_posix_lock *)
2541-
(((char *) &pSMB->hdr.Protocol) + offset);
2542+
(((char *)pSMB) + offset + 4);
25422543

25432544
parm_data->lock_type = cpu_to_le16(lock_type);
25442545
if (waitFlag) {
@@ -2767,7 +2768,8 @@ int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
27672768
param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
27682769
offset = param_offset + params;
27692770

2770-
data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2771+
/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
2772+
data_offset = (char *)(pSMB) + offset + 4;
27712773
rename_info = (struct set_file_rename *) data_offset;
27722774
pSMB->MaxParameterCount = cpu_to_le16(2);
27732775
pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
@@ -2925,7 +2927,8 @@ CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
29252927
InformationLevel) - 4;
29262928
offset = param_offset + params;
29272929

2928-
data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2930+
/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
2931+
data_offset = (char *)pSMB + offset + 4;
29292932
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
29302933
name_len_target =
29312934
cifsConvertToUTF16((__le16 *) data_offset, toName,
@@ -3009,7 +3012,8 @@ CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
30093012
InformationLevel) - 4;
30103013
offset = param_offset + params;
30113014

3012-
data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3015+
/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
3016+
data_offset = (char *)pSMB + offset + 4;
30133017
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
30143018
name_len_target =
30153019
cifsConvertToUTF16((__le16 *) data_offset, fromName,
@@ -5626,9 +5630,9 @@ CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
56265630
pSMB->TotalDataCount = pSMB->DataCount;
56275631
pSMB->TotalParameterCount = pSMB->ParameterCount;
56285632
pSMB->ParameterOffset = cpu_to_le16(param_offset);
5633+
/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
56295634
parm_data =
5630-
(struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5631-
+ offset);
5635+
(struct file_end_of_file_info *)(((char *)pSMB) + offset + 4);
56325636
pSMB->DataOffset = cpu_to_le16(offset);
56335637
parm_data->FileSize = cpu_to_le64(size);
56345638
pSMB->Fid = cfile->fid.netfid;
@@ -5761,7 +5765,8 @@ CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
57615765
param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
57625766
offset = param_offset + params;
57635767

5764-
data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5768+
/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
5769+
data_offset = (char *)(pSMB) + offset + 4;
57655770

57665771
count = 1;
57675772
pSMB->MaxParameterCount = cpu_to_le16(2);
@@ -6062,9 +6067,8 @@ CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
60626067
param_offset = offsetof(struct smb_com_transaction2_spi_req,
60636068
InformationLevel) - 4;
60646069
offset = param_offset + params;
6065-
data_offset =
6066-
(FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6067-
offset);
6070+
/* SMB offsets are from the beginning of SMB which is 4 bytes in, after RFC1001 field */
6071+
data_offset = (FILE_UNIX_BASIC_INFO *)((char *) pSMB + offset + 4);
60686072
memset(data_offset, 0, count);
60696073
pSMB->DataOffset = cpu_to_le16(offset);
60706074
pSMB->ParameterOffset = cpu_to_le16(param_offset);

fs/cifs/connect.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1403,6 +1403,11 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx)
14031403
goto out_err_crypto_release;
14041404
}
14051405
tcp_ses->min_offload = ctx->min_offload;
1406+
/*
1407+
* at this point we are the only ones with the pointer
1408+
* to the struct since the kernel thread not created yet
1409+
* no need to spinlock this update of tcpStatus
1410+
*/
14061411
tcp_ses->tcpStatus = CifsNeedNegotiate;
14071412

14081413
if ((ctx->max_credits < 20) || (ctx->max_credits > 60000))

fs/cifs/fs_context.c

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,6 @@ smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx
322322
new_ctx->UNC = NULL;
323323
new_ctx->source = NULL;
324324
new_ctx->iocharset = NULL;
325-
326325
/*
327326
* Make sure to stay in sync with smb3_cleanup_fs_context_contents()
328327
*/
@@ -792,6 +791,8 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
792791
int i, opt;
793792
bool is_smb3 = !strcmp(fc->fs_type->name, "smb3");
794793
bool skip_parsing = false;
794+
kuid_t uid;
795+
kgid_t gid;
795796

796797
cifs_dbg(FYI, "CIFS: parsing cifs mount option '%s'\n", param->key);
797798

@@ -904,18 +905,31 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
904905
}
905906
break;
906907
case Opt_uid:
907-
ctx->linux_uid.val = result.uint_32;
908+
uid = make_kuid(current_user_ns(), result.uint_32);
909+
if (!uid_valid(uid))
910+
goto cifs_parse_mount_err;
911+
ctx->linux_uid = uid;
908912
ctx->uid_specified = true;
909913
break;
910914
case Opt_cruid:
911-
ctx->cred_uid.val = result.uint_32;
915+
uid = make_kuid(current_user_ns(), result.uint_32);
916+
if (!uid_valid(uid))
917+
goto cifs_parse_mount_err;
918+
ctx->cred_uid = uid;
919+
ctx->cruid_specified = true;
912920
break;
913921
case Opt_backupgid:
914-
ctx->backupgid.val = result.uint_32;
922+
gid = make_kgid(current_user_ns(), result.uint_32);
923+
if (!gid_valid(gid))
924+
goto cifs_parse_mount_err;
925+
ctx->backupgid = gid;
915926
ctx->backupgid_specified = true;
916927
break;
917928
case Opt_gid:
918-
ctx->linux_gid.val = result.uint_32;
929+
gid = make_kgid(current_user_ns(), result.uint_32);
930+
if (!gid_valid(gid))
931+
goto cifs_parse_mount_err;
932+
ctx->linux_gid = gid;
919933
ctx->gid_specified = true;
920934
break;
921935
case Opt_port:

fs/cifs/fs_context.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ enum cifs_param {
155155

156156
struct smb3_fs_context {
157157
bool uid_specified;
158+
bool cruid_specified;
158159
bool gid_specified;
159160
bool sloppy;
160161
bool got_ip;

fs/cifs/smb2pdu.c

Lines changed: 75 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,29 @@ build_compression_ctxt(struct smb2_compression_capabilities_context *pneg_ctxt)
433433
pneg_ctxt->CompressionAlgorithms[2] = SMB3_COMPRESS_LZNT1;
434434
}
435435

436+
static unsigned int
437+
build_signing_ctxt(struct smb2_signing_capabilities *pneg_ctxt)
438+
{
439+
unsigned int ctxt_len = sizeof(struct smb2_signing_capabilities);
440+
unsigned short num_algs = 1; /* number of signing algorithms sent */
441+
442+
pneg_ctxt->ContextType = SMB2_SIGNING_CAPABILITIES;
443+
/*
444+
* Context Data length must be rounded to multiple of 8 for some servers
445+
*/
446+
pneg_ctxt->DataLength = cpu_to_le16(DIV_ROUND_UP(
447+
sizeof(struct smb2_signing_capabilities) -
448+
sizeof(struct smb2_neg_context) +
449+
(num_algs * 2 /* sizeof u16 */), 8) * 8);
450+
pneg_ctxt->SigningAlgorithmCount = cpu_to_le16(num_algs);
451+
pneg_ctxt->SigningAlgorithms[0] = cpu_to_le16(SIGNING_ALG_AES_CMAC);
452+
453+
ctxt_len += 2 /* sizeof le16 */ * num_algs;
454+
ctxt_len = DIV_ROUND_UP(ctxt_len, 8) * 8;
455+
return ctxt_len;
456+
/* TBD add SIGNING_ALG_AES_GMAC and/or SIGNING_ALG_HMAC_SHA256 */
457+
}
458+
436459
static void
437460
build_encrypt_ctxt(struct smb2_encryption_neg_context *pneg_ctxt)
438461
{
@@ -498,7 +521,7 @@ assemble_neg_contexts(struct smb2_negotiate_req *req,
498521
struct TCP_Server_Info *server, unsigned int *total_len)
499522
{
500523
char *pneg_ctxt;
501-
unsigned int ctxt_len;
524+
unsigned int ctxt_len, neg_context_count;
502525

503526
if (*total_len > 200) {
504527
/* In case length corrupted don't want to overrun smb buffer */
@@ -525,6 +548,17 @@ assemble_neg_contexts(struct smb2_negotiate_req *req,
525548
*total_len += ctxt_len;
526549
pneg_ctxt += ctxt_len;
527550

551+
ctxt_len = build_netname_ctxt((struct smb2_netname_neg_context *)pneg_ctxt,
552+
server->hostname);
553+
*total_len += ctxt_len;
554+
pneg_ctxt += ctxt_len;
555+
556+
build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt);
557+
*total_len += sizeof(struct smb2_posix_neg_context);
558+
pneg_ctxt += sizeof(struct smb2_posix_neg_context);
559+
560+
neg_context_count = 4;
561+
528562
if (server->compress_algorithm) {
529563
build_compression_ctxt((struct smb2_compression_capabilities_context *)
530564
pneg_ctxt);
@@ -533,17 +567,20 @@ assemble_neg_contexts(struct smb2_negotiate_req *req,
533567
8) * 8;
534568
*total_len += ctxt_len;
535569
pneg_ctxt += ctxt_len;
536-
req->NegotiateContextCount = cpu_to_le16(5);
537-
} else
538-
req->NegotiateContextCount = cpu_to_le16(4);
570+
neg_context_count++;
571+
}
539572

540-
ctxt_len = build_netname_ctxt((struct smb2_netname_neg_context *)pneg_ctxt,
541-
server->hostname);
542-
*total_len += ctxt_len;
543-
pneg_ctxt += ctxt_len;
573+
if (enable_negotiate_signing) {
574+
ctxt_len = build_signing_ctxt((struct smb2_signing_capabilities *)
575+
pneg_ctxt);
576+
*total_len += ctxt_len;
577+
pneg_ctxt += ctxt_len;
578+
neg_context_count++;
579+
}
580+
581+
/* check for and add transport_capabilities and signing capabilities */
582+
req->NegotiateContextCount = cpu_to_le16(neg_context_count);
544583

545-
build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt);
546-
*total_len += sizeof(struct smb2_posix_neg_context);
547584
}
548585

549586
static void decode_preauth_context(struct smb2_preauth_neg_context *ctxt)
@@ -632,6 +669,31 @@ static int decode_encrypt_ctx(struct TCP_Server_Info *server,
632669
return 0;
633670
}
634671

672+
static void decode_signing_ctx(struct TCP_Server_Info *server,
673+
struct smb2_signing_capabilities *pctxt)
674+
{
675+
unsigned int len = le16_to_cpu(pctxt->DataLength);
676+
677+
if ((len < 4) || (len > 16)) {
678+
pr_warn_once("server sent bad signing negcontext\n");
679+
return;
680+
}
681+
if (le16_to_cpu(pctxt->SigningAlgorithmCount) != 1) {
682+
pr_warn_once("Invalid signing algorithm count\n");
683+
return;
684+
}
685+
if (le16_to_cpu(pctxt->SigningAlgorithms[0]) > 2) {
686+
pr_warn_once("unknown signing algorithm\n");
687+
return;
688+
}
689+
690+
server->signing_negotiated = true;
691+
server->signing_algorithm = le16_to_cpu(pctxt->SigningAlgorithms[0]);
692+
cifs_dbg(FYI, "signing algorithm %d chosen\n",
693+
server->signing_algorithm);
694+
}
695+
696+
635697
static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp,
636698
struct TCP_Server_Info *server,
637699
unsigned int len_of_smb)
@@ -675,6 +737,9 @@ static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp,
675737
(struct smb2_compression_capabilities_context *)pctx);
676738
else if (pctx->ContextType == SMB2_POSIX_EXTENSIONS_AVAILABLE)
677739
server->posix_ext_supported = true;
740+
else if (pctx->ContextType == SMB2_SIGNING_CAPABILITIES)
741+
decode_signing_ctx(server,
742+
(struct smb2_signing_capabilities *)pctx);
678743
else
679744
cifs_server_dbg(VFS, "unknown negcontext of type %d ignored\n",
680745
le16_to_cpu(pctx->ContextType));

0 commit comments

Comments
 (0)