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.0-rc6-ksmbd-server-fix' of git://git.samba.org/ksmbd

Pull smb server fix from Steve French:

- Fix out of bound write

* tag 'v7.0-rc6-ksmbd-server-fix' of git://git.samba.org/ksmbd:
ksmbd: fix OOB write in QUERY_INFO for compound requests

+134 -32
+89 -32
fs/smb/server/smb2pdu.c
··· 3402 3402 KSMBD_SHARE_FLAG_ACL_XATTR)) { 3403 3403 struct smb_fattr fattr; 3404 3404 struct smb_ntsd *pntsd; 3405 - int pntsd_size, ace_num = 0; 3405 + int pntsd_size; 3406 + size_t scratch_len; 3406 3407 3407 3408 ksmbd_acls_fattr(&fattr, idmap, inode); 3408 - if (fattr.cf_acls) 3409 - ace_num = fattr.cf_acls->a_count; 3410 - if (fattr.cf_dacls) 3411 - ace_num += fattr.cf_dacls->a_count; 3409 + scratch_len = smb_acl_sec_desc_scratch_len(&fattr, 3410 + NULL, 0, 3411 + OWNER_SECINFO | GROUP_SECINFO | 3412 + DACL_SECINFO); 3413 + if (!scratch_len || scratch_len == SIZE_MAX) { 3414 + rc = -EFBIG; 3415 + posix_acl_release(fattr.cf_acls); 3416 + posix_acl_release(fattr.cf_dacls); 3417 + goto err_out; 3418 + } 3412 3419 3413 - pntsd = kmalloc(sizeof(struct smb_ntsd) + 3414 - sizeof(struct smb_sid) * 3 + 3415 - sizeof(struct smb_acl) + 3416 - sizeof(struct smb_ace) * ace_num * 2, 3417 - KSMBD_DEFAULT_GFP); 3420 + pntsd = kvzalloc(scratch_len, KSMBD_DEFAULT_GFP); 3418 3421 if (!pntsd) { 3422 + rc = -ENOMEM; 3419 3423 posix_acl_release(fattr.cf_acls); 3420 3424 posix_acl_release(fattr.cf_dacls); 3421 3425 goto err_out; ··· 3434 3430 posix_acl_release(fattr.cf_acls); 3435 3431 posix_acl_release(fattr.cf_dacls); 3436 3432 if (rc) { 3437 - kfree(pntsd); 3433 + kvfree(pntsd); 3438 3434 goto err_out; 3439 3435 } 3440 3436 ··· 3444 3440 pntsd, 3445 3441 pntsd_size, 3446 3442 false); 3447 - kfree(pntsd); 3443 + kvfree(pntsd); 3448 3444 if (rc) 3449 3445 pr_err("failed to store ntacl in xattr : %d\n", 3450 3446 rc); ··· 5376 5372 if (test_share_config_flag(work->tcon->share_conf, 5377 5373 KSMBD_SHARE_FLAG_PIPE)) { 5378 5374 /* smb2 info file called for pipe */ 5379 - return smb2_get_info_file_pipe(work->sess, req, rsp, 5375 + rc = smb2_get_info_file_pipe(work->sess, req, rsp, 5380 5376 work->response_buf); 5377 + goto iov_pin_out; 5381 5378 } 5382 5379 5383 5380 if (work->next_smb2_rcv_hdr_off) { ··· 5478 5473 rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength), 5479 5474 rsp, work->response_buf); 5480 5475 ksmbd_fd_put(work, fp); 5476 + 5477 + iov_pin_out: 5478 + if (!rc) 5479 + rc = ksmbd_iov_pin_rsp(work, (void *)rsp, 5480 + offsetof(struct smb2_query_info_rsp, Buffer) + 5481 + le32_to_cpu(rsp->OutputBufferLength)); 5481 5482 return rc; 5482 5483 } 5483 5484 ··· 5710 5699 rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength), 5711 5700 rsp, work->response_buf); 5712 5701 path_put(&path); 5702 + 5703 + if (!rc) 5704 + rc = ksmbd_iov_pin_rsp(work, (void *)rsp, 5705 + offsetof(struct smb2_query_info_rsp, Buffer) + 5706 + le32_to_cpu(rsp->OutputBufferLength)); 5713 5707 return rc; 5714 5708 } 5715 5709 ··· 5724 5708 { 5725 5709 struct ksmbd_file *fp; 5726 5710 struct mnt_idmap *idmap; 5727 - struct smb_ntsd *pntsd = (struct smb_ntsd *)rsp->Buffer, *ppntsd = NULL; 5711 + struct smb_ntsd *pntsd = NULL, *ppntsd = NULL; 5728 5712 struct smb_fattr fattr = {{0}}; 5729 5713 struct inode *inode; 5730 5714 __u32 secdesclen = 0; 5731 5715 unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID; 5732 5716 int addition_info = le32_to_cpu(req->AdditionalInformation); 5733 - int rc = 0, ppntsd_size = 0; 5717 + int rc = 0, ppntsd_size = 0, max_len; 5718 + size_t scratch_len = 0; 5734 5719 5735 5720 if (addition_info & ~(OWNER_SECINFO | GROUP_SECINFO | DACL_SECINFO | 5736 5721 PROTECTED_DACL_SECINFO | 5737 5722 UNPROTECTED_DACL_SECINFO)) { 5738 5723 ksmbd_debug(SMB, "Unsupported addition info: 0x%x)\n", 5739 5724 addition_info); 5725 + 5726 + pntsd = kzalloc(ALIGN(sizeof(struct smb_ntsd), 8), 5727 + KSMBD_DEFAULT_GFP); 5728 + if (!pntsd) 5729 + return -ENOMEM; 5740 5730 5741 5731 pntsd->revision = cpu_to_le16(1); 5742 5732 pntsd->type = cpu_to_le16(SELF_RELATIVE | DACL_PROTECTED); ··· 5752 5730 pntsd->dacloffset = 0; 5753 5731 5754 5732 secdesclen = sizeof(struct smb_ntsd); 5755 - rsp->OutputBufferLength = cpu_to_le32(secdesclen); 5756 - 5757 - return 0; 5733 + goto iov_pin; 5758 5734 } 5759 5735 5760 5736 if (work->next_smb2_rcv_hdr_off) { ··· 5784 5764 &ppntsd); 5785 5765 5786 5766 /* Check if sd buffer size exceeds response buffer size */ 5787 - if (smb2_resp_buf_len(work, 8) > ppntsd_size) 5788 - rc = build_sec_desc(idmap, pntsd, ppntsd, ppntsd_size, 5789 - addition_info, &secdesclen, &fattr); 5767 + max_len = smb2_calc_max_out_buf_len(work, 5768 + offsetof(struct smb2_query_info_rsp, Buffer), 5769 + le32_to_cpu(req->OutputBufferLength)); 5770 + if (max_len < 0) { 5771 + rc = -EINVAL; 5772 + goto release_acl; 5773 + } 5774 + 5775 + scratch_len = smb_acl_sec_desc_scratch_len(&fattr, ppntsd, 5776 + ppntsd_size, addition_info); 5777 + if (!scratch_len || scratch_len == SIZE_MAX) { 5778 + rc = -EFBIG; 5779 + goto release_acl; 5780 + } 5781 + 5782 + pntsd = kvzalloc(scratch_len, KSMBD_DEFAULT_GFP); 5783 + if (!pntsd) { 5784 + rc = -ENOMEM; 5785 + goto release_acl; 5786 + } 5787 + 5788 + rc = build_sec_desc(idmap, pntsd, ppntsd, ppntsd_size, 5789 + addition_info, &secdesclen, &fattr); 5790 + 5791 + release_acl: 5790 5792 posix_acl_release(fattr.cf_acls); 5791 5793 posix_acl_release(fattr.cf_dacls); 5792 5794 kfree(ppntsd); 5793 5795 ksmbd_fd_put(work, fp); 5794 - if (rc) 5795 - return rc; 5796 5796 5797 + if (!rc && ALIGN(secdesclen, 8) > scratch_len) 5798 + rc = -EFBIG; 5799 + if (rc) 5800 + goto err_out; 5801 + 5802 + iov_pin: 5797 5803 rsp->OutputBufferLength = cpu_to_le32(secdesclen); 5798 - return 0; 5804 + rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength), 5805 + rsp, work->response_buf); 5806 + if (rc) 5807 + goto err_out; 5808 + 5809 + rc = ksmbd_iov_pin_rsp_read(work, (void *)rsp, 5810 + offsetof(struct smb2_query_info_rsp, Buffer), 5811 + pntsd, secdesclen); 5812 + err_out: 5813 + if (rc) { 5814 + rsp->OutputBufferLength = 0; 5815 + kvfree(pntsd); 5816 + } 5817 + 5818 + return rc; 5799 5819 } 5800 5820 5801 5821 /** ··· 5859 5799 goto err_out; 5860 5800 } 5861 5801 5802 + rsp->StructureSize = cpu_to_le16(9); 5803 + rsp->OutputBufferOffset = cpu_to_le16(72); 5804 + 5862 5805 switch (req->InfoType) { 5863 5806 case SMB2_O_INFO_FILE: 5864 5807 ksmbd_debug(SMB, "GOT SMB2_O_INFO_FILE\n"); ··· 5882 5819 } 5883 5820 ksmbd_revert_fsids(work); 5884 5821 5885 - if (!rc) { 5886 - rsp->StructureSize = cpu_to_le16(9); 5887 - rsp->OutputBufferOffset = cpu_to_le16(72); 5888 - rc = ksmbd_iov_pin_rsp(work, (void *)rsp, 5889 - offsetof(struct smb2_query_info_rsp, Buffer) + 5890 - le32_to_cpu(rsp->OutputBufferLength)); 5891 - } 5892 - 5893 5822 err_out: 5894 5823 if (rc < 0) { 5895 5824 if (rc == -EACCES) ··· 5892 5837 rsp->hdr.Status = STATUS_UNEXPECTED_IO_ERROR; 5893 5838 else if (rc == -ENOMEM) 5894 5839 rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES; 5840 + else if (rc == -EINVAL && rsp->hdr.Status == 0) 5841 + rsp->hdr.Status = STATUS_INVALID_PARAMETER; 5895 5842 else if (rc == -EOPNOTSUPP || rsp->hdr.Status == 0) 5896 5843 rsp->hdr.Status = STATUS_INVALID_INFO_CLASS; 5897 5844 smb2_set_err_rsp(work);
+43
fs/smb/server/smbacl.c
··· 915 915 return 0; 916 916 } 917 917 918 + size_t smb_acl_sec_desc_scratch_len(struct smb_fattr *fattr, 919 + struct smb_ntsd *ppntsd, int ppntsd_size, int addition_info) 920 + { 921 + size_t len = sizeof(struct smb_ntsd); 922 + size_t tmp; 923 + 924 + if (addition_info & OWNER_SECINFO) 925 + len += sizeof(struct smb_sid); 926 + if (addition_info & GROUP_SECINFO) 927 + len += sizeof(struct smb_sid); 928 + if (!(addition_info & DACL_SECINFO)) 929 + return len; 930 + 931 + len += sizeof(struct smb_acl); 932 + if (ppntsd && ppntsd_size > 0) { 933 + unsigned int dacl_offset = le32_to_cpu(ppntsd->dacloffset); 934 + 935 + if (dacl_offset < ppntsd_size && 936 + check_add_overflow(len, ppntsd_size - dacl_offset, &len)) 937 + return 0; 938 + } 939 + 940 + if (fattr->cf_acls) { 941 + if (check_mul_overflow((size_t)fattr->cf_acls->a_count, 942 + 2 * sizeof(struct smb_ace), &tmp) || 943 + check_add_overflow(len, tmp, &len)) 944 + return 0; 945 + } else { 946 + /* default/minimum DACL */ 947 + if (check_add_overflow(len, 5 * sizeof(struct smb_ace), &len)) 948 + return 0; 949 + } 950 + 951 + if (fattr->cf_dacls) { 952 + if (check_mul_overflow((size_t)fattr->cf_dacls->a_count, 953 + sizeof(struct smb_ace), &tmp) || 954 + check_add_overflow(len, tmp, &len)) 955 + return 0; 956 + } 957 + 958 + return len; 959 + } 960 + 918 961 /* Convert permission bits from mode to equivalent CIFS ACL */ 919 962 int build_sec_desc(struct mnt_idmap *idmap, 920 963 struct smb_ntsd *pntsd, struct smb_ntsd *ppntsd,
+2
fs/smb/server/smbacl.h
··· 101 101 bool type_check, bool get_write); 102 102 void id_to_sid(unsigned int cid, uint sidtype, struct smb_sid *ssid); 103 103 void ksmbd_init_domain(u32 *sub_auth); 104 + size_t smb_acl_sec_desc_scratch_len(struct smb_fattr *fattr, 105 + struct smb_ntsd *ppntsd, int ppntsd_size, int addition_info); 104 106 105 107 static inline uid_t posix_acl_uid_translate(struct mnt_idmap *idmap, 106 108 struct posix_acl_entry *pace)