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 'v6.14-rc-smb3-client-fixes-part2' of git://git.samba.org/sfrench/cifs-2.6

Pull more smb client updates from Steve French:

- various updates for special file handling: symlink handling,
support for creating sockets, cleanups, new mount options (e.g. to
allow disabling using reparse points for them, and to allow
overriding the way symlinks are saved), and fixes to error paths

- fix for kerberos mounts (allow IAKerb)

- SMB1 fix for stat and for setting SACL (auditing)

- fix an incorrect error code mapping

- cleanups"

* tag 'v6.14-rc-smb3-client-fixes-part2' of git://git.samba.org/sfrench/cifs-2.6: (21 commits)
cifs: Fix parsing native symlinks directory/file type
cifs: update internal version number
cifs: Add support for creating WSL-style symlinks
smb3: add support for IAKerb
cifs: Fix struct FILE_ALL_INFO
cifs: Add support for creating NFS-style symlinks
cifs: Add support for creating native Windows sockets
cifs: Add mount option -o reparse=none
cifs: Add mount option -o symlink= for choosing symlink create type
cifs: Fix creating and resolving absolute NT-style symlinks
cifs: Simplify reparse point check in cifs_query_path_info() function
cifs: Remove symlink member from cifs_open_info_data union
cifs: Update description about ACL permissions
cifs: Rename struct reparse_posix_data to reparse_nfs_data_buffer and move to common/smb2pdu.h
cifs: Remove struct reparse_posix_data from struct cifs_open_info_data
cifs: Remove unicode parameter from parse_reparse_point() function
cifs: Fix getting and setting SACLs over SMB1
cifs: Remove intermediate object of failed create SFU call
cifs: Validate EAs for WSL reparse points
cifs: Change translation of STATUS_PRIVILEGE_NOT_HELD to -EPERM
...

+885 -193
+2
fs/smb/client/asn1.c
··· 52 52 server->sec_kerberos = true; 53 53 else if (oid == OID_ntlmssp) 54 54 server->sec_ntlmssp = true; 55 + else if (oid == OID_IAKerb) 56 + server->sec_iakerb = true; 55 57 else { 56 58 char buf[50]; 57 59
+3 -1
fs/smb/client/cifs_spnego.c
··· 138 138 139 139 dp = description + strlen(description); 140 140 141 - /* for now, only sec=krb5 and sec=mskrb5 are valid */ 141 + /* for now, only sec=krb5 and sec=mskrb5 and iakerb are valid */ 142 142 if (server->sec_kerberos) 143 143 sprintf(dp, ";sec=krb5"); 144 144 else if (server->sec_mskerberos) 145 145 sprintf(dp, ";sec=mskrb5"); 146 + else if (server->sec_iakerb) 147 + sprintf(dp, ";sec=iakerb"); 146 148 else { 147 149 cifs_dbg(VFS, "unknown or missing server auth type, use krb5\n"); 148 150 sprintf(dp, ";sec=krb5");
+15 -10
fs/smb/client/cifsacl.c
··· 1395 1395 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 1396 1396 struct smb_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, 1397 1397 const struct cifs_fid *cifsfid, u32 *pacllen, 1398 - u32 __maybe_unused unused) 1398 + u32 info) 1399 1399 { 1400 1400 struct smb_ntsd *pntsd = NULL; 1401 1401 unsigned int xid; ··· 1407 1407 1408 1408 xid = get_xid(); 1409 1409 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), cifsfid->netfid, &pntsd, 1410 - pacllen); 1410 + pacllen, info); 1411 1411 free_xid(xid); 1412 1412 1413 1413 cifs_put_tlink(tlink); ··· 1419 1419 } 1420 1420 1421 1421 static struct smb_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, 1422 - const char *path, u32 *pacllen) 1422 + const char *path, u32 *pacllen, u32 info) 1423 1423 { 1424 1424 struct smb_ntsd *pntsd = NULL; 1425 1425 int oplock = 0; ··· 1446 1446 .fid = &fid, 1447 1447 }; 1448 1448 1449 + if (info & SACL_SECINFO) 1450 + oparms.desired_access |= SYSTEM_SECURITY; 1451 + 1449 1452 rc = CIFS_open(xid, &oparms, &oplock, NULL); 1450 1453 if (!rc) { 1451 - rc = CIFSSMBGetCIFSACL(xid, tcon, fid.netfid, &pntsd, pacllen); 1454 + rc = CIFSSMBGetCIFSACL(xid, tcon, fid.netfid, &pntsd, pacllen, info); 1452 1455 CIFSSMBClose(xid, tcon, fid.netfid); 1453 1456 } 1454 1457 ··· 1475 1472 if (inode) 1476 1473 open_file = find_readable_file(CIFS_I(inode), true); 1477 1474 if (!open_file) 1478 - return get_cifs_acl_by_path(cifs_sb, path, pacllen); 1475 + return get_cifs_acl_by_path(cifs_sb, path, pacllen, info); 1479 1476 1480 1477 pntsd = get_cifs_acl_by_fid(cifs_sb, &open_file->fid, pacllen, info); 1481 1478 cifsFileInfo_put(open_file); ··· 1488 1485 { 1489 1486 int oplock = 0; 1490 1487 unsigned int xid; 1491 - int rc, access_flags; 1488 + int rc, access_flags = 0; 1492 1489 struct cifs_tcon *tcon; 1493 1490 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 1494 1491 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); ··· 1501 1498 tcon = tlink_tcon(tlink); 1502 1499 xid = get_xid(); 1503 1500 1504 - if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP) 1505 - access_flags = WRITE_OWNER; 1506 - else 1507 - access_flags = WRITE_DAC; 1501 + if (aclflag & CIFS_ACL_OWNER || aclflag & CIFS_ACL_GROUP) 1502 + access_flags |= WRITE_OWNER; 1503 + if (aclflag & CIFS_ACL_SACL) 1504 + access_flags |= SYSTEM_SECURITY; 1505 + if (aclflag & CIFS_ACL_DACL) 1506 + access_flags |= WRITE_DAC; 1508 1507 1509 1508 oparms = (struct cifs_open_parms) { 1510 1509 .tcon = tcon,
+6
fs/smb/client/cifsfs.c
··· 715 715 cifs_sb->ctx->backupgid)); 716 716 seq_show_option(s, "reparse", 717 717 cifs_reparse_type_str(cifs_sb->ctx->reparse_type)); 718 + if (cifs_sb->ctx->nonativesocket) 719 + seq_puts(s, ",nonativesocket"); 720 + else 721 + seq_puts(s, ",nativesocket"); 722 + seq_show_option(s, "symlink", 723 + cifs_symlink_type_str(get_cifs_symlink_type(cifs_sb))); 718 724 719 725 seq_printf(s, ",rsize=%u", cifs_sb->ctx->rsize); 720 726 seq_printf(s, ",wsize=%u", cifs_sb->ctx->wsize);
+2 -2
fs/smb/client/cifsfs.h
··· 146 146 #endif /* CONFIG_CIFS_NFSD_EXPORT */ 147 147 148 148 /* when changing internal version - update following two lines at same time */ 149 - #define SMB3_PRODUCT_BUILD 52 150 - #define CIFS_VERSION "2.52" 149 + #define SMB3_PRODUCT_BUILD 53 150 + #define CIFS_VERSION "2.53" 151 151 #endif /* _CIFSFS_H */
+49 -13
fs/smb/client/cifsglob.h
··· 151 151 NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */ 152 152 RawNTLMSSP, /* NTLMSSP without SPNEGO, NTLMv2 hash */ 153 153 Kerberos, /* Kerberos via SPNEGO */ 154 + IAKerb, /* Kerberos proxy */ 154 155 }; 155 156 156 157 enum upcall_target_enum { ··· 161 160 }; 162 161 163 162 enum cifs_reparse_type { 163 + CIFS_REPARSE_TYPE_NONE, 164 164 CIFS_REPARSE_TYPE_NFS, 165 165 CIFS_REPARSE_TYPE_WSL, 166 166 CIFS_REPARSE_TYPE_DEFAULT = CIFS_REPARSE_TYPE_NFS, ··· 170 168 static inline const char *cifs_reparse_type_str(enum cifs_reparse_type type) 171 169 { 172 170 switch (type) { 171 + case CIFS_REPARSE_TYPE_NONE: 172 + return "none"; 173 173 case CIFS_REPARSE_TYPE_NFS: 174 174 return "nfs"; 175 175 case CIFS_REPARSE_TYPE_WSL: 176 + return "wsl"; 177 + default: 178 + return "unknown"; 179 + } 180 + } 181 + 182 + enum cifs_symlink_type { 183 + CIFS_SYMLINK_TYPE_DEFAULT, 184 + CIFS_SYMLINK_TYPE_NONE, 185 + CIFS_SYMLINK_TYPE_NATIVE, 186 + CIFS_SYMLINK_TYPE_UNIX, 187 + CIFS_SYMLINK_TYPE_MFSYMLINKS, 188 + CIFS_SYMLINK_TYPE_SFU, 189 + CIFS_SYMLINK_TYPE_NFS, 190 + CIFS_SYMLINK_TYPE_WSL, 191 + }; 192 + 193 + static inline const char *cifs_symlink_type_str(enum cifs_symlink_type type) 194 + { 195 + switch (type) { 196 + case CIFS_SYMLINK_TYPE_NONE: 197 + return "none"; 198 + case CIFS_SYMLINK_TYPE_NATIVE: 199 + return "native"; 200 + case CIFS_SYMLINK_TYPE_UNIX: 201 + return "unix"; 202 + case CIFS_SYMLINK_TYPE_MFSYMLINKS: 203 + return "mfsymlinks"; 204 + case CIFS_SYMLINK_TYPE_SFU: 205 + return "sfu"; 206 + case CIFS_SYMLINK_TYPE_NFS: 207 + return "nfs"; 208 + case CIFS_SYMLINK_TYPE_WSL: 176 209 return "wsl"; 177 210 default: 178 211 return "unknown"; ··· 252 215 253 216 struct cifs_open_info_data { 254 217 bool adjust_tz; 255 - union { 256 - bool reparse_point; 257 - bool symlink; 258 - }; 218 + bool reparse_point; 259 219 struct { 260 220 /* ioctl response buffer */ 261 221 struct { ··· 260 226 struct kvec iov; 261 227 } io; 262 228 __u32 tag; 263 - union { 264 - struct reparse_data_buffer *buf; 265 - struct reparse_posix_data *posix; 266 - }; 229 + struct reparse_data_buffer *buf; 267 230 } reparse; 268 231 struct { 269 232 __u8 eas[SMB2_WSL_MAX_QUERY_EA_RESP_SIZE]; ··· 782 751 bool sec_kerberosu2u; /* supports U2U Kerberos */ 783 752 bool sec_kerberos; /* supports plain Kerberos */ 784 753 bool sec_mskerberos; /* supports legacy MS Kerberos */ 754 + bool sec_iakerb; /* supports pass-through auth for Kerberos (krb5 proxy) */ 785 755 bool large_buf; /* is current buffer large? */ 786 756 /* use SMBD connection instead of socket */ 787 757 bool rdma; ··· 2150 2118 return "Kerberos"; 2151 2119 case NTLMv2: 2152 2120 return "NTLMv2"; 2121 + case IAKerb: 2122 + return "IAKerb"; 2153 2123 default: 2154 2124 return "Unknown"; 2155 2125 } ··· 2207 2173 2208 2174 static inline void move_cifs_info_to_smb2(struct smb2_file_all_info *dst, const FILE_ALL_INFO *src) 2209 2175 { 2210 - memcpy(dst, src, (size_t)((u8 *)&src->AccessFlags - (u8 *)src)); 2211 - dst->AccessFlags = src->AccessFlags; 2212 - dst->CurrentByteOffset = src->CurrentByteOffset; 2213 - dst->Mode = src->Mode; 2214 - dst->AlignmentRequirement = src->AlignmentRequirement; 2176 + memcpy(dst, src, (size_t)((u8 *)&src->EASize - (u8 *)src)); 2177 + dst->IndexNumber = 0; 2178 + dst->EASize = src->EASize; 2179 + dst->AccessFlags = 0; 2180 + dst->CurrentByteOffset = 0; 2181 + dst->Mode = 0; 2182 + dst->AlignmentRequirement = 0; 2215 2183 dst->FileNameLength = src->FileNameLength; 2216 2184 } 2217 2185
+61 -41
fs/smb/client/cifspdu.h
··· 190 190 */ 191 191 192 192 #define FILE_READ_DATA 0x00000001 /* Data can be read from the file */ 193 + /* or directory child entries can */ 194 + /* be listed together with the */ 195 + /* associated child attributes */ 196 + /* (so the FILE_READ_ATTRIBUTES on */ 197 + /* the child entry is not needed) */ 193 198 #define FILE_WRITE_DATA 0x00000002 /* Data can be written to the file */ 199 + /* or new file can be created in */ 200 + /* the directory */ 194 201 #define FILE_APPEND_DATA 0x00000004 /* Data can be appended to the file */ 202 + /* (for non-local files over SMB it */ 203 + /* is same as FILE_WRITE_DATA) */ 204 + /* or new subdirectory can be */ 205 + /* created in the directory */ 195 206 #define FILE_READ_EA 0x00000008 /* Extended attributes associated */ 196 207 /* with the file can be read */ 197 208 #define FILE_WRITE_EA 0x00000010 /* Extended attributes associated */ 198 209 /* with the file can be written */ 199 210 #define FILE_EXECUTE 0x00000020 /*Data can be read into memory from */ 200 211 /* the file using system paging I/O */ 201 - #define FILE_DELETE_CHILD 0x00000040 212 + /* for executing the file / script */ 213 + /* or right to traverse directory */ 214 + /* (but by default all users have */ 215 + /* directory bypass traverse */ 216 + /* privilege and do not need this */ 217 + /* permission on directories at all)*/ 218 + #define FILE_DELETE_CHILD 0x00000040 /* Child entry can be deleted from */ 219 + /* the directory (so the DELETE on */ 220 + /* the child entry is not needed) */ 202 221 #define FILE_READ_ATTRIBUTES 0x00000080 /* Attributes associated with the */ 203 - /* file can be read */ 222 + /* file or directory can be read */ 204 223 #define FILE_WRITE_ATTRIBUTES 0x00000100 /* Attributes associated with the */ 205 - /* file can be written */ 206 - #define DELETE 0x00010000 /* The file can be deleted */ 207 - #define READ_CONTROL 0x00020000 /* The access control list and */ 208 - /* ownership associated with the */ 209 - /* file can be read */ 210 - #define WRITE_DAC 0x00040000 /* The access control list and */ 211 - /* ownership associated with the */ 212 - /* file can be written. */ 224 + /* file or directory can be written */ 225 + #define DELETE 0x00010000 /* The file or dir can be deleted */ 226 + #define READ_CONTROL 0x00020000 /* The discretionary access control */ 227 + /* list and ownership associated */ 228 + /* with the file or dir can be read */ 229 + #define WRITE_DAC 0x00040000 /* The discretionary access control */ 230 + /* list associated with the file or */ 231 + /* directory can be written */ 213 232 #define WRITE_OWNER 0x00080000 /* Ownership information associated */ 214 - /* with the file can be written */ 233 + /* with the file/dir can be written */ 215 234 #define SYNCHRONIZE 0x00100000 /* The file handle can waited on to */ 216 235 /* synchronize with the completion */ 217 236 /* of an input/output request */ 218 237 #define SYSTEM_SECURITY 0x01000000 /* The system access control list */ 219 - /* can be read and changed */ 220 - #define GENERIC_ALL 0x10000000 221 - #define GENERIC_EXECUTE 0x20000000 222 - #define GENERIC_WRITE 0x40000000 223 - #define GENERIC_READ 0x80000000 224 - /* In summary - Relevant file */ 225 - /* access flags from CIFS are */ 226 - /* file_read_data, file_write_data */ 227 - /* file_execute, file_read_attributes*/ 228 - /* write_dac, and delete. */ 238 + /* associated with the file or */ 239 + /* directory can be read or written */ 240 + /* (cannot be in DACL, can in SACL) */ 241 + #define MAXIMUM_ALLOWED 0x02000000 /* Maximal subset of GENERIC_ALL */ 242 + /* permissions which can be granted */ 243 + /* (cannot be in DACL nor SACL) */ 244 + #define GENERIC_ALL 0x10000000 /* Same as: GENERIC_EXECUTE | */ 245 + /* GENERIC_WRITE | */ 246 + /* GENERIC_READ | */ 247 + /* FILE_DELETE_CHILD | */ 248 + /* DELETE | */ 249 + /* WRITE_DAC | */ 250 + /* WRITE_OWNER */ 251 + /* So GENERIC_ALL contains all bits */ 252 + /* mentioned above except these two */ 253 + /* SYSTEM_SECURITY MAXIMUM_ALLOWED */ 254 + #define GENERIC_EXECUTE 0x20000000 /* Same as: FILE_EXECUTE | */ 255 + /* FILE_READ_ATTRIBUTES | */ 256 + /* READ_CONTROL | */ 257 + /* SYNCHRONIZE */ 258 + #define GENERIC_WRITE 0x40000000 /* Same as: FILE_WRITE_DATA | */ 259 + /* FILE_APPEND_DATA | */ 260 + /* FILE_WRITE_EA | */ 261 + /* FILE_WRITE_ATTRIBUTES | */ 262 + /* READ_CONTROL | */ 263 + /* SYNCHRONIZE */ 264 + #define GENERIC_READ 0x80000000 /* Same as: FILE_READ_DATA | */ 265 + /* FILE_READ_EA | */ 266 + /* FILE_READ_ATTRIBUTES | */ 267 + /* READ_CONTROL | */ 268 + /* SYNCHRONIZE */ 229 269 230 270 #define FILE_READ_RIGHTS (FILE_READ_DATA | FILE_READ_EA | FILE_READ_ATTRIBUTES) 231 271 #define FILE_WRITE_RIGHTS (FILE_WRITE_DATA | FILE_APPEND_DATA \ ··· 1524 1484 __u8 FileName[]; 1525 1485 } __attribute__((packed)); 1526 1486 1527 - /* For IO_REPARSE_TAG_NFS */ 1528 - #define NFS_SPECFILE_LNK 0x00000000014B4E4C 1529 - #define NFS_SPECFILE_CHR 0x0000000000524843 1530 - #define NFS_SPECFILE_BLK 0x00000000004B4C42 1531 - #define NFS_SPECFILE_FIFO 0x000000004F464946 1532 - #define NFS_SPECFILE_SOCK 0x000000004B434F53 1533 - struct reparse_posix_data { 1534 - __le32 ReparseTag; 1535 - __le16 ReparseDataLength; 1536 - __u16 Reserved; 1537 - __le64 InodeType; /* LNK, FIFO, CHR etc. */ 1538 - __u8 DataBuffer[]; 1539 - } __attribute__((packed)); 1540 - 1541 1487 struct cifs_quota_data { 1542 1488 __u32 rsrvd1; /* 0 */ 1543 1489 __u32 sid_size; ··· 2290 2264 __u8 DeletePending; 2291 2265 __u8 Directory; 2292 2266 __u16 Pad2; 2293 - __le64 IndexNumber; 2294 2267 __le32 EASize; 2295 - __le32 AccessFlags; 2296 - __u64 IndexNumber1; 2297 - __le64 CurrentByteOffset; 2298 - __le32 Mode; 2299 - __le32 AlignmentRequirement; 2300 2268 __le32 FileNameLength; 2301 2269 union { 2302 2270 char __pad;
+2 -2
fs/smb/client/cifsproto.h
··· 557 557 const struct nls_table *nls_codepage, 558 558 struct cifs_sb_info *cifs_sb); 559 559 extern int CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, 560 - __u16 fid, struct smb_ntsd **acl_inf, __u32 *buflen); 560 + __u16 fid, struct smb_ntsd **acl_inf, __u32 *buflen, __u32 info); 561 561 extern int CIFSSMBSetCIFSACL(const unsigned int, struct cifs_tcon *, __u16, 562 562 struct smb_ntsd *pntsd, __u32 len, int aclflag); 563 563 extern int cifs_do_get_acl(const unsigned int xid, struct cifs_tcon *tcon, ··· 656 656 int parse_reparse_point(struct reparse_data_buffer *buf, 657 657 u32 plen, struct cifs_sb_info *cifs_sb, 658 658 const char *full_path, 659 - bool unicode, struct cifs_open_info_data *data); 659 + struct cifs_open_info_data *data); 660 660 int __cifs_sfu_make_node(unsigned int xid, struct inode *inode, 661 661 struct dentry *dentry, struct cifs_tcon *tcon, 662 662 const char *full_path, umode_t mode, dev_t dev,
+2 -2
fs/smb/client/cifssmb.c
··· 3369 3369 /* Get Security Descriptor (by handle) from remote server for a file or dir */ 3370 3370 int 3371 3371 CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid, 3372 - struct smb_ntsd **acl_inf, __u32 *pbuflen) 3372 + struct smb_ntsd **acl_inf, __u32 *pbuflen, __u32 info) 3373 3373 { 3374 3374 int rc = 0; 3375 3375 int buf_type = 0; ··· 3392 3392 pSMB->MaxSetupCount = 0; 3393 3393 pSMB->Fid = fid; /* file handle always le */ 3394 3394 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP | 3395 - CIFS_ACL_DACL); 3395 + CIFS_ACL_DACL | info); 3396 3396 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */ 3397 3397 inc_rfc1001_len(pSMB, 11); 3398 3398 iov[0].iov_base = (char *)pSMB;
+4
fs/smb/client/connect.c
··· 2849 2849 return 0; 2850 2850 if (old->ctx->reparse_type != new->ctx->reparse_type) 2851 2851 return 0; 2852 + if (old->ctx->nonativesocket != new->ctx->nonativesocket) 2853 + return 0; 2854 + if (old->ctx->symlink_type != new->ctx->symlink_type) 2855 + return 0; 2852 2856 2853 2857 return 1; 2854 2858 }
+104
fs/smb/client/fs_context.c
··· 133 133 fsparam_flag("rootfs", Opt_rootfs), 134 134 fsparam_flag("compress", Opt_compress), 135 135 fsparam_flag("witness", Opt_witness), 136 + fsparam_flag_no("nativesocket", Opt_nativesocket), 136 137 137 138 /* Mount options which take uid or gid */ 138 139 fsparam_uid("backupuid", Opt_backupuid), ··· 186 185 fsparam_string("cache", Opt_cache), 187 186 fsparam_string("reparse", Opt_reparse), 188 187 fsparam_string("upcall_target", Opt_upcalltarget), 188 + fsparam_string("symlink", Opt_symlink), 189 + fsparam_string("symlinkroot", Opt_symlinkroot), 189 190 190 191 /* Arguments that should be ignored */ 191 192 fsparam_flag("guest", Opt_ignore), ··· 335 332 336 333 static const match_table_t reparse_flavor_tokens = { 337 334 { Opt_reparse_default, "default" }, 335 + { Opt_reparse_none, "none" }, 338 336 { Opt_reparse_nfs, "nfs" }, 339 337 { Opt_reparse_wsl, "wsl" }, 340 338 { Opt_reparse_err, NULL }, ··· 350 346 case Opt_reparse_default: 351 347 ctx->reparse_type = CIFS_REPARSE_TYPE_DEFAULT; 352 348 break; 349 + case Opt_reparse_none: 350 + ctx->reparse_type = CIFS_REPARSE_TYPE_NONE; 351 + break; 353 352 case Opt_reparse_nfs: 354 353 ctx->reparse_type = CIFS_REPARSE_TYPE_NFS; 355 354 break; ··· 361 354 break; 362 355 default: 363 356 cifs_errorf(fc, "bad reparse= option: %s\n", value); 357 + return 1; 358 + } 359 + return 0; 360 + } 361 + 362 + static const match_table_t symlink_flavor_tokens = { 363 + { Opt_symlink_default, "default" }, 364 + { Opt_symlink_none, "none" }, 365 + { Opt_symlink_native, "native" }, 366 + { Opt_symlink_unix, "unix" }, 367 + { Opt_symlink_mfsymlinks, "mfsymlinks" }, 368 + { Opt_symlink_sfu, "sfu" }, 369 + { Opt_symlink_nfs, "nfs" }, 370 + { Opt_symlink_wsl, "wsl" }, 371 + { Opt_symlink_err, NULL }, 372 + }; 373 + 374 + static int parse_symlink_flavor(struct fs_context *fc, char *value, 375 + struct smb3_fs_context *ctx) 376 + { 377 + substring_t args[MAX_OPT_ARGS]; 378 + 379 + switch (match_token(value, symlink_flavor_tokens, args)) { 380 + case Opt_symlink_default: 381 + ctx->symlink_type = CIFS_SYMLINK_TYPE_DEFAULT; 382 + break; 383 + case Opt_symlink_none: 384 + ctx->symlink_type = CIFS_SYMLINK_TYPE_NONE; 385 + break; 386 + case Opt_symlink_native: 387 + ctx->symlink_type = CIFS_SYMLINK_TYPE_NATIVE; 388 + break; 389 + case Opt_symlink_unix: 390 + ctx->symlink_type = CIFS_SYMLINK_TYPE_UNIX; 391 + break; 392 + case Opt_symlink_mfsymlinks: 393 + ctx->symlink_type = CIFS_SYMLINK_TYPE_MFSYMLINKS; 394 + break; 395 + case Opt_symlink_sfu: 396 + ctx->symlink_type = CIFS_SYMLINK_TYPE_SFU; 397 + break; 398 + case Opt_symlink_nfs: 399 + ctx->symlink_type = CIFS_SYMLINK_TYPE_NFS; 400 + break; 401 + case Opt_symlink_wsl: 402 + ctx->symlink_type = CIFS_SYMLINK_TYPE_WSL; 403 + break; 404 + default: 405 + cifs_errorf(fc, "bad symlink= option: %s\n", value); 364 406 return 1; 365 407 } 366 408 return 0; ··· 442 386 new_ctx->iocharset = NULL; 443 387 new_ctx->leaf_fullpath = NULL; 444 388 new_ctx->dns_dom = NULL; 389 + new_ctx->symlinkroot = NULL; 445 390 /* 446 391 * Make sure to stay in sync with smb3_cleanup_fs_context_contents() 447 392 */ ··· 458 401 DUP_CTX_STR(iocharset); 459 402 DUP_CTX_STR(leaf_fullpath); 460 403 DUP_CTX_STR(dns_dom); 404 + DUP_CTX_STR(symlinkroot); 461 405 462 406 return 0; 463 407 } ··· 1785 1727 if (parse_reparse_flavor(fc, param->string, ctx)) 1786 1728 goto cifs_parse_mount_err; 1787 1729 break; 1730 + case Opt_nativesocket: 1731 + ctx->nonativesocket = result.negated; 1732 + break; 1733 + case Opt_symlink: 1734 + if (parse_symlink_flavor(fc, param->string, ctx)) 1735 + goto cifs_parse_mount_err; 1736 + break; 1737 + case Opt_symlinkroot: 1738 + if (param->string[0] != '/') { 1739 + cifs_errorf(fc, "symlinkroot mount options must be absolute path\n"); 1740 + goto cifs_parse_mount_err; 1741 + } 1742 + kfree(ctx->symlinkroot); 1743 + ctx->symlinkroot = kstrdup(param->string, GFP_KERNEL); 1744 + if (!ctx->symlinkroot) 1745 + goto cifs_parse_mount_err; 1746 + break; 1788 1747 } 1789 1748 /* case Opt_ignore: - is ignored as expected ... */ 1790 1749 ··· 1809 1734 cifs_errorf(fc, "multiuser mount option not supported with upcalltarget set as 'mount'\n"); 1810 1735 goto cifs_parse_mount_err; 1811 1736 } 1737 + 1738 + /* 1739 + * By default resolve all native absolute symlinks relative to "/mnt/". 1740 + * Same default has drvfs driver running in WSL for resolving SMB shares. 1741 + */ 1742 + if (!ctx->symlinkroot) 1743 + ctx->symlinkroot = kstrdup("/mnt/", GFP_KERNEL); 1812 1744 1813 1745 return 0; 1814 1746 ··· 1825 1743 kfree_sensitive(ctx->password2); 1826 1744 ctx->password2 = NULL; 1827 1745 return -EINVAL; 1746 + } 1747 + 1748 + enum cifs_symlink_type get_cifs_symlink_type(struct cifs_sb_info *cifs_sb) 1749 + { 1750 + if (cifs_sb->ctx->symlink_type == CIFS_SYMLINK_TYPE_DEFAULT) { 1751 + if (cifs_sb->ctx->mfsymlinks) 1752 + return CIFS_SYMLINK_TYPE_MFSYMLINKS; 1753 + else if (cifs_sb->ctx->sfu_emul) 1754 + return CIFS_SYMLINK_TYPE_SFU; 1755 + else if (cifs_sb->ctx->linux_ext && !cifs_sb->ctx->no_linux_ext) 1756 + return CIFS_SYMLINK_TYPE_UNIX; 1757 + else if (cifs_sb->ctx->reparse_type != CIFS_REPARSE_TYPE_NONE) 1758 + return CIFS_SYMLINK_TYPE_NATIVE; 1759 + else 1760 + return CIFS_SYMLINK_TYPE_NONE; 1761 + } else { 1762 + return cifs_sb->ctx->symlink_type; 1763 + } 1828 1764 } 1829 1765 1830 1766 int smb3_init_fs_context(struct fs_context *fc) ··· 1921 1821 1922 1822 ctx->retrans = 1; 1923 1823 ctx->reparse_type = CIFS_REPARSE_TYPE_DEFAULT; 1824 + ctx->symlink_type = CIFS_SYMLINK_TYPE_DEFAULT; 1825 + ctx->nonativesocket = 0; 1924 1826 1925 1827 /* 1926 1828 * short int override_uid = -1; ··· 1969 1867 ctx->leaf_fullpath = NULL; 1970 1868 kfree(ctx->dns_dom); 1971 1869 ctx->dns_dom = NULL; 1870 + kfree(ctx->symlinkroot); 1871 + ctx->symlinkroot = NULL; 1972 1872 } 1973 1873 1974 1874 void
+21
fs/smb/client/fs_context.h
··· 43 43 44 44 enum cifs_reparse_parm { 45 45 Opt_reparse_default, 46 + Opt_reparse_none, 46 47 Opt_reparse_nfs, 47 48 Opt_reparse_wsl, 48 49 Opt_reparse_err 50 + }; 51 + 52 + enum cifs_symlink_parm { 53 + Opt_symlink_default, 54 + Opt_symlink_none, 55 + Opt_symlink_native, 56 + Opt_symlink_unix, 57 + Opt_symlink_mfsymlinks, 58 + Opt_symlink_sfu, 59 + Opt_symlink_nfs, 60 + Opt_symlink_wsl, 61 + Opt_symlink_err 49 62 }; 50 63 51 64 enum cifs_sec_param { ··· 179 166 Opt_cache, 180 167 Opt_reparse, 181 168 Opt_upcalltarget, 169 + Opt_nativesocket, 170 + Opt_symlink, 171 + Opt_symlinkroot, 182 172 183 173 /* Mount options to be ignored */ 184 174 Opt_ignore, ··· 310 294 struct cifs_ses *dfs_root_ses; 311 295 bool dfs_automount:1; /* set for dfs automount only */ 312 296 enum cifs_reparse_type reparse_type; 297 + enum cifs_symlink_type symlink_type; 298 + bool nonativesocket:1; 313 299 bool dfs_conn:1; /* set for dfs mounts */ 314 300 char *dns_dom; 301 + char *symlinkroot; /* top level directory for native SMB symlinks in absolute format */ 315 302 }; 316 303 317 304 extern const struct fs_parameter_spec smb3_fs_parameters[]; 305 + 306 + extern enum cifs_symlink_type get_cifs_symlink_type(struct cifs_sb_info *cifs_sb); 318 307 319 308 extern int smb3_init_fs_context(struct fs_context *fc); 320 309 extern void smb3_cleanup_fs_context_contents(struct smb3_fs_context *ctx);
+6 -1
fs/smb/client/inode.c
··· 990 990 /* TODO: add support to query reparse tag */ 991 991 data.adjust_tz = false; 992 992 if (data.symlink_target) { 993 - data.symlink = true; 993 + data.reparse_point = true; 994 994 data.reparse.tag = IO_REPARSE_TAG_SYMLINK; 995 995 } 996 996 path = build_path_from_dentry(dentry, page); ··· 1215 1215 rc = server->ops->parse_reparse_point(cifs_sb, 1216 1216 full_path, 1217 1217 iov, data); 1218 + } 1219 + 1220 + if (data->reparse.tag == IO_REPARSE_TAG_SYMLINK && !rc) { 1221 + bool directory = le32_to_cpu(data->fi.Attributes) & ATTR_DIRECTORY; 1222 + rc = smb2_fix_symlink_target_type(&data->symlink_target, directory, cifs_sb); 1218 1223 } 1219 1224 break; 1220 1225 }
+46 -14
fs/smb/client/link.c
··· 18 18 #include "cifs_unicode.h" 19 19 #include "smb2proto.h" 20 20 #include "cifs_ioctl.h" 21 + #include "fs_context.h" 21 22 22 23 /* 23 24 * M-F Symlink Functions - Begin ··· 605 604 cifs_dbg(FYI, "symname is %s\n", symname); 606 605 607 606 /* BB what if DFS and this volume is on different share? BB */ 608 - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { 609 - rc = create_mf_symlink(xid, pTcon, cifs_sb, full_path, symname); 610 - } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { 611 - rc = __cifs_sfu_make_node(xid, inode, direntry, pTcon, 612 - full_path, S_IFLNK, 0, symname); 607 + rc = -EOPNOTSUPP; 608 + switch (get_cifs_symlink_type(cifs_sb)) { 609 + case CIFS_SYMLINK_TYPE_DEFAULT: 610 + /* should not happen, get_cifs_symlink_type() resolves the default */ 611 + break; 612 + 613 + case CIFS_SYMLINK_TYPE_NONE: 614 + break; 615 + 616 + case CIFS_SYMLINK_TYPE_UNIX: 613 617 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 614 - } else if (pTcon->unix_ext) { 615 - rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname, 616 - cifs_sb->local_nls, 617 - cifs_remap(cifs_sb)); 618 + if (pTcon->unix_ext) { 619 + rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, 620 + symname, 621 + cifs_sb->local_nls, 622 + cifs_remap(cifs_sb)); 623 + } 618 624 #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 619 - } else if (server->ops->create_reparse_symlink) { 620 - rc = server->ops->create_reparse_symlink(xid, inode, direntry, 621 - pTcon, full_path, 622 - symname); 623 - goto symlink_exit; 625 + break; 626 + 627 + case CIFS_SYMLINK_TYPE_MFSYMLINKS: 628 + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) { 629 + rc = create_mf_symlink(xid, pTcon, cifs_sb, 630 + full_path, symname); 631 + } 632 + break; 633 + 634 + case CIFS_SYMLINK_TYPE_SFU: 635 + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { 636 + rc = __cifs_sfu_make_node(xid, inode, direntry, pTcon, 637 + full_path, S_IFLNK, 638 + 0, symname); 639 + } 640 + break; 641 + 642 + case CIFS_SYMLINK_TYPE_NATIVE: 643 + case CIFS_SYMLINK_TYPE_NFS: 644 + case CIFS_SYMLINK_TYPE_WSL: 645 + if (server->ops->create_reparse_symlink) { 646 + rc = server->ops->create_reparse_symlink(xid, inode, 647 + direntry, 648 + pTcon, 649 + full_path, 650 + symname); 651 + goto symlink_exit; 652 + } 653 + break; 624 654 } 625 655 626 656 if (rc == 0) {
+9 -1
fs/smb/client/netmisc.c
··· 313 313 ERRDOS, 2215, NT_STATUS_NO_LOGON_SERVERS}, { 314 314 ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_LOGON_SESSION}, { 315 315 ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_PRIVILEGE}, { 316 - ERRDOS, ERRnoaccess, NT_STATUS_PRIVILEGE_NOT_HELD}, { 317 316 ERRHRD, ERRgeneral, NT_STATUS_INVALID_ACCOUNT_NAME}, { 318 317 ERRHRD, ERRgeneral, NT_STATUS_USER_EXISTS}, 319 318 /* { This NT error code was 'sqashed' ··· 869 870 } 870 871 } 871 872 /* else ERRHRD class errors or junk - return EIO */ 873 + 874 + /* special cases for NT status codes which cannot be translated to DOS codes */ 875 + if (smb->Flags2 & SMBFLG2_ERR_STATUS) { 876 + __u32 err = le32_to_cpu(smb->Status.CifsError); 877 + if (err == (NT_STATUS_NOT_A_REPARSE_POINT)) 878 + rc = -ENODATA; 879 + else if (err == (NT_STATUS_PRIVILEGE_NOT_HELD)) 880 + rc = -EPERM; 881 + } 872 882 873 883 cifs_dbg(FYI, "Mapping smb error code 0x%x to POSIX err %d\n", 874 884 le32_to_cpu(smb->Status.CifsError), rc);
+1
fs/smb/client/nterr.c
··· 674 674 {"NT_STATUS_QUOTA_LIST_INCONSISTENT", 675 675 NT_STATUS_QUOTA_LIST_INCONSISTENT}, 676 676 {"NT_STATUS_FILE_IS_OFFLINE", NT_STATUS_FILE_IS_OFFLINE}, 677 + {"NT_STATUS_NOT_A_REPARSE_POINT", NT_STATUS_NOT_A_REPARSE_POINT}, 677 678 {"NT_STATUS_NO_MORE_ENTRIES", NT_STATUS_NO_MORE_ENTRIES}, 678 679 {"NT_STATUS_MORE_ENTRIES", NT_STATUS_MORE_ENTRIES}, 679 680 {"NT_STATUS_SOME_UNMAPPED", NT_STATUS_SOME_UNMAPPED},
+1
fs/smb/client/nterr.h
··· 546 546 #define NT_STATUS_TOO_MANY_LINKS 0xC0000000 | 0x0265 547 547 #define NT_STATUS_QUOTA_LIST_INCONSISTENT 0xC0000000 | 0x0266 548 548 #define NT_STATUS_FILE_IS_OFFLINE 0xC0000000 | 0x0267 549 + #define NT_STATUS_NOT_A_REPARSE_POINT 0xC0000000 | 0x0275 549 550 #define NT_STATUS_NO_SUCH_JOB 0xC0000000 | 0xEDE /* scheduler */ 550 551 551 552 #endif /* _NTERR_H */
+448 -71
fs/smb/client/reparse.c
··· 14 14 #include "fs_context.h" 15 15 #include "reparse.h" 16 16 17 + static int mknod_nfs(unsigned int xid, struct inode *inode, 18 + struct dentry *dentry, struct cifs_tcon *tcon, 19 + const char *full_path, umode_t mode, dev_t dev, 20 + const char *symname); 21 + 22 + static int mknod_wsl(unsigned int xid, struct inode *inode, 23 + struct dentry *dentry, struct cifs_tcon *tcon, 24 + const char *full_path, umode_t mode, dev_t dev, 25 + const char *symname); 26 + 27 + static int create_native_symlink(const unsigned int xid, struct inode *inode, 28 + struct dentry *dentry, struct cifs_tcon *tcon, 29 + const char *full_path, const char *symname); 30 + 17 31 static int detect_directory_symlink_target(struct cifs_sb_info *cifs_sb, 18 32 const unsigned int xid, 19 33 const char *full_path, ··· 38 24 struct dentry *dentry, struct cifs_tcon *tcon, 39 25 const char *full_path, const char *symname) 40 26 { 27 + switch (get_cifs_symlink_type(CIFS_SB(inode->i_sb))) { 28 + case CIFS_SYMLINK_TYPE_NATIVE: 29 + return create_native_symlink(xid, inode, dentry, tcon, full_path, symname); 30 + case CIFS_SYMLINK_TYPE_NFS: 31 + return mknod_nfs(xid, inode, dentry, tcon, full_path, S_IFLNK, 0, symname); 32 + case CIFS_SYMLINK_TYPE_WSL: 33 + return mknod_wsl(xid, inode, dentry, tcon, full_path, S_IFLNK, 0, symname); 34 + default: 35 + return -EOPNOTSUPP; 36 + } 37 + } 38 + 39 + static int create_native_symlink(const unsigned int xid, struct inode *inode, 40 + struct dentry *dentry, struct cifs_tcon *tcon, 41 + const char *full_path, const char *symname) 42 + { 41 43 struct reparse_symlink_data_buffer *buf = NULL; 42 - struct cifs_open_info_data data; 44 + struct cifs_open_info_data data = {}; 43 45 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 44 46 struct inode *new; 45 47 struct kvec iov; 46 - __le16 *path; 48 + __le16 *path = NULL; 47 49 bool directory; 48 - char *sym, sep = CIFS_DIR_SEP(cifs_sb); 49 - u16 len, plen; 50 + char *symlink_target = NULL; 51 + char *sym = NULL; 52 + char sep = CIFS_DIR_SEP(cifs_sb); 53 + u16 len, plen, poff, slen; 50 54 int rc = 0; 51 55 52 56 if (strlen(symname) > REPARSE_SYM_PATH_MAX) 53 57 return -ENAMETOOLONG; 54 58 55 - sym = kstrdup(symname, GFP_KERNEL); 56 - if (!sym) 57 - return -ENOMEM; 59 + symlink_target = kstrdup(symname, GFP_KERNEL); 60 + if (!symlink_target) { 61 + rc = -ENOMEM; 62 + goto out; 63 + } 58 64 59 65 data = (struct cifs_open_info_data) { 60 66 .reparse_point = true, 61 67 .reparse = { .tag = IO_REPARSE_TAG_SYMLINK, }, 62 - .symlink_target = sym, 68 + .symlink_target = symlink_target, 63 69 }; 64 70 65 - convert_delimiter(sym, sep); 71 + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) && symname[0] == '/') { 72 + /* 73 + * This is a request to create an absolute symlink on the server 74 + * which does not support POSIX paths, and expects symlink in 75 + * NT-style path. So convert absolute Linux symlink target path 76 + * to the absolute NT-style path. Root of the NT-style path for 77 + * symlinks is specified in "symlinkroot" mount option. This will 78 + * ensure compatibility of this symlink stored in absolute form 79 + * on the SMB server. 80 + */ 81 + if (!strstarts(symname, cifs_sb->ctx->symlinkroot)) { 82 + /* 83 + * If the absolute Linux symlink target path is not 84 + * inside "symlinkroot" location then there is no way 85 + * to convert such Linux symlink to NT-style path. 86 + */ 87 + cifs_dbg(VFS, 88 + "absolute symlink '%s' cannot be converted to NT format " 89 + "because it is outside of symlinkroot='%s'\n", 90 + symname, cifs_sb->ctx->symlinkroot); 91 + rc = -EINVAL; 92 + goto out; 93 + } 94 + len = strlen(cifs_sb->ctx->symlinkroot); 95 + if (cifs_sb->ctx->symlinkroot[len-1] != '/') 96 + len++; 97 + if (symname[len] >= 'a' && symname[len] <= 'z' && 98 + (symname[len+1] == '/' || symname[len+1] == '\0')) { 99 + /* 100 + * Symlink points to Linux target /symlinkroot/x/path/... 101 + * where 'x' is the lowercase local Windows drive. 102 + * NT-style path for 'x' has common form \??\X:\path\... 103 + * with uppercase local Windows drive. 104 + */ 105 + int common_path_len = strlen(symname+len+1)+1; 106 + sym = kzalloc(6+common_path_len, GFP_KERNEL); 107 + if (!sym) { 108 + rc = -ENOMEM; 109 + goto out; 110 + } 111 + memcpy(sym, "\\??\\", 4); 112 + sym[4] = symname[len] - ('a'-'A'); 113 + sym[5] = ':'; 114 + memcpy(sym+6, symname+len+1, common_path_len); 115 + } else { 116 + /* Unhandled absolute symlink. Report an error. */ 117 + cifs_dbg( 118 + VFS, 119 + "absolute symlink '%s' cannot be converted to NT format " 120 + "because it points to unknown target\n", 121 + symname); 122 + rc = -EINVAL; 123 + goto out; 124 + } 125 + } else { 126 + /* 127 + * This is request to either create an absolute symlink on 128 + * server which expects POSIX paths or it is an request to 129 + * create a relative symlink from the current directory. 130 + * These paths have same format as relative SMB symlinks, 131 + * so no conversion is needed. So just take symname as-is. 132 + */ 133 + sym = kstrdup(symname, GFP_KERNEL); 134 + if (!sym) { 135 + rc = -ENOMEM; 136 + goto out; 137 + } 138 + } 139 + 140 + if (sep == '\\') 141 + convert_delimiter(sym, sep); 142 + 143 + /* 144 + * For absolute NT symlinks it is required to pass also leading 145 + * backslash and to not mangle NT object prefix "\\??\\" and not to 146 + * mangle colon in drive letter. But cifs_convert_path_to_utf16() 147 + * removes leading backslash and replaces '?' and ':'. So temporary 148 + * mask these characters in NT object prefix by '_' and then change 149 + * them back. 150 + */ 151 + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) && symname[0] == '/') 152 + sym[0] = sym[1] = sym[2] = sym[5] = '_'; 153 + 66 154 path = cifs_convert_path_to_utf16(sym, cifs_sb); 67 155 if (!path) { 68 156 rc = -ENOMEM; 69 157 goto out; 158 + } 159 + 160 + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) && symname[0] == '/') { 161 + sym[0] = '\\'; 162 + sym[1] = sym[2] = '?'; 163 + sym[5] = ':'; 164 + path[0] = cpu_to_le16('\\'); 165 + path[1] = path[2] = cpu_to_le16('?'); 166 + path[5] = cpu_to_le16(':'); 70 167 } 71 168 72 169 /* ··· 192 67 if (rc < 0) 193 68 goto out; 194 69 195 - plen = 2 * UniStrnlen((wchar_t *)path, REPARSE_SYM_PATH_MAX); 196 - len = sizeof(*buf) + plen * 2; 70 + slen = 2 * UniStrnlen((wchar_t *)path, REPARSE_SYM_PATH_MAX); 71 + poff = 0; 72 + plen = slen; 73 + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) && symname[0] == '/') { 74 + /* 75 + * For absolute NT symlinks skip leading "\\??\\" in PrintName as 76 + * PrintName is user visible location in DOS/Win32 format (not in NT format). 77 + */ 78 + poff = 4; 79 + plen -= 2 * poff; 80 + } 81 + len = sizeof(*buf) + plen + slen; 197 82 buf = kzalloc(len, GFP_KERNEL); 198 83 if (!buf) { 199 84 rc = -ENOMEM; ··· 212 77 213 78 buf->ReparseTag = cpu_to_le32(IO_REPARSE_TAG_SYMLINK); 214 79 buf->ReparseDataLength = cpu_to_le16(len - sizeof(struct reparse_data_buffer)); 80 + 215 81 buf->SubstituteNameOffset = cpu_to_le16(plen); 216 - buf->SubstituteNameLength = cpu_to_le16(plen); 217 - memcpy(&buf->PathBuffer[plen], path, plen); 82 + buf->SubstituteNameLength = cpu_to_le16(slen); 83 + memcpy(&buf->PathBuffer[plen], path, slen); 84 + 218 85 buf->PrintNameOffset = 0; 219 86 buf->PrintNameLength = cpu_to_le16(plen); 220 - memcpy(buf->PathBuffer, path, plen); 221 - buf->Flags = cpu_to_le32(*symname != '/' ? SYMLINK_FLAG_RELATIVE : 0); 222 - if (*sym != sep) 223 - buf->Flags = cpu_to_le32(SYMLINK_FLAG_RELATIVE); 87 + memcpy(buf->PathBuffer, path+poff, plen); 224 88 225 - convert_delimiter(sym, '/'); 89 + buf->Flags = cpu_to_le32(*symname != '/' ? SYMLINK_FLAG_RELATIVE : 0); 90 + 226 91 iov.iov_base = buf; 227 92 iov.iov_len = len; 228 93 new = smb2_get_reparse_inode(&data, inode->i_sb, xid, ··· 233 98 else 234 99 rc = PTR_ERR(new); 235 100 out: 101 + kfree(sym); 236 102 kfree(path); 237 103 cifs_free_open_info(&data); 238 104 kfree(buf); ··· 378 242 return 0; 379 243 } 380 244 381 - static int nfs_set_reparse_buf(struct reparse_posix_data *buf, 245 + static int create_native_socket(const unsigned int xid, struct inode *inode, 246 + struct dentry *dentry, struct cifs_tcon *tcon, 247 + const char *full_path) 248 + { 249 + struct reparse_data_buffer buf = { 250 + .ReparseTag = cpu_to_le32(IO_REPARSE_TAG_AF_UNIX), 251 + .ReparseDataLength = cpu_to_le16(0), 252 + }; 253 + struct cifs_open_info_data data = { 254 + .reparse_point = true, 255 + .reparse = { .tag = IO_REPARSE_TAG_AF_UNIX, .buf = &buf, }, 256 + }; 257 + struct kvec iov = { 258 + .iov_base = &buf, 259 + .iov_len = sizeof(buf), 260 + }; 261 + struct inode *new; 262 + int rc = 0; 263 + 264 + new = smb2_get_reparse_inode(&data, inode->i_sb, xid, 265 + tcon, full_path, false, &iov, NULL); 266 + if (!IS_ERR(new)) 267 + d_instantiate(dentry, new); 268 + else 269 + rc = PTR_ERR(new); 270 + cifs_free_open_info(&data); 271 + return rc; 272 + } 273 + 274 + static int nfs_set_reparse_buf(struct reparse_nfs_data_buffer *buf, 382 275 mode_t mode, dev_t dev, 276 + __le16 *symname_utf16, 277 + int symname_utf16_len, 383 278 struct kvec *iov) 384 279 { 385 280 u64 type; ··· 421 254 switch ((type = reparse_mode_nfs_type(mode))) { 422 255 case NFS_SPECFILE_BLK: 423 256 case NFS_SPECFILE_CHR: 424 - dlen = sizeof(__le64); 257 + dlen = 2 * sizeof(__le32); 258 + ((__le32 *)buf->DataBuffer)[0] = cpu_to_le32(MAJOR(dev)); 259 + ((__le32 *)buf->DataBuffer)[1] = cpu_to_le32(MINOR(dev)); 260 + break; 261 + case NFS_SPECFILE_LNK: 262 + dlen = symname_utf16_len; 263 + memcpy(buf->DataBuffer, symname_utf16, symname_utf16_len); 425 264 break; 426 265 case NFS_SPECFILE_FIFO: 427 266 case NFS_SPECFILE_SOCK: ··· 442 269 buf->InodeType = cpu_to_le64(type); 443 270 buf->ReparseDataLength = cpu_to_le16(len + dlen - 444 271 sizeof(struct reparse_data_buffer)); 445 - *(__le64 *)buf->DataBuffer = cpu_to_le64(((u64)MINOR(dev) << 32) | 446 - MAJOR(dev)); 447 272 iov->iov_base = buf; 448 273 iov->iov_len = len + dlen; 449 274 return 0; ··· 449 278 450 279 static int mknod_nfs(unsigned int xid, struct inode *inode, 451 280 struct dentry *dentry, struct cifs_tcon *tcon, 452 - const char *full_path, umode_t mode, dev_t dev) 281 + const char *full_path, umode_t mode, dev_t dev, 282 + const char *symname) 453 283 { 284 + struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 454 285 struct cifs_open_info_data data; 455 - struct reparse_posix_data *p; 286 + struct reparse_nfs_data_buffer *p = NULL; 287 + __le16 *symname_utf16 = NULL; 288 + int symname_utf16_len = 0; 456 289 struct inode *new; 457 290 struct kvec iov; 458 291 __u8 buf[sizeof(*p) + sizeof(__le64)]; 459 292 int rc; 460 293 461 - p = (struct reparse_posix_data *)buf; 462 - rc = nfs_set_reparse_buf(p, mode, dev, &iov); 294 + if (S_ISLNK(mode)) { 295 + symname_utf16 = cifs_strndup_to_utf16(symname, strlen(symname), 296 + &symname_utf16_len, 297 + cifs_sb->local_nls, 298 + NO_MAP_UNI_RSVD); 299 + if (!symname_utf16) { 300 + rc = -ENOMEM; 301 + goto out; 302 + } 303 + symname_utf16_len -= 2; /* symlink is without trailing wide-nul */ 304 + p = kzalloc(sizeof(*p) + symname_utf16_len, GFP_KERNEL); 305 + if (!p) { 306 + rc = -ENOMEM; 307 + goto out; 308 + } 309 + } else { 310 + p = (struct reparse_nfs_data_buffer *)buf; 311 + } 312 + rc = nfs_set_reparse_buf(p, mode, dev, symname_utf16, symname_utf16_len, &iov); 463 313 if (rc) 464 - return rc; 314 + goto out; 465 315 466 316 data = (struct cifs_open_info_data) { 467 317 .reparse_point = true, 468 - .reparse = { .tag = IO_REPARSE_TAG_NFS, .posix = p, }, 318 + .reparse = { .tag = IO_REPARSE_TAG_NFS, .buf = (struct reparse_data_buffer *)p, }, 319 + .symlink_target = kstrdup(symname, GFP_KERNEL), 469 320 }; 470 321 471 322 new = smb2_get_reparse_inode(&data, inode->i_sb, xid, ··· 497 304 else 498 305 rc = PTR_ERR(new); 499 306 cifs_free_open_info(&data); 307 + out: 308 + if (S_ISLNK(mode)) { 309 + kfree(symname_utf16); 310 + kfree(p); 311 + } 500 312 return rc; 501 313 } 502 314 503 - static int wsl_set_reparse_buf(struct reparse_data_buffer *buf, 504 - mode_t mode, struct kvec *iov) 315 + static int wsl_set_reparse_buf(struct reparse_data_buffer **buf, 316 + mode_t mode, const char *symname, 317 + struct cifs_sb_info *cifs_sb, 318 + struct kvec *iov) 505 319 { 320 + struct reparse_wsl_symlink_data_buffer *symlink_buf; 321 + __le16 *symname_utf16; 322 + int symname_utf16_len; 323 + int symname_utf8_maxlen; 324 + int symname_utf8_len; 325 + size_t buf_len; 506 326 u32 tag; 507 327 508 328 switch ((tag = reparse_mode_wsl_tag(mode))) { ··· 523 317 case IO_REPARSE_TAG_LX_CHR: 524 318 case IO_REPARSE_TAG_LX_FIFO: 525 319 case IO_REPARSE_TAG_AF_UNIX: 320 + buf_len = sizeof(struct reparse_data_buffer); 321 + *buf = kzalloc(buf_len, GFP_KERNEL); 322 + if (!*buf) 323 + return -ENOMEM; 324 + break; 325 + case IO_REPARSE_TAG_LX_SYMLINK: 326 + symname_utf16 = cifs_strndup_to_utf16(symname, strlen(symname), 327 + &symname_utf16_len, 328 + cifs_sb->local_nls, 329 + NO_MAP_UNI_RSVD); 330 + if (!symname_utf16) 331 + return -ENOMEM; 332 + symname_utf8_maxlen = symname_utf16_len/2*3; 333 + symlink_buf = kzalloc(sizeof(struct reparse_wsl_symlink_data_buffer) + 334 + symname_utf8_maxlen, GFP_KERNEL); 335 + if (!symlink_buf) { 336 + kfree(symname_utf16); 337 + return -ENOMEM; 338 + } 339 + /* Flag 0x02000000 is unknown, but all wsl symlinks have this value */ 340 + symlink_buf->Flags = cpu_to_le32(0x02000000); 341 + /* PathBuffer is in UTF-8 but without trailing null-term byte */ 342 + symname_utf8_len = utf16s_to_utf8s((wchar_t *)symname_utf16, symname_utf16_len/2, 343 + UTF16_LITTLE_ENDIAN, 344 + symlink_buf->PathBuffer, 345 + symname_utf8_maxlen); 346 + *buf = (struct reparse_data_buffer *)symlink_buf; 347 + buf_len = sizeof(struct reparse_wsl_symlink_data_buffer) + symname_utf8_len; 348 + kfree(symname_utf16); 526 349 break; 527 350 default: 528 351 return -EOPNOTSUPP; 529 352 } 530 353 531 - buf->ReparseTag = cpu_to_le32(tag); 532 - buf->Reserved = 0; 533 - buf->ReparseDataLength = 0; 534 - iov->iov_base = buf; 535 - iov->iov_len = sizeof(*buf); 354 + (*buf)->ReparseTag = cpu_to_le32(tag); 355 + (*buf)->Reserved = 0; 356 + (*buf)->ReparseDataLength = cpu_to_le16(buf_len - sizeof(struct reparse_data_buffer)); 357 + iov->iov_base = *buf; 358 + iov->iov_len = buf_len; 536 359 return 0; 537 360 } 538 361 ··· 650 415 651 416 static int mknod_wsl(unsigned int xid, struct inode *inode, 652 417 struct dentry *dentry, struct cifs_tcon *tcon, 653 - const char *full_path, umode_t mode, dev_t dev) 418 + const char *full_path, umode_t mode, dev_t dev, 419 + const char *symname) 654 420 { 421 + struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 655 422 struct cifs_open_info_data data; 656 - struct reparse_data_buffer buf; 423 + struct reparse_data_buffer *buf; 657 424 struct smb2_create_ea_ctx *cc; 658 425 struct inode *new; 659 426 unsigned int len; 660 427 struct kvec reparse_iov, xattr_iov; 661 428 int rc; 662 429 663 - rc = wsl_set_reparse_buf(&buf, mode, &reparse_iov); 430 + rc = wsl_set_reparse_buf(&buf, mode, symname, cifs_sb, &reparse_iov); 664 431 if (rc) 665 432 return rc; 666 433 667 434 rc = wsl_set_xattrs(inode, mode, dev, &xattr_iov); 668 - if (rc) 435 + if (rc) { 436 + kfree(buf); 669 437 return rc; 438 + } 670 439 671 440 data = (struct cifs_open_info_data) { 672 441 .reparse_point = true, 673 - .reparse = { .tag = le32_to_cpu(buf.ReparseTag), .buf = &buf, }, 442 + .reparse = { .tag = le32_to_cpu(buf->ReparseTag), .buf = buf, }, 443 + .symlink_target = kstrdup(symname, GFP_KERNEL), 674 444 }; 675 445 676 446 cc = xattr_iov.iov_base; ··· 692 452 rc = PTR_ERR(new); 693 453 cifs_free_open_info(&data); 694 454 kfree(xattr_iov.iov_base); 455 + kfree(buf); 695 456 return rc; 696 457 } 697 458 ··· 701 460 const char *full_path, umode_t mode, dev_t dev) 702 461 { 703 462 struct smb3_fs_context *ctx = CIFS_SB(inode->i_sb)->ctx; 704 - int rc = -EOPNOTSUPP; 463 + 464 + if (S_ISSOCK(mode) && !ctx->nonativesocket && ctx->reparse_type != CIFS_REPARSE_TYPE_NONE) 465 + return create_native_socket(xid, inode, dentry, tcon, full_path); 705 466 706 467 switch (ctx->reparse_type) { 707 468 case CIFS_REPARSE_TYPE_NFS: 708 - rc = mknod_nfs(xid, inode, dentry, tcon, full_path, mode, dev); 709 - break; 469 + return mknod_nfs(xid, inode, dentry, tcon, full_path, mode, dev, NULL); 710 470 case CIFS_REPARSE_TYPE_WSL: 711 - rc = mknod_wsl(xid, inode, dentry, tcon, full_path, mode, dev); 712 - break; 471 + return mknod_wsl(xid, inode, dentry, tcon, full_path, mode, dev, NULL); 472 + default: 473 + return -EOPNOTSUPP; 713 474 } 714 - return rc; 715 475 } 716 476 717 477 /* See MS-FSCC 2.1.2.6 for the 'NFS' style reparse tags */ 718 - static int parse_reparse_posix(struct reparse_posix_data *buf, 478 + static int parse_reparse_nfs(struct reparse_nfs_data_buffer *buf, 719 479 struct cifs_sb_info *cifs_sb, 720 480 struct cifs_open_info_data *data) 721 481 { ··· 778 536 } 779 537 780 538 int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len, 781 - bool unicode, bool relative, 539 + bool relative, 782 540 const char *full_path, 783 541 struct cifs_sb_info *cifs_sb) 784 542 { 785 543 char sep = CIFS_DIR_SEP(cifs_sb); 786 544 char *linux_target = NULL; 787 545 char *smb_target = NULL; 546 + int symlinkroot_len; 547 + int abs_path_len; 548 + char *abs_path; 788 549 int levels; 789 550 int rc; 790 551 int i; 791 552 792 - /* Check that length it valid for unicode/non-unicode mode */ 793 - if (!len || (unicode && (len % 2))) { 553 + /* Check that length it valid */ 554 + if (!len || (len % 2)) { 794 555 cifs_dbg(VFS, "srv returned malformed symlink buffer\n"); 795 556 rc = -EIO; 796 557 goto out; 797 558 } 798 559 799 560 /* 800 - * Check that buffer does not contain UTF-16 null codepoint in unicode 801 - * mode or null byte in non-unicode mode because Linux cannot process 802 - * symlink with null byte. 561 + * Check that buffer does not contain UTF-16 null codepoint 562 + * because Linux cannot process symlink with null byte. 803 563 */ 804 - if ((unicode && UniStrnlen((wchar_t *)buf, len/2) != len/2) || 805 - (!unicode && strnlen(buf, len) != len)) { 564 + if (UniStrnlen((wchar_t *)buf, len/2) != len/2) { 806 565 cifs_dbg(VFS, "srv returned null byte in native symlink target location\n"); 807 566 rc = -EIO; 808 567 goto out; 809 568 } 810 569 811 - smb_target = cifs_strndup_from_utf16(buf, len, unicode, cifs_sb->local_nls); 570 + smb_target = cifs_strndup_from_utf16(buf, len, true, cifs_sb->local_nls); 812 571 if (!smb_target) { 813 572 rc = -ENOMEM; 814 573 goto out; 815 574 } 816 575 817 - if (smb_target[0] == sep && relative) { 576 + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) && !relative) { 577 + /* 578 + * This is an absolute symlink from the server which does not 579 + * support POSIX paths, so the symlink is in NT-style path. 580 + * So convert it to absolute Linux symlink target path. Root of 581 + * the NT-style path for symlinks is specified in "symlinkroot" 582 + * mount option. 583 + * 584 + * Root of the DOS and Win32 paths is at NT path \??\ 585 + * It means that DOS/Win32 path C:\folder\file.txt is 586 + * NT path \??\C:\folder\file.txt 587 + * 588 + * NT systems have some well-known object symlinks in their NT 589 + * hierarchy, which is needed to take into account when resolving 590 + * other symlinks. Most commonly used symlink paths are: 591 + * \?? -> \GLOBAL?? 592 + * \DosDevices -> \?? 593 + * \GLOBAL??\GLOBALROOT -> \ 594 + * \GLOBAL??\Global -> \GLOBAL?? 595 + * \GLOBAL??\NUL -> \Device\Null 596 + * \GLOBAL??\UNC -> \Device\Mup 597 + * \GLOBAL??\PhysicalDrive0 -> \Device\Harddisk0\DR0 (for each harddisk) 598 + * \GLOBAL??\A: -> \Device\Floppy0 (if A: is the first floppy) 599 + * \GLOBAL??\C: -> \Device\HarddiskVolume1 (if C: is the first harddisk) 600 + * \GLOBAL??\D: -> \Device\CdRom0 (if D: is first cdrom) 601 + * \SystemRoot -> \Device\Harddisk0\Partition1\WINDOWS (or where is NT system installed) 602 + * \Volume{...} -> \Device\HarddiskVolume1 (where ... is system generated guid) 603 + * 604 + * In most common cases, absolute NT symlinks points to path on 605 + * DOS/Win32 drive letter, system-specific Volume or on UNC share. 606 + * Here are few examples of commonly used absolute NT symlinks 607 + * created by mklink.exe tool: 608 + * \??\C:\folder\file.txt 609 + * \??\\C:\folder\file.txt 610 + * \??\UNC\server\share\file.txt 611 + * \??\\UNC\server\share\file.txt 612 + * \??\Volume{b75e2c83-0000-0000-0000-602f00000000}\folder\file.txt 613 + * 614 + * It means that the most common path prefix \??\ is also NT path 615 + * symlink (to \GLOBAL??). It is less common that second path 616 + * separator is double backslash, but it is valid. 617 + * 618 + * Volume guid is randomly generated by the target system and so 619 + * only the target system knows the mapping between guid and the 620 + * hardisk number. Over SMB it is not possible to resolve this 621 + * mapping, therefore symlinks pointing to target location of 622 + * volume guids are totally unusable over SMB. 623 + * 624 + * For now parse only symlink paths available for DOS and Win32. 625 + * Those are paths with \??\ prefix or paths which points to \??\ 626 + * via other NT symlink (\DosDevices\, \GLOBAL??\, ...). 627 + */ 628 + abs_path = smb_target; 629 + globalroot: 630 + if (strstarts(abs_path, "\\??\\")) 631 + abs_path += sizeof("\\??\\")-1; 632 + else if (strstarts(abs_path, "\\DosDevices\\")) 633 + abs_path += sizeof("\\DosDevices\\")-1; 634 + else if (strstarts(abs_path, "\\GLOBAL??\\")) 635 + abs_path += sizeof("\\GLOBAL??\\")-1; 636 + else { 637 + /* Unhandled absolute symlink, points outside of DOS/Win32 */ 638 + cifs_dbg(VFS, 639 + "absolute symlink '%s' cannot be converted from NT format " 640 + "because points to unknown target\n", 641 + smb_target); 642 + rc = -EIO; 643 + goto out; 644 + } 645 + 646 + /* Sometimes path separator after \?? is double backslash */ 647 + if (abs_path[0] == '\\') 648 + abs_path++; 649 + 650 + while (strstarts(abs_path, "Global\\")) 651 + abs_path += sizeof("Global\\")-1; 652 + 653 + if (strstarts(abs_path, "GLOBALROOT\\")) { 654 + /* Label globalroot requires path with leading '\\', so do not trim '\\' */ 655 + abs_path += sizeof("GLOBALROOT")-1; 656 + goto globalroot; 657 + } 658 + 659 + /* For now parse only paths to drive letters */ 660 + if (((abs_path[0] >= 'A' && abs_path[0] <= 'Z') || 661 + (abs_path[0] >= 'a' && abs_path[0] <= 'z')) && 662 + abs_path[1] == ':' && 663 + (abs_path[2] == '\\' || abs_path[2] == '\0')) { 664 + /* Convert drive letter to lowercase and drop colon */ 665 + char drive_letter = abs_path[0]; 666 + if (drive_letter >= 'A' && drive_letter <= 'Z') 667 + drive_letter += 'a'-'A'; 668 + abs_path++; 669 + abs_path[0] = drive_letter; 670 + } else { 671 + /* Unhandled absolute symlink. Report an error. */ 672 + cifs_dbg(VFS, 673 + "absolute symlink '%s' cannot be converted from NT format " 674 + "because points to unknown target\n", 675 + smb_target); 676 + rc = -EIO; 677 + goto out; 678 + } 679 + 680 + abs_path_len = strlen(abs_path)+1; 681 + symlinkroot_len = strlen(cifs_sb->ctx->symlinkroot); 682 + if (cifs_sb->ctx->symlinkroot[symlinkroot_len-1] == '/') 683 + symlinkroot_len--; 684 + linux_target = kmalloc(symlinkroot_len + 1 + abs_path_len, GFP_KERNEL); 685 + if (!linux_target) { 686 + rc = -ENOMEM; 687 + goto out; 688 + } 689 + memcpy(linux_target, cifs_sb->ctx->symlinkroot, symlinkroot_len); 690 + linux_target[symlinkroot_len] = '/'; 691 + memcpy(linux_target + symlinkroot_len + 1, abs_path, abs_path_len); 692 + } else if (smb_target[0] == sep && relative) { 818 693 /* 819 694 * This is a relative SMB symlink from the top of the share, 820 695 * which is the top level directory of the Linux mount point. ··· 960 601 } 961 602 memcpy(linux_target + levels*3, smb_target+1, smb_target_len); /* +1 to skip leading sep */ 962 603 } else { 604 + /* 605 + * This is either an absolute symlink in POSIX-style format 606 + * or relative SMB symlink from the current directory. 607 + * These paths have same format as Linux symlinks, so no 608 + * conversion is needed. 609 + */ 963 610 linux_target = smb_target; 964 611 smb_target = NULL; 965 612 } ··· 985 620 return rc; 986 621 } 987 622 988 - static int parse_reparse_symlink(struct reparse_symlink_data_buffer *sym, 989 - u32 plen, bool unicode, 623 + static int parse_reparse_native_symlink(struct reparse_symlink_data_buffer *sym, 624 + u32 plen, 990 625 struct cifs_sb_info *cifs_sb, 991 626 const char *full_path, 992 627 struct cifs_open_info_data *data) ··· 1006 641 return smb2_parse_native_symlink(&data->symlink_target, 1007 642 sym->PathBuffer + offs, 1008 643 len, 1009 - unicode, 1010 644 le32_to_cpu(sym->Flags) & SYMLINK_FLAG_RELATIVE, 1011 645 full_path, 1012 646 cifs_sb); ··· 1060 696 int parse_reparse_point(struct reparse_data_buffer *buf, 1061 697 u32 plen, struct cifs_sb_info *cifs_sb, 1062 698 const char *full_path, 1063 - bool unicode, struct cifs_open_info_data *data) 699 + struct cifs_open_info_data *data) 1064 700 { 1065 701 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 1066 702 ··· 1069 705 /* See MS-FSCC 2.1.2 */ 1070 706 switch (le32_to_cpu(buf->ReparseTag)) { 1071 707 case IO_REPARSE_TAG_NFS: 1072 - return parse_reparse_posix((struct reparse_posix_data *)buf, 708 + return parse_reparse_nfs((struct reparse_nfs_data_buffer *)buf, 1073 709 cifs_sb, data); 1074 710 case IO_REPARSE_TAG_SYMLINK: 1075 - return parse_reparse_symlink( 711 + return parse_reparse_native_symlink( 1076 712 (struct reparse_symlink_data_buffer *)buf, 1077 - plen, unicode, cifs_sb, full_path, data); 713 + plen, cifs_sb, full_path, data); 1078 714 case IO_REPARSE_TAG_LX_SYMLINK: 1079 715 return parse_reparse_wsl_symlink( 1080 716 (struct reparse_wsl_symlink_data_buffer *)buf, ··· 1108 744 1109 745 buf = (struct reparse_data_buffer *)((u8 *)io + 1110 746 le32_to_cpu(io->OutputOffset)); 1111 - return parse_reparse_point(buf, plen, cifs_sb, full_path, true, data); 747 + return parse_reparse_point(buf, plen, cifs_sb, full_path, data); 1112 748 } 1113 749 1114 - static void wsl_to_fattr(struct cifs_open_info_data *data, 750 + static bool wsl_to_fattr(struct cifs_open_info_data *data, 1115 751 struct cifs_sb_info *cifs_sb, 1116 752 u32 tag, struct cifs_fattr *fattr) 1117 753 { 1118 754 struct smb2_file_full_ea_info *ea; 755 + bool have_xattr_dev = false; 1119 756 u32 next = 0; 1120 757 1121 758 switch (tag) { ··· 1159 794 fattr->cf_uid = wsl_make_kuid(cifs_sb, v); 1160 795 else if (!strncmp(name, SMB2_WSL_XATTR_GID, nlen)) 1161 796 fattr->cf_gid = wsl_make_kgid(cifs_sb, v); 1162 - else if (!strncmp(name, SMB2_WSL_XATTR_MODE, nlen)) 797 + else if (!strncmp(name, SMB2_WSL_XATTR_MODE, nlen)) { 798 + /* File type in reparse point tag and in xattr mode must match. */ 799 + if (S_DT(fattr->cf_mode) != S_DT(le32_to_cpu(*(__le32 *)v))) 800 + return false; 1163 801 fattr->cf_mode = (umode_t)le32_to_cpu(*(__le32 *)v); 1164 - else if (!strncmp(name, SMB2_WSL_XATTR_DEV, nlen)) 802 + } else if (!strncmp(name, SMB2_WSL_XATTR_DEV, nlen)) { 1165 803 fattr->cf_rdev = reparse_mkdev(v); 804 + have_xattr_dev = true; 805 + } 1166 806 } while (next); 1167 807 out: 808 + 809 + /* Major and minor numbers for char and block devices are mandatory. */ 810 + if (!have_xattr_dev && (tag == IO_REPARSE_TAG_LX_CHR || tag == IO_REPARSE_TAG_LX_BLK)) 811 + return false; 812 + 1168 813 fattr->cf_dtype = S_DT(fattr->cf_mode); 814 + return true; 1169 815 } 1170 816 1171 817 static bool posix_reparse_to_fattr(struct cifs_sb_info *cifs_sb, 1172 818 struct cifs_fattr *fattr, 1173 819 struct cifs_open_info_data *data) 1174 820 { 1175 - struct reparse_posix_data *buf = data->reparse.posix; 1176 - 821 + struct reparse_nfs_data_buffer *buf = (struct reparse_nfs_data_buffer *)data->reparse.buf; 1177 822 1178 823 if (buf == NULL) 1179 824 return true; ··· 1249 874 case IO_REPARSE_TAG_AF_UNIX: 1250 875 case IO_REPARSE_TAG_LX_CHR: 1251 876 case IO_REPARSE_TAG_LX_BLK: 1252 - wsl_to_fattr(data, cifs_sb, tag, fattr); 877 + ok = wsl_to_fattr(data, cifs_sb, tag, fattr); 878 + if (!ok) 879 + return false; 1253 880 break; 1254 881 case IO_REPARSE_TAG_NFS: 1255 882 ok = posix_reparse_to_fattr(cifs_sb, fattr, data);
+2
fs/smb/client/reparse.h
··· 50 50 static inline u64 reparse_mode_nfs_type(mode_t mode) 51 51 { 52 52 switch (mode & S_IFMT) { 53 + case S_IFLNK: return NFS_SPECFILE_LNK; 53 54 case S_IFBLK: return NFS_SPECFILE_BLK; 54 55 case S_IFCHR: return NFS_SPECFILE_CHR; 55 56 case S_IFIFO: return NFS_SPECFILE_FIFO; ··· 62 61 static inline u32 reparse_mode_wsl_tag(mode_t mode) 63 62 { 64 63 switch (mode & S_IFMT) { 64 + case S_IFLNK: return IO_REPARSE_TAG_LX_SYMLINK; 65 65 case S_IFBLK: return IO_REPARSE_TAG_LX_BLK; 66 66 case S_IFCHR: return IO_REPARSE_TAG_LX_CHR; 67 67 case S_IFIFO: return IO_REPARSE_TAG_LX_FIFO;
+2 -1
fs/smb/client/sess.c
··· 1235 1235 switch (requested) { 1236 1236 case Kerberos: 1237 1237 case RawNTLMSSP: 1238 + case IAKerb: 1238 1239 return requested; 1239 1240 case Unspecified: 1240 1241 if (server->sec_ntlmssp && 1241 1242 (global_secflags & CIFSSEC_MAY_NTLMSSP)) 1242 1243 return RawNTLMSSP; 1243 - if ((server->sec_kerberos || server->sec_mskerberos) && 1244 + if ((server->sec_kerberos || server->sec_mskerberos || server->sec_iakerb) && 1244 1245 (global_secflags & CIFSSEC_MAY_KRB5)) 1245 1246 return Kerberos; 1246 1247 fallthrough;
+3 -27
fs/smb/client/smb1ops.c
··· 551 551 int rc; 552 552 FILE_ALL_INFO fi = {}; 553 553 554 - data->symlink = false; 554 + data->reparse_point = false; 555 555 data->adjust_tz = false; 556 556 557 557 /* could do find first instead but this returns more info */ ··· 569 569 } 570 570 571 571 if (!rc) { 572 - int tmprc; 573 - int oplock = 0; 574 - struct cifs_fid fid; 575 - struct cifs_open_parms oparms; 576 - 577 572 move_cifs_info_to_smb2(&data->fi, &fi); 578 - 579 - if (!(le32_to_cpu(fi.Attributes) & ATTR_REPARSE)) 580 - return 0; 581 - 582 - oparms = (struct cifs_open_parms) { 583 - .tcon = tcon, 584 - .cifs_sb = cifs_sb, 585 - .desired_access = FILE_READ_ATTRIBUTES, 586 - .create_options = cifs_create_options(cifs_sb, 0), 587 - .disposition = FILE_OPEN, 588 - .path = full_path, 589 - .fid = &fid, 590 - }; 591 - 592 - /* Need to check if this is a symbolic link or not */ 593 - tmprc = CIFS_open(xid, &oparms, &oplock, NULL); 594 - if (tmprc == -EOPNOTSUPP) 595 - data->symlink = true; 596 - else if (tmprc == 0) 597 - CIFSSMBClose(xid, tcon, fid.netfid); 573 + data->reparse_point = le32_to_cpu(fi.Attributes) & ATTR_REPARSE; 598 574 } 599 575 600 576 return rc; ··· 986 1010 987 1011 buf = (struct reparse_data_buffer *)((__u8 *)&io->hdr.Protocol + 988 1012 le32_to_cpu(io->DataOffset)); 989 - return parse_reparse_point(buf, plen, cifs_sb, full_path, true, data); 1013 + return parse_reparse_point(buf, plen, cifs_sb, full_path, data); 990 1014 } 991 1015 992 1016 static bool
+51 -1
fs/smb/client/smb2file.c
··· 63 63 return sym; 64 64 } 65 65 66 + int smb2_fix_symlink_target_type(char **target, bool directory, struct cifs_sb_info *cifs_sb) 67 + { 68 + char *buf; 69 + int len; 70 + 71 + /* 72 + * POSIX server does not distinguish between symlinks to file and 73 + * symlink directory. So nothing is needed to fix on the client side. 74 + */ 75 + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) 76 + return 0; 77 + 78 + if (!*target) 79 + return -EIO; 80 + 81 + len = strlen(*target); 82 + if (!len) 83 + return -EIO; 84 + 85 + /* 86 + * If this is directory symlink and it does not have trailing slash then 87 + * append it. Trailing slash simulates Windows/SMB behavior which do not 88 + * allow resolving directory symlink to file. 89 + */ 90 + if (directory && (*target)[len-1] != '/') { 91 + buf = krealloc(*target, len+2, GFP_KERNEL); 92 + if (!buf) 93 + return -ENOMEM; 94 + buf[len] = '/'; 95 + buf[len+1] = '\0'; 96 + *target = buf; 97 + len++; 98 + } 99 + 100 + /* 101 + * If this is a file (non-directory) symlink and it points to path name 102 + * with trailing slash then this is an invalid symlink because file name 103 + * cannot contain slash character. File name with slash is invalid on 104 + * both Windows and Linux systems. So return an error for such symlink. 105 + */ 106 + if (!directory && (*target)[len-1] == '/') 107 + return -EIO; 108 + 109 + return 0; 110 + } 111 + 66 112 int smb2_parse_symlink_response(struct cifs_sb_info *cifs_sb, const struct kvec *iov, 67 113 const char *full_path, char **path) 68 114 { ··· 135 89 return smb2_parse_native_symlink(path, 136 90 (char *)sym->PathBuffer + sub_offs, 137 91 sub_len, 138 - true, 139 92 le32_to_cpu(sym->Flags) & SYMLINK_FLAG_RELATIVE, 140 93 full_path, 141 94 cifs_sb); ··· 177 132 rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, 178 133 NULL, NULL, NULL); 179 134 oparms->create_options &= ~OPEN_REPARSE_POINT; 135 + } 136 + if (!rc) { 137 + bool directory = le32_to_cpu(data->fi.Attributes) & ATTR_DIRECTORY; 138 + rc = smb2_fix_symlink_target_type(&data->symlink_target, 139 + directory, oparms->cifs_sb); 180 140 } 181 141 } 182 142 }
+5
fs/smb/client/smb2inode.c
··· 1010 1010 else 1011 1011 rc = -EOPNOTSUPP; 1012 1012 } 1013 + 1014 + if (data->reparse.tag == IO_REPARSE_TAG_SYMLINK && !rc) { 1015 + bool directory = le32_to_cpu(data->fi.Attributes) & ATTR_DIRECTORY; 1016 + rc = smb2_fix_symlink_target_type(&data->symlink_target, directory, cifs_sb); 1017 + } 1013 1018 break; 1014 1019 case -EREMOTE: 1015 1020 break;
+2 -2
fs/smb/client/smb2maperror.c
··· 380 380 {STATUS_NO_LOGON_SERVERS, -EIO, "STATUS_NO_LOGON_SERVERS"}, 381 381 {STATUS_NO_SUCH_LOGON_SESSION, -EIO, "STATUS_NO_SUCH_LOGON_SESSION"}, 382 382 {STATUS_NO_SUCH_PRIVILEGE, -EIO, "STATUS_NO_SUCH_PRIVILEGE"}, 383 - {STATUS_PRIVILEGE_NOT_HELD, -EIO, "STATUS_PRIVILEGE_NOT_HELD"}, 383 + {STATUS_PRIVILEGE_NOT_HELD, -EPERM, "STATUS_PRIVILEGE_NOT_HELD"}, 384 384 {STATUS_INVALID_ACCOUNT_NAME, -EIO, "STATUS_INVALID_ACCOUNT_NAME"}, 385 385 {STATUS_USER_EXISTS, -EIO, "STATUS_USER_EXISTS"}, 386 386 {STATUS_NO_SUCH_USER, -EIO, "STATUS_NO_SUCH_USER"}, ··· 871 871 {STATUS_VALIDATE_CONTINUE, -EIO, "STATUS_VALIDATE_CONTINUE"}, 872 872 {STATUS_NO_MATCH, -EIO, "STATUS_NO_MATCH"}, 873 873 {STATUS_NO_MORE_MATCHES, -EIO, "STATUS_NO_MORE_MATCHES"}, 874 - {STATUS_NOT_A_REPARSE_POINT, -EIO, "STATUS_NOT_A_REPARSE_POINT"}, 874 + {STATUS_NOT_A_REPARSE_POINT, -ENODATA, "STATUS_NOT_A_REPARSE_POINT"}, 875 875 {STATUS_IO_REPARSE_TAG_INVALID, -EIO, "STATUS_IO_REPARSE_TAG_INVALID"}, 876 876 {STATUS_IO_REPARSE_TAG_MISMATCH, -EIO, 877 877 "STATUS_IO_REPARSE_TAG_MISMATCH"},
+22 -1
fs/smb/client/smb2ops.c
··· 5077 5077 { 5078 5078 struct TCP_Server_Info *server = tcon->ses->server; 5079 5079 struct cifs_open_parms oparms; 5080 + struct cifs_open_info_data idata; 5080 5081 struct cifs_io_parms io_parms = {}; 5081 5082 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 5082 5083 struct cifs_fid fid; ··· 5147 5146 CREATE_OPTION_SPECIAL, ACL_NO_MODE); 5148 5147 oparms.fid = &fid; 5149 5148 5150 - rc = server->ops->open(xid, &oparms, &oplock, NULL); 5149 + rc = server->ops->open(xid, &oparms, &oplock, &idata); 5151 5150 if (rc) 5152 5151 goto out; 5152 + 5153 + /* 5154 + * Check if the server honored ATTR_SYSTEM flag by CREATE_OPTION_SPECIAL 5155 + * option. If not then server does not support ATTR_SYSTEM and newly 5156 + * created file is not SFU compatible, which means that the call failed. 5157 + */ 5158 + if (!(le32_to_cpu(idata.fi.Attributes) & ATTR_SYSTEM)) { 5159 + rc = -EOPNOTSUPP; 5160 + goto out_close; 5161 + } 5153 5162 5154 5163 if (type_len + data_len > 0) { 5155 5164 io_parms.pid = current->tgid; ··· 5175 5164 iov, ARRAY_SIZE(iov)-1); 5176 5165 } 5177 5166 5167 + out_close: 5178 5168 server->ops->close(xid, tcon, &fid); 5169 + 5170 + /* 5171 + * If CREATE was successful but either setting ATTR_SYSTEM failed or 5172 + * writing type/data information failed then remove the intermediate 5173 + * object created by CREATE. Otherwise intermediate empty object stay 5174 + * on the server. 5175 + */ 5176 + if (rc) 5177 + server->ops->unlink(xid, tcon, full_path, cifs_sb, NULL); 5179 5178 5180 5179 out: 5181 5180 kfree(symname_utf16);
+1 -1
fs/smb/client/smb2pdu.c
··· 1429 1429 if (server->sec_ntlmssp && 1430 1430 (global_secflags & CIFSSEC_MAY_NTLMSSP)) 1431 1431 return RawNTLMSSP; 1432 - if ((server->sec_kerberos || server->sec_mskerberos) && 1432 + if ((server->sec_kerberos || server->sec_mskerberos || server->sec_iakerb) && 1433 1433 (global_secflags & CIFSSEC_MAY_KRB5)) 1434 1434 return Kerberos; 1435 1435 fallthrough;
+2 -1
fs/smb/client/smb2proto.h
··· 111 111 struct cifs_sb_info *cifs_sb, 112 112 const unsigned char *path, char *pbuf, 113 113 unsigned int *pbytes_read); 114 + int smb2_fix_symlink_target_type(char **target, bool directory, struct cifs_sb_info *cifs_sb); 114 115 int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len, 115 - bool unicode, bool relative, 116 + bool relative, 116 117 const char *full_path, 117 118 struct cifs_sb_info *cifs_sb); 118 119 int smb2_parse_symlink_response(struct cifs_sb_info *cifs_sb,
+13 -1
fs/smb/common/smb2pdu.h
··· 1550 1550 __u8 PathBuffer[]; /* Variable Length */ 1551 1551 } __packed; 1552 1552 1553 - /* See MS-FSCC 2.1.2.6 and cifspdu.h for struct reparse_posix_data */ 1553 + /* For IO_REPARSE_TAG_NFS - see MS-FSCC 2.1.2.6 */ 1554 + #define NFS_SPECFILE_LNK 0x00000000014B4E4C 1555 + #define NFS_SPECFILE_CHR 0x0000000000524843 1556 + #define NFS_SPECFILE_BLK 0x00000000004B4C42 1557 + #define NFS_SPECFILE_FIFO 0x000000004F464946 1558 + #define NFS_SPECFILE_SOCK 0x000000004B434F53 1559 + struct reparse_nfs_data_buffer { 1560 + __le32 ReparseTag; 1561 + __le16 ReparseDataLength; 1562 + __u16 Reserved; 1563 + __le64 InodeType; /* NFS_SPECFILE_* */ 1564 + __u8 DataBuffer[]; 1565 + } __packed; 1554 1566 1555 1567 /* For IO_REPARSE_TAG_LX_SYMLINK */ 1556 1568 struct reparse_wsl_symlink_data_buffer {