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 '6.7-rc2-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull smb client fixes from Steve French:

- use after free fix in releasing multichannel interfaces

- fixes for special file types (report char, block, FIFOs properly when
created e.g. by NFS to Windows)

- fixes for reporting various special file types and symlinks properly
when using SMB1

* tag '6.7-rc2-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6:
smb: client: introduce cifs_sfu_make_node()
smb: client: set correct file type from NFS reparse points
smb: client: introduce ->parse_reparse_point()
smb: client: implement ->query_reparse_point() for SMB1
cifs: fix use after free for iface while disabling secondary channels

+312 -373
+11 -3
fs/smb/client/cifsglob.h
··· 191 191 bool reparse_point; 192 192 bool symlink; 193 193 }; 194 - __u32 reparse_tag; 194 + struct { 195 + __u32 tag; 196 + union { 197 + struct reparse_data_buffer *buf; 198 + struct reparse_posix_data *posix; 199 + }; 200 + } reparse; 195 201 char *symlink_target; 196 202 union { 197 203 struct smb2_file_all_info fi; ··· 401 395 struct cifs_tcon *tcon, 402 396 struct cifs_sb_info *cifs_sb, 403 397 const char *full_path, 404 - char **target_path, 405 - struct kvec *rsp_iov); 398 + char **target_path); 406 399 /* open a file for non-posix mounts */ 407 400 int (*open)(const unsigned int xid, struct cifs_open_parms *oparms, __u32 *oplock, 408 401 void *buf); ··· 556 551 bool (*is_status_io_timeout)(char *buf); 557 552 /* Check for STATUS_NETWORK_NAME_DELETED */ 558 553 bool (*is_network_name_deleted)(char *buf, struct TCP_Server_Info *srv); 554 + int (*parse_reparse_point)(struct cifs_sb_info *cifs_sb, 555 + struct kvec *rsp_iov, 556 + struct cifs_open_info_data *data); 559 557 }; 560 558 561 559 struct smb_version_values {
+2 -2
fs/smb/client/cifspdu.h
··· 1356 1356 __le32 DataDisplacement; 1357 1357 __u8 SetupCount; /* 1 */ 1358 1358 __le16 ReturnedDataLen; 1359 - __u16 ByteCount; 1359 + __le16 ByteCount; 1360 1360 } __attribute__((packed)) TRANSACT_IOCTL_RSP; 1361 1361 1362 1362 #define CIFS_ACL_OWNER 1 ··· 1509 1509 __le16 ReparseDataLength; 1510 1510 __u16 Reserved; 1511 1511 __le64 InodeType; /* LNK, FIFO, CHR etc. */ 1512 - char PathBuffer[]; 1512 + __u8 DataBuffer[]; 1513 1513 } __attribute__((packed)); 1514 1514 1515 1515 struct cifs_quota_data {
+13 -1
fs/smb/client/cifsproto.h
··· 210 210 const struct cifs_fid *fid); 211 211 bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb, 212 212 struct cifs_fattr *fattr, 213 - u32 tag); 213 + struct cifs_open_info_data *data); 214 214 extern int smb311_posix_get_inode_info(struct inode **pinode, const char *search_path, 215 215 struct super_block *sb, unsigned int xid); 216 216 extern int cifs_get_inode_info_unix(struct inode **pinode, ··· 458 458 struct cifs_tcon *tcon, 459 459 const unsigned char *searchName, char **syminfo, 460 460 const struct nls_table *nls_codepage, int remap); 461 + extern int cifs_query_reparse_point(const unsigned int xid, 462 + struct cifs_tcon *tcon, 463 + struct cifs_sb_info *cifs_sb, 464 + const char *full_path, 465 + u32 *tag, struct kvec *rsp, 466 + int *rsp_buftype); 461 467 extern int CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, 462 468 __u16 fid, char **symlinkinfo, 463 469 const struct nls_table *nls_codepage); ··· 665 659 int cifs_update_super_prepath(struct cifs_sb_info *cifs_sb, char *prefix); 666 660 char *extract_hostname(const char *unc); 667 661 char *extract_sharename(const char *unc); 662 + int parse_reparse_point(struct reparse_data_buffer *buf, 663 + u32 plen, struct cifs_sb_info *cifs_sb, 664 + bool unicode, struct cifs_open_info_data *data); 665 + int cifs_sfu_make_node(unsigned int xid, struct inode *inode, 666 + struct dentry *dentry, struct cifs_tcon *tcon, 667 + const char *full_path, umode_t mode, dev_t dev); 668 668 669 669 #ifdef CONFIG_CIFS_DFS_UPCALL 670 670 static inline int get_dfs_path(const unsigned int xid, struct cifs_ses *ses,
+76 -115
fs/smb/client/cifssmb.c
··· 2690 2690 return rc; 2691 2691 } 2692 2692 2693 - /* 2694 - * Recent Windows versions now create symlinks more frequently 2695 - * and they use the "reparse point" mechanism below. We can of course 2696 - * do symlinks nicely to Samba and other servers which support the 2697 - * CIFS Unix Extensions and we can also do SFU symlinks and "client only" 2698 - * "MF" symlinks optionally, but for recent Windows we really need to 2699 - * reenable the code below and fix the cifs_symlink callers to handle this. 2700 - * In the interim this code has been moved to its own config option so 2701 - * it is not compiled in by default until callers fixed up and more tested. 2702 - */ 2703 - int 2704 - CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, 2705 - __u16 fid, char **symlinkinfo, 2706 - const struct nls_table *nls_codepage) 2693 + int cifs_query_reparse_point(const unsigned int xid, 2694 + struct cifs_tcon *tcon, 2695 + struct cifs_sb_info *cifs_sb, 2696 + const char *full_path, 2697 + u32 *tag, struct kvec *rsp, 2698 + int *rsp_buftype) 2707 2699 { 2708 - int rc = 0; 2709 - int bytes_returned; 2710 - struct smb_com_transaction_ioctl_req *pSMB; 2711 - struct smb_com_transaction_ioctl_rsp *pSMBr; 2712 - bool is_unicode; 2713 - unsigned int sub_len; 2714 - char *sub_start; 2715 - struct reparse_symlink_data *reparse_buf; 2716 - struct reparse_posix_data *posix_buf; 2700 + struct cifs_open_parms oparms; 2701 + TRANSACT_IOCTL_REQ *io_req = NULL; 2702 + TRANSACT_IOCTL_RSP *io_rsp = NULL; 2703 + struct cifs_fid fid; 2717 2704 __u32 data_offset, data_count; 2718 - char *end_of_smb; 2705 + __u8 *start, *end; 2706 + int io_rsp_len; 2707 + int oplock = 0; 2708 + int rc; 2719 2709 2720 - cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid); 2721 - rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, 2722 - (void **) &pSMBr); 2710 + cifs_tcon_dbg(FYI, "%s: path=%s\n", __func__, full_path); 2711 + 2712 + if (cap_unix(tcon->ses)) 2713 + return -EOPNOTSUPP; 2714 + 2715 + oparms = (struct cifs_open_parms) { 2716 + .tcon = tcon, 2717 + .cifs_sb = cifs_sb, 2718 + .desired_access = FILE_READ_ATTRIBUTES, 2719 + .create_options = cifs_create_options(cifs_sb, 2720 + OPEN_REPARSE_POINT), 2721 + .disposition = FILE_OPEN, 2722 + .path = full_path, 2723 + .fid = &fid, 2724 + }; 2725 + 2726 + rc = CIFS_open(xid, &oparms, &oplock, NULL); 2723 2727 if (rc) 2724 2728 return rc; 2725 2729 2726 - pSMB->TotalParameterCount = 0 ; 2727 - pSMB->TotalDataCount = 0; 2728 - pSMB->MaxParameterCount = cpu_to_le32(2); 2730 + rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, 2731 + (void **)&io_req, (void **)&io_rsp); 2732 + if (rc) 2733 + goto error; 2734 + 2735 + io_req->TotalParameterCount = 0; 2736 + io_req->TotalDataCount = 0; 2737 + io_req->MaxParameterCount = cpu_to_le32(2); 2729 2738 /* BB find exact data count max from sess structure BB */ 2730 - pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00); 2731 - pSMB->MaxSetupCount = 4; 2732 - pSMB->Reserved = 0; 2733 - pSMB->ParameterOffset = 0; 2734 - pSMB->DataCount = 0; 2735 - pSMB->DataOffset = 0; 2736 - pSMB->SetupCount = 4; 2737 - pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL); 2738 - pSMB->ParameterCount = pSMB->TotalParameterCount; 2739 - pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT); 2740 - pSMB->IsFsctl = 1; /* FSCTL */ 2741 - pSMB->IsRootFlag = 0; 2742 - pSMB->Fid = fid; /* file handle always le */ 2743 - pSMB->ByteCount = 0; 2739 + io_req->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00); 2740 + io_req->MaxSetupCount = 4; 2741 + io_req->Reserved = 0; 2742 + io_req->ParameterOffset = 0; 2743 + io_req->DataCount = 0; 2744 + io_req->DataOffset = 0; 2745 + io_req->SetupCount = 4; 2746 + io_req->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL); 2747 + io_req->ParameterCount = io_req->TotalParameterCount; 2748 + io_req->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT); 2749 + io_req->IsFsctl = 1; 2750 + io_req->IsRootFlag = 0; 2751 + io_req->Fid = fid.netfid; 2752 + io_req->ByteCount = 0; 2744 2753 2745 - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 2746 - (struct smb_hdr *) pSMBr, &bytes_returned, 0); 2747 - if (rc) { 2748 - cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc); 2749 - goto qreparse_out; 2750 - } 2754 + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)io_req, 2755 + (struct smb_hdr *)io_rsp, &io_rsp_len, 0); 2756 + if (rc) 2757 + goto error; 2751 2758 2752 - data_offset = le32_to_cpu(pSMBr->DataOffset); 2753 - data_count = le32_to_cpu(pSMBr->DataCount); 2754 - if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) { 2755 - /* BB also check enough total bytes returned */ 2756 - rc = -EIO; /* bad smb */ 2757 - goto qreparse_out; 2758 - } 2759 - if (!data_count || (data_count > 2048)) { 2759 + data_offset = le32_to_cpu(io_rsp->DataOffset); 2760 + data_count = le32_to_cpu(io_rsp->DataCount); 2761 + if (get_bcc(&io_rsp->hdr) < 2 || data_offset > 512 || 2762 + !data_count || data_count > 2048) { 2760 2763 rc = -EIO; 2761 - cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n"); 2762 - goto qreparse_out; 2764 + goto error; 2763 2765 } 2764 - end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount; 2765 - reparse_buf = (struct reparse_symlink_data *) 2766 - ((char *)&pSMBr->hdr.Protocol + data_offset); 2767 - if ((char *)reparse_buf >= end_of_smb) { 2766 + 2767 + end = 2 + get_bcc(&io_rsp->hdr) + (__u8 *)&io_rsp->ByteCount; 2768 + start = (__u8 *)&io_rsp->hdr.Protocol + data_offset; 2769 + if (start >= end) { 2768 2770 rc = -EIO; 2769 - goto qreparse_out; 2770 - } 2771 - if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) { 2772 - cifs_dbg(FYI, "NFS style reparse tag\n"); 2773 - posix_buf = (struct reparse_posix_data *)reparse_buf; 2774 - 2775 - if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) { 2776 - cifs_dbg(FYI, "unsupported file type 0x%llx\n", 2777 - le64_to_cpu(posix_buf->InodeType)); 2778 - rc = -EOPNOTSUPP; 2779 - goto qreparse_out; 2780 - } 2781 - is_unicode = true; 2782 - sub_len = le16_to_cpu(reparse_buf->ReparseDataLength); 2783 - if (posix_buf->PathBuffer + sub_len > end_of_smb) { 2784 - cifs_dbg(FYI, "reparse buf beyond SMB\n"); 2785 - rc = -EIO; 2786 - goto qreparse_out; 2787 - } 2788 - *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer, 2789 - sub_len, is_unicode, nls_codepage); 2790 - goto qreparse_out; 2791 - } else if (reparse_buf->ReparseTag != 2792 - cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) { 2793 - rc = -EOPNOTSUPP; 2794 - goto qreparse_out; 2771 + goto error; 2795 2772 } 2796 2773 2797 - /* Reparse tag is NTFS symlink */ 2798 - sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) + 2799 - reparse_buf->PathBuffer; 2800 - sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength); 2801 - if (sub_start + sub_len > end_of_smb) { 2802 - cifs_dbg(FYI, "reparse buf beyond SMB\n"); 2803 - rc = -EIO; 2804 - goto qreparse_out; 2805 - } 2806 - if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) 2807 - is_unicode = true; 2808 - else 2809 - is_unicode = false; 2774 + *tag = le32_to_cpu(((struct reparse_data_buffer *)start)->ReparseTag); 2775 + rsp->iov_base = io_rsp; 2776 + rsp->iov_len = io_rsp_len; 2777 + *rsp_buftype = CIFS_LARGE_BUFFER; 2778 + CIFSSMBClose(xid, tcon, fid.netfid); 2779 + return 0; 2810 2780 2811 - /* BB FIXME investigate remapping reserved chars here */ 2812 - *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode, 2813 - nls_codepage); 2814 - if (!*symlinkinfo) 2815 - rc = -ENOMEM; 2816 - qreparse_out: 2817 - cifs_buf_release(pSMB); 2818 - 2819 - /* 2820 - * Note: On -EAGAIN error only caller can retry on handle based calls 2821 - * since file handle passed in no longer valid. 2822 - */ 2781 + error: 2782 + cifs_buf_release(io_req); 2783 + CIFSSMBClose(xid, tcon, fid.netfid); 2823 2784 return rc; 2824 2785 } 2825 2786
+60 -14
fs/smb/client/inode.c
··· 459 459 return -EOPNOTSUPP; 460 460 rc = server->ops->query_symlink(xid, tcon, 461 461 cifs_sb, full_path, 462 - &fattr->cf_symlink_target, 463 - NULL); 462 + &fattr->cf_symlink_target); 464 463 cifs_dbg(FYI, "%s: query_symlink: %d\n", __func__, rc); 465 464 } 466 465 return rc; ··· 721 722 fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink); 722 723 } 723 724 725 + static inline dev_t nfs_mkdev(struct reparse_posix_data *buf) 726 + { 727 + u64 v = le64_to_cpu(*(__le64 *)buf->DataBuffer); 728 + 729 + return MKDEV(v >> 32, v & 0xffffffff); 730 + } 731 + 724 732 bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb, 725 733 struct cifs_fattr *fattr, 726 - u32 tag) 734 + struct cifs_open_info_data *data) 727 735 { 736 + struct reparse_posix_data *buf = data->reparse.posix; 737 + u32 tag = data->reparse.tag; 738 + 739 + if (tag == IO_REPARSE_TAG_NFS && buf) { 740 + switch (le64_to_cpu(buf->InodeType)) { 741 + case NFS_SPECFILE_CHR: 742 + fattr->cf_mode |= S_IFCHR | cifs_sb->ctx->file_mode; 743 + fattr->cf_dtype = DT_CHR; 744 + fattr->cf_rdev = nfs_mkdev(buf); 745 + break; 746 + case NFS_SPECFILE_BLK: 747 + fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode; 748 + fattr->cf_dtype = DT_BLK; 749 + fattr->cf_rdev = nfs_mkdev(buf); 750 + break; 751 + case NFS_SPECFILE_FIFO: 752 + fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode; 753 + fattr->cf_dtype = DT_FIFO; 754 + break; 755 + case NFS_SPECFILE_SOCK: 756 + fattr->cf_mode |= S_IFSOCK | cifs_sb->ctx->file_mode; 757 + fattr->cf_dtype = DT_SOCK; 758 + break; 759 + case NFS_SPECFILE_LNK: 760 + fattr->cf_mode = S_IFLNK | cifs_sb->ctx->file_mode; 761 + fattr->cf_dtype = DT_LNK; 762 + break; 763 + default: 764 + WARN_ON_ONCE(1); 765 + return false; 766 + } 767 + return true; 768 + } 769 + 728 770 switch (tag) { 729 771 case IO_REPARSE_TAG_LX_SYMLINK: 730 772 fattr->cf_mode |= S_IFLNK | cifs_sb->ctx->file_mode; ··· 831 791 fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks); 832 792 833 793 if (cifs_open_data_reparse(data) && 834 - cifs_reparse_point_to_fattr(cifs_sb, fattr, data->reparse_tag)) 794 + cifs_reparse_point_to_fattr(cifs_sb, fattr, data)) 835 795 goto out_reparse; 836 796 837 797 if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { ··· 896 856 data.adjust_tz = false; 897 857 if (data.symlink_target) { 898 858 data.symlink = true; 899 - data.reparse_tag = IO_REPARSE_TAG_SYMLINK; 859 + data.reparse.tag = IO_REPARSE_TAG_SYMLINK; 900 860 } 901 861 cifs_open_info_to_fattr(&fattr, &data, inode->i_sb); 902 862 break; ··· 1065 1025 struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 1066 1026 struct kvec rsp_iov, *iov = NULL; 1067 1027 int rsp_buftype = CIFS_NO_BUFFER; 1068 - u32 tag = data->reparse_tag; 1028 + u32 tag = data->reparse.tag; 1069 1029 int rc = 0; 1070 1030 1071 1031 if (!tag && server->ops->query_reparse_point) { ··· 1075 1035 if (!rc) 1076 1036 iov = &rsp_iov; 1077 1037 } 1078 - switch ((data->reparse_tag = tag)) { 1038 + 1039 + rc = -EOPNOTSUPP; 1040 + switch ((data->reparse.tag = tag)) { 1079 1041 case 0: /* SMB1 symlink */ 1080 - iov = NULL; 1081 - fallthrough; 1082 - case IO_REPARSE_TAG_NFS: 1083 - case IO_REPARSE_TAG_SYMLINK: 1084 - if (!data->symlink_target && server->ops->query_symlink) { 1042 + if (server->ops->query_symlink) { 1085 1043 rc = server->ops->query_symlink(xid, tcon, 1086 1044 cifs_sb, full_path, 1087 - &data->symlink_target, 1088 - iov); 1045 + &data->symlink_target); 1089 1046 } 1090 1047 break; 1091 1048 case IO_REPARSE_TAG_MOUNT_POINT: 1092 1049 cifs_create_junction_fattr(fattr, sb); 1050 + rc = 0; 1093 1051 goto out; 1052 + default: 1053 + if (data->symlink_target) { 1054 + rc = 0; 1055 + } else if (server->ops->parse_reparse_point) { 1056 + rc = server->ops->parse_reparse_point(cifs_sb, 1057 + iov, data); 1058 + } 1059 + break; 1094 1060 } 1095 1061 1096 1062 cifs_open_info_to_fattr(fattr, data, sb);
+5 -1
fs/smb/client/readdir.c
··· 153 153 static void 154 154 cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb) 155 155 { 156 + struct cifs_open_info_data data = { 157 + .reparse = { .tag = fattr->cf_cifstag, }, 158 + }; 159 + 156 160 fattr->cf_uid = cifs_sb->ctx->linux_uid; 157 161 fattr->cf_gid = cifs_sb->ctx->linux_gid; 158 162 ··· 169 165 * reasonably map some of them to directories vs. files vs. symlinks 170 166 */ 171 167 if ((fattr->cf_cifsattrs & ATTR_REPARSE) && 172 - cifs_reparse_point_to_fattr(cifs_sb, fattr, fattr->cf_cifstag)) 168 + cifs_reparse_point_to_fattr(cifs_sb, fattr, &data)) 173 169 goto out_reparse; 174 170 175 171 if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
+1 -1
fs/smb/client/sess.c
··· 332 332 333 333 if (iface) { 334 334 spin_lock(&ses->iface_lock); 335 - kref_put(&iface->refcount, release_iface); 336 335 iface->num_channels--; 337 336 if (iface->weight_fulfilled) 338 337 iface->weight_fulfilled--; 338 + kref_put(&iface->refcount, release_iface); 339 339 spin_unlock(&ses->iface_lock); 340 340 } 341 341
+32 -121
fs/smb/client/smb1ops.c
··· 976 976 struct cifs_tcon *tcon, 977 977 struct cifs_sb_info *cifs_sb, 978 978 const char *full_path, 979 - char **target_path, 980 - struct kvec *rsp_iov) 979 + char **target_path) 981 980 { 982 981 int rc; 983 - int oplock = 0; 984 - bool is_reparse_point = !!rsp_iov; 985 - struct cifs_fid fid; 986 - struct cifs_open_parms oparms; 987 982 988 - cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path); 983 + cifs_tcon_dbg(FYI, "%s: path=%s\n", __func__, full_path); 989 984 990 - if (is_reparse_point) { 991 - cifs_dbg(VFS, "reparse points not handled for SMB1 symlinks\n"); 985 + if (!cap_unix(tcon->ses)) 992 986 return -EOPNOTSUPP; 993 - } 994 987 995 - /* Check for unix extensions */ 996 - if (cap_unix(tcon->ses)) { 997 - rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, target_path, 998 - cifs_sb->local_nls, 999 - cifs_remap(cifs_sb)); 1000 - if (rc == -EREMOTE) 1001 - rc = cifs_unix_dfs_readlink(xid, tcon, full_path, 1002 - target_path, 1003 - cifs_sb->local_nls); 1004 - 1005 - goto out; 1006 - } 1007 - 1008 - oparms = (struct cifs_open_parms) { 1009 - .tcon = tcon, 1010 - .cifs_sb = cifs_sb, 1011 - .desired_access = FILE_READ_ATTRIBUTES, 1012 - .create_options = cifs_create_options(cifs_sb, 1013 - OPEN_REPARSE_POINT), 1014 - .disposition = FILE_OPEN, 1015 - .path = full_path, 1016 - .fid = &fid, 1017 - }; 1018 - 1019 - rc = CIFS_open(xid, &oparms, &oplock, NULL); 1020 - if (rc) 1021 - goto out; 1022 - 1023 - rc = CIFSSMBQuerySymLink(xid, tcon, fid.netfid, target_path, 1024 - cifs_sb->local_nls); 1025 - if (rc) 1026 - goto out_close; 1027 - 1028 - convert_delimiter(*target_path, '/'); 1029 - out_close: 1030 - CIFSSMBClose(xid, tcon, fid.netfid); 1031 - out: 1032 - if (!rc) 1033 - cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path); 988 + rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, target_path, 989 + cifs_sb->local_nls, cifs_remap(cifs_sb)); 990 + if (rc == -EREMOTE) 991 + rc = cifs_unix_dfs_readlink(xid, tcon, full_path, 992 + target_path, cifs_sb->local_nls); 1034 993 return rc; 994 + } 995 + 996 + static int cifs_parse_reparse_point(struct cifs_sb_info *cifs_sb, 997 + struct kvec *rsp_iov, 998 + struct cifs_open_info_data *data) 999 + { 1000 + struct reparse_data_buffer *buf; 1001 + TRANSACT_IOCTL_RSP *io = rsp_iov->iov_base; 1002 + bool unicode = !!(io->hdr.Flags2 & SMBFLG2_UNICODE); 1003 + u32 plen = le16_to_cpu(io->ByteCount); 1004 + 1005 + buf = (struct reparse_data_buffer *)((__u8 *)&io->hdr.Protocol + 1006 + le32_to_cpu(io->DataOffset)); 1007 + return parse_reparse_point(buf, plen, cifs_sb, unicode, data); 1035 1008 } 1036 1009 1037 1010 static bool ··· 1041 1068 { 1042 1069 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 1043 1070 struct inode *newinode = NULL; 1044 - int rc = -EPERM; 1045 - struct cifs_open_info_data buf = {}; 1046 - struct cifs_io_parms io_parms; 1047 - __u32 oplock = 0; 1048 - struct cifs_fid fid; 1049 - struct cifs_open_parms oparms; 1050 - unsigned int bytes_written; 1051 - struct win_dev *pdev; 1052 - struct kvec iov[2]; 1071 + int rc; 1053 1072 1054 1073 if (tcon->unix_ext) { 1055 1074 /* ··· 1075 1110 d_instantiate(dentry, newinode); 1076 1111 return rc; 1077 1112 } 1078 - 1079 1113 /* 1080 - * SMB1 SFU emulation: should work with all servers, but only 1081 - * support block and char device (no socket & fifo) 1114 + * Check if mounted with mount parm 'sfu' mount parm. 1115 + * SFU emulation should work with all servers, but only 1116 + * supports block and char device (no socket & fifo), 1117 + * and was used by default in earlier versions of Windows 1082 1118 */ 1083 1119 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) 1084 - return rc; 1085 - 1086 - if (!S_ISCHR(mode) && !S_ISBLK(mode)) 1087 - return rc; 1088 - 1089 - cifs_dbg(FYI, "sfu compat create special file\n"); 1090 - 1091 - oparms = (struct cifs_open_parms) { 1092 - .tcon = tcon, 1093 - .cifs_sb = cifs_sb, 1094 - .desired_access = GENERIC_WRITE, 1095 - .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR | 1096 - CREATE_OPTION_SPECIAL), 1097 - .disposition = FILE_CREATE, 1098 - .path = full_path, 1099 - .fid = &fid, 1100 - }; 1101 - 1102 - if (tcon->ses->server->oplocks) 1103 - oplock = REQ_OPLOCK; 1104 - else 1105 - oplock = 0; 1106 - rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, &buf); 1107 - if (rc) 1108 - return rc; 1109 - 1110 - /* 1111 - * BB Do not bother to decode buf since no local inode yet to put 1112 - * timestamps in, but we can reuse it safely. 1113 - */ 1114 - 1115 - pdev = (struct win_dev *)&buf.fi; 1116 - io_parms.pid = current->tgid; 1117 - io_parms.tcon = tcon; 1118 - io_parms.offset = 0; 1119 - io_parms.length = sizeof(struct win_dev); 1120 - iov[1].iov_base = &buf.fi; 1121 - iov[1].iov_len = sizeof(struct win_dev); 1122 - if (S_ISCHR(mode)) { 1123 - memcpy(pdev->type, "IntxCHR", 8); 1124 - pdev->major = cpu_to_le64(MAJOR(dev)); 1125 - pdev->minor = cpu_to_le64(MINOR(dev)); 1126 - rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms, 1127 - &bytes_written, iov, 1); 1128 - } else if (S_ISBLK(mode)) { 1129 - memcpy(pdev->type, "IntxBLK", 8); 1130 - pdev->major = cpu_to_le64(MAJOR(dev)); 1131 - pdev->minor = cpu_to_le64(MINOR(dev)); 1132 - rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms, 1133 - &bytes_written, iov, 1); 1134 - } 1135 - tcon->ses->server->ops->close(xid, tcon, &fid); 1136 - d_drop(dentry); 1137 - 1138 - /* FIXME: add code here to set EAs */ 1139 - 1140 - cifs_free_open_info(&buf); 1141 - return rc; 1120 + return -EPERM; 1121 + return cifs_sfu_make_node(xid, inode, dentry, tcon, 1122 + full_path, mode, dev); 1142 1123 } 1143 - 1144 - 1145 1124 1146 1125 struct smb_version_operations smb1_operations = { 1147 1126 .send_cancel = send_nt_cancel, ··· 1123 1214 .is_path_accessible = cifs_is_path_accessible, 1124 1215 .can_echo = cifs_can_echo, 1125 1216 .query_path_info = cifs_query_path_info, 1217 + .query_reparse_point = cifs_query_reparse_point, 1126 1218 .query_file_info = cifs_query_file_info, 1127 1219 .get_srv_inum = cifs_get_srv_inum, 1128 1220 .set_path_size = CIFSSMBSetEOF, ··· 1139 1229 .rename = CIFSSMBRename, 1140 1230 .create_hardlink = CIFSCreateHardLink, 1141 1231 .query_symlink = cifs_query_symlink, 1232 + .parse_reparse_point = cifs_parse_reparse_point, 1142 1233 .open = cifs_open_file, 1143 1234 .set_fid = cifs_set_fid, 1144 1235 .close = cifs_close_file,
+1 -1
fs/smb/client/smb2inode.c
··· 555 555 break; 556 556 } 557 557 data->reparse_point = reparse_point; 558 - data->reparse_tag = tag; 558 + data->reparse.tag = tag; 559 559 return rc; 560 560 } 561 561
+111 -114
fs/smb/client/smb2ops.c
··· 2866 2866 return rc; 2867 2867 } 2868 2868 2869 - static int 2870 - parse_reparse_posix(struct reparse_posix_data *symlink_buf, 2871 - u32 plen, char **target_path, 2872 - struct cifs_sb_info *cifs_sb) 2869 + /* See MS-FSCC 2.1.2.6 for the 'NFS' style reparse tags */ 2870 + static int parse_reparse_posix(struct reparse_posix_data *buf, 2871 + struct cifs_sb_info *cifs_sb, 2872 + struct cifs_open_info_data *data) 2873 2873 { 2874 2874 unsigned int len; 2875 + u64 type; 2875 2876 2876 - /* See MS-FSCC 2.1.2.6 for the 'NFS' style reparse tags */ 2877 - len = le16_to_cpu(symlink_buf->ReparseDataLength); 2878 - 2879 - if (le64_to_cpu(symlink_buf->InodeType) != NFS_SPECFILE_LNK) { 2880 - cifs_dbg(VFS, "%lld not a supported symlink type\n", 2881 - le64_to_cpu(symlink_buf->InodeType)); 2877 + switch ((type = le64_to_cpu(buf->InodeType))) { 2878 + case NFS_SPECFILE_LNK: 2879 + len = le16_to_cpu(buf->ReparseDataLength); 2880 + data->symlink_target = cifs_strndup_from_utf16(buf->DataBuffer, 2881 + len, true, 2882 + cifs_sb->local_nls); 2883 + if (!data->symlink_target) 2884 + return -ENOMEM; 2885 + convert_delimiter(data->symlink_target, '/'); 2886 + cifs_dbg(FYI, "%s: target path: %s\n", 2887 + __func__, data->symlink_target); 2888 + break; 2889 + case NFS_SPECFILE_CHR: 2890 + case NFS_SPECFILE_BLK: 2891 + case NFS_SPECFILE_FIFO: 2892 + case NFS_SPECFILE_SOCK: 2893 + break; 2894 + default: 2895 + cifs_dbg(VFS, "%s: unhandled inode type: 0x%llx\n", 2896 + __func__, type); 2882 2897 return -EOPNOTSUPP; 2883 2898 } 2884 - 2885 - *target_path = cifs_strndup_from_utf16( 2886 - symlink_buf->PathBuffer, 2887 - len, true, cifs_sb->local_nls); 2888 - if (!(*target_path)) 2889 - return -ENOMEM; 2890 - 2891 - convert_delimiter(*target_path, '/'); 2892 - cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path); 2893 - 2894 2899 return 0; 2895 2900 } 2896 2901 2897 - static int 2898 - parse_reparse_symlink(struct reparse_symlink_data_buffer *symlink_buf, 2899 - u32 plen, char **target_path, 2900 - struct cifs_sb_info *cifs_sb) 2902 + static int parse_reparse_symlink(struct reparse_symlink_data_buffer *sym, 2903 + u32 plen, bool unicode, 2904 + struct cifs_sb_info *cifs_sb, 2905 + struct cifs_open_info_data *data) 2901 2906 { 2902 - unsigned int sub_len; 2903 - unsigned int sub_offset; 2907 + unsigned int len; 2908 + unsigned int offs; 2904 2909 2905 2910 /* We handle Symbolic Link reparse tag here. See: MS-FSCC 2.1.2.4 */ 2906 2911 2907 - sub_offset = le16_to_cpu(symlink_buf->SubstituteNameOffset); 2908 - sub_len = le16_to_cpu(symlink_buf->SubstituteNameLength); 2909 - if (sub_offset + 20 > plen || 2910 - sub_offset + sub_len + 20 > plen) { 2912 + offs = le16_to_cpu(sym->SubstituteNameOffset); 2913 + len = le16_to_cpu(sym->SubstituteNameLength); 2914 + if (offs + 20 > plen || offs + len + 20 > plen) { 2911 2915 cifs_dbg(VFS, "srv returned malformed symlink buffer\n"); 2912 2916 return -EIO; 2913 2917 } 2914 2918 2915 - *target_path = cifs_strndup_from_utf16( 2916 - symlink_buf->PathBuffer + sub_offset, 2917 - sub_len, true, cifs_sb->local_nls); 2918 - if (!(*target_path)) 2919 + data->symlink_target = cifs_strndup_from_utf16(sym->PathBuffer + offs, 2920 + len, unicode, 2921 + cifs_sb->local_nls); 2922 + if (!data->symlink_target) 2919 2923 return -ENOMEM; 2920 2924 2921 - convert_delimiter(*target_path, '/'); 2922 - cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path); 2925 + convert_delimiter(data->symlink_target, '/'); 2926 + cifs_dbg(FYI, "%s: target path: %s\n", __func__, data->symlink_target); 2923 2927 2924 2928 return 0; 2925 2929 } 2926 2930 2927 - static int 2928 - parse_reparse_point(struct reparse_data_buffer *buf, 2929 - u32 plen, char **target_path, 2930 - struct cifs_sb_info *cifs_sb) 2931 + int parse_reparse_point(struct reparse_data_buffer *buf, 2932 + u32 plen, struct cifs_sb_info *cifs_sb, 2933 + bool unicode, struct cifs_open_info_data *data) 2931 2934 { 2932 - if (plen < sizeof(struct reparse_data_buffer)) { 2933 - cifs_dbg(VFS, "reparse buffer is too small. Must be at least 8 bytes but was %d\n", 2934 - plen); 2935 + if (plen < sizeof(*buf)) { 2936 + cifs_dbg(VFS, "%s: reparse buffer is too small. Must be at least 8 bytes but was %d\n", 2937 + __func__, plen); 2935 2938 return -EIO; 2936 2939 } 2937 2940 2938 - if (plen < le16_to_cpu(buf->ReparseDataLength) + 2939 - sizeof(struct reparse_data_buffer)) { 2940 - cifs_dbg(VFS, "srv returned invalid reparse buf length: %d\n", 2941 - plen); 2941 + if (plen < le16_to_cpu(buf->ReparseDataLength) + sizeof(*buf)) { 2942 + cifs_dbg(VFS, "%s: invalid reparse buf length: %d\n", 2943 + __func__, plen); 2942 2944 return -EIO; 2943 2945 } 2946 + 2947 + data->reparse.buf = buf; 2944 2948 2945 2949 /* See MS-FSCC 2.1.2 */ 2946 2950 switch (le32_to_cpu(buf->ReparseTag)) { 2947 2951 case IO_REPARSE_TAG_NFS: 2948 - return parse_reparse_posix( 2949 - (struct reparse_posix_data *)buf, 2950 - plen, target_path, cifs_sb); 2952 + return parse_reparse_posix((struct reparse_posix_data *)buf, 2953 + cifs_sb, data); 2951 2954 case IO_REPARSE_TAG_SYMLINK: 2952 2955 return parse_reparse_symlink( 2953 2956 (struct reparse_symlink_data_buffer *)buf, 2954 - plen, target_path, cifs_sb); 2957 + plen, unicode, cifs_sb, data); 2958 + case IO_REPARSE_TAG_LX_SYMLINK: 2959 + case IO_REPARSE_TAG_AF_UNIX: 2960 + case IO_REPARSE_TAG_LX_FIFO: 2961 + case IO_REPARSE_TAG_LX_CHR: 2962 + case IO_REPARSE_TAG_LX_BLK: 2963 + return 0; 2955 2964 default: 2956 - cifs_dbg(VFS, "srv returned unknown symlink buffer tag:0x%08x\n", 2957 - le32_to_cpu(buf->ReparseTag)); 2965 + cifs_dbg(VFS, "%s: unhandled reparse tag: 0x%08x\n", 2966 + __func__, le32_to_cpu(buf->ReparseTag)); 2958 2967 return -EOPNOTSUPP; 2959 2968 } 2960 2969 } 2961 2970 2962 - static int smb2_query_symlink(const unsigned int xid, 2963 - struct cifs_tcon *tcon, 2964 - struct cifs_sb_info *cifs_sb, 2965 - const char *full_path, 2966 - char **target_path, 2967 - struct kvec *rsp_iov) 2971 + static int smb2_parse_reparse_point(struct cifs_sb_info *cifs_sb, 2972 + struct kvec *rsp_iov, 2973 + struct cifs_open_info_data *data) 2968 2974 { 2969 2975 struct reparse_data_buffer *buf; 2970 2976 struct smb2_ioctl_rsp *io = rsp_iov->iov_base; 2971 2977 u32 plen = le32_to_cpu(io->OutputCount); 2972 2978 2973 - cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path); 2974 - 2975 2979 buf = (struct reparse_data_buffer *)((u8 *)io + 2976 2980 le32_to_cpu(io->OutputOffset)); 2977 - return parse_reparse_point(buf, plen, target_path, cifs_sb); 2981 + return parse_reparse_point(buf, plen, cifs_sb, true, data); 2978 2982 } 2979 2983 2980 2984 static int smb2_query_reparse_point(const unsigned int xid, ··· 5068 5064 return le32_to_cpu(hdr->NextCommand); 5069 5065 } 5070 5066 5071 - static int 5072 - smb2_make_node(unsigned int xid, struct inode *inode, 5073 - struct dentry *dentry, struct cifs_tcon *tcon, 5074 - const char *full_path, umode_t mode, dev_t dev) 5067 + int cifs_sfu_make_node(unsigned int xid, struct inode *inode, 5068 + struct dentry *dentry, struct cifs_tcon *tcon, 5069 + const char *full_path, umode_t mode, dev_t dev) 5075 5070 { 5076 - struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 5077 - int rc = -EPERM; 5078 5071 struct cifs_open_info_data buf = {}; 5079 - struct cifs_io_parms io_parms = {0}; 5080 - __u32 oplock = 0; 5081 - struct cifs_fid fid; 5072 + struct TCP_Server_Info *server = tcon->ses->server; 5082 5073 struct cifs_open_parms oparms; 5074 + struct cifs_io_parms io_parms = {}; 5075 + struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 5076 + struct cifs_fid fid; 5083 5077 unsigned int bytes_written; 5084 5078 struct win_dev *pdev; 5085 5079 struct kvec iov[2]; 5086 - 5087 - /* 5088 - * Check if mounted with mount parm 'sfu' mount parm. 5089 - * SFU emulation should work with all servers, but only 5090 - * supports block and char device (no socket & fifo), 5091 - * and was used by default in earlier versions of Windows 5092 - */ 5093 - if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) 5094 - return rc; 5095 - 5096 - /* 5097 - * TODO: Add ability to create instead via reparse point. Windows (e.g. 5098 - * their current NFS server) uses this approach to expose special files 5099 - * over SMB2/SMB3 and Samba will do this with SMB3.1.1 POSIX Extensions 5100 - */ 5080 + __u32 oplock = server->oplocks ? REQ_OPLOCK : 0; 5081 + int rc; 5101 5082 5102 5083 if (!S_ISCHR(mode) && !S_ISBLK(mode) && !S_ISFIFO(mode)) 5103 - return rc; 5104 - 5105 - cifs_dbg(FYI, "sfu compat create special file\n"); 5084 + return -EPERM; 5106 5085 5107 5086 oparms = (struct cifs_open_parms) { 5108 5087 .tcon = tcon, ··· 5098 5111 .fid = &fid, 5099 5112 }; 5100 5113 5101 - if (tcon->ses->server->oplocks) 5102 - oplock = REQ_OPLOCK; 5103 - else 5104 - oplock = 0; 5105 - rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, &buf); 5114 + rc = server->ops->open(xid, &oparms, &oplock, &buf); 5106 5115 if (rc) 5107 5116 return rc; 5108 5117 ··· 5106 5123 * BB Do not bother to decode buf since no local inode yet to put 5107 5124 * timestamps in, but we can reuse it safely. 5108 5125 */ 5109 - 5110 5126 pdev = (struct win_dev *)&buf.fi; 5111 5127 io_parms.pid = current->tgid; 5112 5128 io_parms.tcon = tcon; 5113 - io_parms.offset = 0; 5114 - io_parms.length = sizeof(struct win_dev); 5115 - iov[1].iov_base = &buf.fi; 5116 - iov[1].iov_len = sizeof(struct win_dev); 5129 + io_parms.length = sizeof(*pdev); 5130 + iov[1].iov_base = pdev; 5131 + iov[1].iov_len = sizeof(*pdev); 5117 5132 if (S_ISCHR(mode)) { 5118 5133 memcpy(pdev->type, "IntxCHR", 8); 5119 5134 pdev->major = cpu_to_le64(MAJOR(dev)); 5120 5135 pdev->minor = cpu_to_le64(MINOR(dev)); 5121 - rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms, 5122 - &bytes_written, iov, 1); 5123 5136 } else if (S_ISBLK(mode)) { 5124 5137 memcpy(pdev->type, "IntxBLK", 8); 5125 5138 pdev->major = cpu_to_le64(MAJOR(dev)); 5126 5139 pdev->minor = cpu_to_le64(MINOR(dev)); 5127 - rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms, 5128 - &bytes_written, iov, 1); 5129 5140 } else if (S_ISFIFO(mode)) { 5130 5141 memcpy(pdev->type, "LnxFIFO", 8); 5131 - pdev->major = 0; 5132 - pdev->minor = 0; 5133 - rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms, 5134 - &bytes_written, iov, 1); 5135 5142 } 5136 - tcon->ses->server->ops->close(xid, tcon, &fid); 5143 + 5144 + rc = server->ops->sync_write(xid, &fid, &io_parms, 5145 + &bytes_written, iov, 1); 5146 + server->ops->close(xid, tcon, &fid); 5137 5147 d_drop(dentry); 5138 - 5139 5148 /* FIXME: add code here to set EAs */ 5140 - 5141 5149 cifs_free_open_info(&buf); 5142 5150 return rc; 5151 + } 5152 + 5153 + static int smb2_make_node(unsigned int xid, struct inode *inode, 5154 + struct dentry *dentry, struct cifs_tcon *tcon, 5155 + const char *full_path, umode_t mode, dev_t dev) 5156 + { 5157 + struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 5158 + 5159 + /* 5160 + * Check if mounted with mount parm 'sfu' mount parm. 5161 + * SFU emulation should work with all servers, but only 5162 + * supports block and char device (no socket & fifo), 5163 + * and was used by default in earlier versions of Windows 5164 + */ 5165 + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) 5166 + return -EPERM; 5167 + /* 5168 + * TODO: Add ability to create instead via reparse point. Windows (e.g. 5169 + * their current NFS server) uses this approach to expose special files 5170 + * over SMB2/SMB3 and Samba will do this with SMB3.1.1 POSIX Extensions 5171 + */ 5172 + return cifs_sfu_make_node(xid, inode, dentry, tcon, 5173 + full_path, mode, dev); 5143 5174 } 5144 5175 5145 5176 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY ··· 5206 5209 .unlink = smb2_unlink, 5207 5210 .rename = smb2_rename_path, 5208 5211 .create_hardlink = smb2_create_hardlink, 5209 - .query_symlink = smb2_query_symlink, 5212 + .parse_reparse_point = smb2_parse_reparse_point, 5210 5213 .query_mf_symlink = smb3_query_mf_symlink, 5211 5214 .create_mf_symlink = smb3_create_mf_symlink, 5212 5215 .open = smb2_open_file, ··· 5308 5311 .unlink = smb2_unlink, 5309 5312 .rename = smb2_rename_path, 5310 5313 .create_hardlink = smb2_create_hardlink, 5311 - .query_symlink = smb2_query_symlink, 5314 + .parse_reparse_point = smb2_parse_reparse_point, 5312 5315 .query_mf_symlink = smb3_query_mf_symlink, 5313 5316 .create_mf_symlink = smb3_create_mf_symlink, 5314 5317 .open = smb2_open_file, ··· 5413 5416 .unlink = smb2_unlink, 5414 5417 .rename = smb2_rename_path, 5415 5418 .create_hardlink = smb2_create_hardlink, 5416 - .query_symlink = smb2_query_symlink, 5419 + .parse_reparse_point = smb2_parse_reparse_point, 5417 5420 .query_mf_symlink = smb3_query_mf_symlink, 5418 5421 .create_mf_symlink = smb3_create_mf_symlink, 5419 5422 .open = smb2_open_file, ··· 5527 5530 .unlink = smb2_unlink, 5528 5531 .rename = smb2_rename_path, 5529 5532 .create_hardlink = smb2_create_hardlink, 5530 - .query_symlink = smb2_query_symlink, 5533 + .parse_reparse_point = smb2_parse_reparse_point, 5531 5534 .query_mf_symlink = smb3_query_mf_symlink, 5532 5535 .create_mf_symlink = smb3_create_mf_symlink, 5533 5536 .open = smb2_open_file,