diff options
-rw-r--r-- | fs/cifs/cifsglob.h | 1 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 1 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 77 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.h | 12 | ||||
-rw-r--r-- | fs/cifs/smb2proto.h | 1 | ||||
-rw-r--r-- | fs/cifs/smbfsctl.h | 2 |
6 files changed, 90 insertions, 4 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index d9ea7ada1378..f918a998a087 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -384,6 +384,7 @@ struct smb_version_operations { | |||
384 | int (*clone_range)(const unsigned int, struct cifsFileInfo *src_file, | 384 | int (*clone_range)(const unsigned int, struct cifsFileInfo *src_file, |
385 | struct cifsFileInfo *target_file, u64 src_off, u64 len, | 385 | struct cifsFileInfo *target_file, u64 src_off, u64 len, |
386 | u64 dest_off); | 386 | u64 dest_off); |
387 | int (*validate_negotiate)(const unsigned int, struct cifs_tcon *); | ||
387 | }; | 388 | }; |
388 | 389 | ||
389 | struct smb_version_values { | 390 | struct smb_version_values { |
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index a3968eeb6fac..757da3e54d3d 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c | |||
@@ -1319,6 +1319,7 @@ struct smb_version_operations smb30_operations = { | |||
1319 | .create_lease_buf = smb3_create_lease_buf, | 1319 | .create_lease_buf = smb3_create_lease_buf, |
1320 | .parse_lease_buf = smb3_parse_lease_buf, | 1320 | .parse_lease_buf = smb3_parse_lease_buf, |
1321 | .clone_range = smb2_clone_range, | 1321 | .clone_range = smb2_clone_range, |
1322 | .validate_negotiate = smb3_validate_negotiate, | ||
1322 | }; | 1323 | }; |
1323 | 1324 | ||
1324 | struct smb_version_values smb20_values = { | 1325 | struct smb_version_values smb20_values = { |
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 1e136eee3ea6..2013234b73ad 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c | |||
@@ -454,6 +454,81 @@ neg_exit: | |||
454 | return rc; | 454 | return rc; |
455 | } | 455 | } |
456 | 456 | ||
457 | int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) | ||
458 | { | ||
459 | int rc = 0; | ||
460 | struct validate_negotiate_info_req vneg_inbuf; | ||
461 | struct validate_negotiate_info_rsp *pneg_rsp; | ||
462 | u32 rsplen; | ||
463 | |||
464 | cifs_dbg(FYI, "validate negotiate\n"); | ||
465 | |||
466 | /* | ||
467 | * validation ioctl must be signed, so no point sending this if we | ||
468 | * can not sign it. We could eventually change this to selectively | ||
469 | * sign just this, the first and only signed request on a connection. | ||
470 | * This is good enough for now since a user who wants better security | ||
471 | * would also enable signing on the mount. Having validation of | ||
472 | * negotiate info for signed connections helps reduce attack vectors | ||
473 | */ | ||
474 | if (tcon->ses->server->sign == false) | ||
475 | return 0; /* validation requires signing */ | ||
476 | |||
477 | vneg_inbuf.Capabilities = | ||
478 | cpu_to_le32(tcon->ses->server->vals->req_capabilities); | ||
479 | memcpy(vneg_inbuf.Guid, cifs_client_guid, SMB2_CLIENT_GUID_SIZE); | ||
480 | |||
481 | if (tcon->ses->sign) | ||
482 | vneg_inbuf.SecurityMode = | ||
483 | cpu_to_le16(SMB2_NEGOTIATE_SIGNING_REQUIRED); | ||
484 | else if (global_secflags & CIFSSEC_MAY_SIGN) | ||
485 | vneg_inbuf.SecurityMode = | ||
486 | cpu_to_le16(SMB2_NEGOTIATE_SIGNING_ENABLED); | ||
487 | else | ||
488 | vneg_inbuf.SecurityMode = 0; | ||
489 | |||
490 | vneg_inbuf.DialectCount = cpu_to_le16(1); | ||
491 | vneg_inbuf.Dialects[0] = | ||
492 | cpu_to_le16(tcon->ses->server->vals->protocol_id); | ||
493 | |||
494 | rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, | ||
495 | FSCTL_VALIDATE_NEGOTIATE_INFO, true /* is_fsctl */, | ||
496 | (char *)&vneg_inbuf, sizeof(struct validate_negotiate_info_req), | ||
497 | (char **)&pneg_rsp, &rsplen); | ||
498 | |||
499 | if (rc != 0) { | ||
500 | cifs_dbg(VFS, "validate protocol negotiate failed: %d\n", rc); | ||
501 | return -EIO; | ||
502 | } | ||
503 | |||
504 | if (rsplen != sizeof(struct validate_negotiate_info_rsp)) { | ||
505 | cifs_dbg(VFS, "invalid size of protocol negotiate response\n"); | ||
506 | return -EIO; | ||
507 | } | ||
508 | |||
509 | /* check validate negotiate info response matches what we got earlier */ | ||
510 | if (pneg_rsp->Dialect != | ||
511 | cpu_to_le16(tcon->ses->server->vals->protocol_id)) | ||
512 | goto vneg_out; | ||
513 | |||
514 | if (pneg_rsp->SecurityMode != cpu_to_le16(tcon->ses->server->sec_mode)) | ||
515 | goto vneg_out; | ||
516 | |||
517 | /* do not validate server guid because not saved at negprot time yet */ | ||
518 | |||
519 | if ((le32_to_cpu(pneg_rsp->Capabilities) | SMB2_NT_FIND | | ||
520 | SMB2_LARGE_FILES) != tcon->ses->server->capabilities) | ||
521 | goto vneg_out; | ||
522 | |||
523 | /* validate negotiate successful */ | ||
524 | cifs_dbg(FYI, "validate negotiate info successful\n"); | ||
525 | return 0; | ||
526 | |||
527 | vneg_out: | ||
528 | cifs_dbg(VFS, "protocol revalidation - security settings mismatch\n"); | ||
529 | return -EIO; | ||
530 | } | ||
531 | |||
457 | int | 532 | int |
458 | SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, | 533 | SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, |
459 | const struct nls_table *nls_cp) | 534 | const struct nls_table *nls_cp) |
@@ -829,6 +904,8 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, | |||
829 | ((tcon->share_flags & SHI1005_FLAGS_DFS) == 0)) | 904 | ((tcon->share_flags & SHI1005_FLAGS_DFS) == 0)) |
830 | cifs_dbg(VFS, "DFS capability contradicts DFS flag\n"); | 905 | cifs_dbg(VFS, "DFS capability contradicts DFS flag\n"); |
831 | init_copy_chunk_defaults(tcon); | 906 | init_copy_chunk_defaults(tcon); |
907 | if (tcon->ses->server->ops->validate_negotiate) | ||
908 | rc = tcon->ses->server->ops->validate_negotiate(xid, tcon); | ||
832 | tcon_exit: | 909 | tcon_exit: |
833 | free_rsp_buf(resp_buftype, rsp); | 910 | free_rsp_buf(resp_buftype, rsp); |
834 | kfree(unc_path); | 911 | kfree(unc_path); |
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index f88320bbb477..2022c542ea3a 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h | |||
@@ -577,13 +577,19 @@ struct copychunk_ioctl_rsp { | |||
577 | __le32 TotalBytesWritten; | 577 | __le32 TotalBytesWritten; |
578 | } __packed; | 578 | } __packed; |
579 | 579 | ||
580 | /* Response and Request are the same format */ | 580 | struct validate_negotiate_info_req { |
581 | struct validate_negotiate_info { | ||
582 | __le32 Capabilities; | 581 | __le32 Capabilities; |
583 | __u8 Guid[SMB2_CLIENT_GUID_SIZE]; | 582 | __u8 Guid[SMB2_CLIENT_GUID_SIZE]; |
584 | __le16 SecurityMode; | 583 | __le16 SecurityMode; |
585 | __le16 DialectCount; | 584 | __le16 DialectCount; |
586 | __le16 Dialect[1]; | 585 | __le16 Dialects[1]; /* dialect (someday maybe list) client asked for */ |
586 | } __packed; | ||
587 | |||
588 | struct validate_negotiate_info_rsp { | ||
589 | __le32 Capabilities; | ||
590 | __u8 Guid[SMB2_CLIENT_GUID_SIZE]; | ||
591 | __le16 SecurityMode; | ||
592 | __le16 Dialect; /* Dialect in use for the connection */ | ||
587 | } __packed; | 593 | } __packed; |
588 | 594 | ||
589 | #define RSS_CAPABLE 0x00000001 | 595 | #define RSS_CAPABLE 0x00000001 |
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index b4eea105b08c..93adc64666f3 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h | |||
@@ -162,5 +162,6 @@ extern int smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon, | |||
162 | struct smb2_lock_element *buf); | 162 | struct smb2_lock_element *buf); |
163 | extern int SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon, | 163 | extern int SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon, |
164 | __u8 *lease_key, const __le32 lease_state); | 164 | __u8 *lease_key, const __le32 lease_state); |
165 | extern int smb3_validate_negotiate(const unsigned int, struct cifs_tcon *); | ||
165 | 166 | ||
166 | #endif /* _SMB2PROTO_H */ | 167 | #endif /* _SMB2PROTO_H */ |
diff --git a/fs/cifs/smbfsctl.h b/fs/cifs/smbfsctl.h index a4b2391fe66e..0e538b5c9622 100644 --- a/fs/cifs/smbfsctl.h +++ b/fs/cifs/smbfsctl.h | |||
@@ -90,7 +90,7 @@ | |||
90 | #define FSCTL_LMR_REQUEST_RESILIENCY 0x001401D4 /* BB add struct */ | 90 | #define FSCTL_LMR_REQUEST_RESILIENCY 0x001401D4 /* BB add struct */ |
91 | #define FSCTL_LMR_GET_LINK_TRACK_INF 0x001400E8 /* BB add struct */ | 91 | #define FSCTL_LMR_GET_LINK_TRACK_INF 0x001400E8 /* BB add struct */ |
92 | #define FSCTL_LMR_SET_LINK_TRACK_INF 0x001400EC /* BB add struct */ | 92 | #define FSCTL_LMR_SET_LINK_TRACK_INF 0x001400EC /* BB add struct */ |
93 | #define FSCTL_VALIDATE_NEGOTIATE_INFO 0x00140204 /* BB add struct */ | 93 | #define FSCTL_VALIDATE_NEGOTIATE_INFO 0x00140204 |
94 | /* Perform server-side data movement */ | 94 | /* Perform server-side data movement */ |
95 | #define FSCTL_SRV_COPYCHUNK 0x001440F2 | 95 | #define FSCTL_SRV_COPYCHUNK 0x001440F2 |
96 | #define FSCTL_SRV_COPYCHUNK_WRITE 0x001480F2 | 96 | #define FSCTL_SRV_COPYCHUNK_WRITE 0x001480F2 |