Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag '6.13-rc-part1-SMB3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull smb client updates from Steve French:

- Fix two SMB3.1.1 POSIX Extensions problems

- Fixes for special file handling (symlinks and FIFOs)

- Improve compounding

- Four cleanup patches

- Fix use after free in signing

- Add support for handling namespaces for reconnect related upcalls
(e.g. for DNS names resolution and auth)

- Fix various directory lease problems (directory entry caching),
including some important potential use after frees

* tag '6.13-rc-part1-SMB3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6:
smb: prevent use-after-free due to open_cached_dir error paths
smb: Don't leak cfid when reconnect races with open_cached_dir
smb: client: handle max length for SMB symlinks
smb: client: get rid of bounds check in SMB2_ioctl_init()
smb: client: improve compound padding in encryption
smb3: request handle caching when caching directories
cifs: Recognize SFU char/block devices created by Windows NFS server on Windows Server <<2012
CIFS: New mount option for cifs.upcall namespace resolution
smb/client: Prevent error pointer dereference
fs/smb/client: implement chmod() for SMB3 POSIX Extensions
smb: cached directories can be more than root file handle
smb: client: fix use-after-free of signing key
smb: client: Use str_yes_no() helper function
smb: client: memcpy() with surrounding object base address
cifs: Remove pre-historic unused CIFSSMBCopy

+293 -246
+44 -55
fs/smb/client/cached_dir.c
··· 59 59 list_add(&cfid->entry, &cfids->entries); 60 60 cfid->on_list = true; 61 61 kref_get(&cfid->refcount); 62 + /* 63 + * Set @cfid->has_lease to true during construction so that the lease 64 + * reference can be put in cached_dir_lease_break() due to a potential 65 + * lease break right after the request is sent or while @cfid is still 66 + * being cached, or if a reconnection is triggered during construction. 67 + * Concurrent processes won't be to use it yet due to @cfid->time being 68 + * zero. 69 + */ 70 + cfid->has_lease = true; 71 + 62 72 spin_unlock(&cfids->cfid_list_lock); 63 73 return cfid; 64 74 } ··· 186 176 return -ENOENT; 187 177 } 188 178 /* 189 - * Return cached fid if it has a lease. Otherwise, it is either a new 190 - * entry or laundromat worker removed it from @cfids->entries. Caller 191 - * will put last reference if the latter. 179 + * Return cached fid if it is valid (has a lease and has a time). 180 + * Otherwise, it is either a new entry or laundromat worker removed it 181 + * from @cfids->entries. Caller will put last reference if the latter. 192 182 */ 193 183 spin_lock(&cfids->cfid_list_lock); 194 - if (cfid->has_lease) { 184 + if (cfid->has_lease && cfid->time) { 195 185 spin_unlock(&cfids->cfid_list_lock); 196 186 *ret_cfid = cfid; 197 187 kfree(utf16_path); ··· 277 267 278 268 smb2_set_related(&rqst[1]); 279 269 280 - /* 281 - * Set @cfid->has_lease to true before sending out compounded request so 282 - * its lease reference can be put in cached_dir_lease_break() due to a 283 - * potential lease break right after the request is sent or while @cfid 284 - * is still being cached. Concurrent processes won't be to use it yet 285 - * due to @cfid->time being zero. 286 - */ 287 - cfid->has_lease = true; 288 - 289 270 if (retries) { 290 271 smb2_set_replay(server, &rqst[0]); 291 272 smb2_set_replay(server, &rqst[1]); ··· 348 347 SMB2_query_info_free(&rqst[1]); 349 348 free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); 350 349 free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); 350 + out: 351 351 if (rc) { 352 352 spin_lock(&cfids->cfid_list_lock); 353 353 if (cfid->on_list) { ··· 360 358 /* 361 359 * We are guaranteed to have two references at this 362 360 * point. One for the caller and one for a potential 363 - * lease. Release the Lease-ref so that the directory 364 - * will be closed when the caller closes the cached 365 - * handle. 361 + * lease. Release one here, and the second below. 366 362 */ 367 363 cfid->has_lease = false; 368 - spin_unlock(&cfids->cfid_list_lock); 369 364 kref_put(&cfid->refcount, smb2_close_cached_fid); 370 - goto out; 371 365 } 372 366 spin_unlock(&cfids->cfid_list_lock); 373 - } 374 - out: 375 - if (rc) { 376 - if (cfid->is_open) 377 - SMB2_close(0, cfid->tcon, cfid->fid.persistent_fid, 378 - cfid->fid.volatile_fid); 379 - free_cached_dir(cfid); 367 + 368 + kref_put(&cfid->refcount, smb2_close_cached_fid); 380 369 } else { 381 370 *ret_cfid = cfid; 382 371 atomic_inc(&tcon->num_remote_opens); ··· 394 401 spin_lock(&cfids->cfid_list_lock); 395 402 list_for_each_entry(cfid, &cfids->entries, entry) { 396 403 if (dentry && cfid->dentry == dentry) { 397 - cifs_dbg(FYI, "found a cached root file handle by dentry\n"); 404 + cifs_dbg(FYI, "found a cached file handle by dentry\n"); 398 405 kref_get(&cfid->refcount); 399 406 *ret_cfid = cfid; 400 407 spin_unlock(&cfids->cfid_list_lock); ··· 505 512 cfids->num_entries--; 506 513 cfid->is_open = false; 507 514 cfid->on_list = false; 508 - /* To prevent race with smb2_cached_lease_break() */ 509 - kref_get(&cfid->refcount); 515 + if (cfid->has_lease) { 516 + /* 517 + * The lease was never cancelled from the server, 518 + * so steal that reference. 519 + */ 520 + cfid->has_lease = false; 521 + } else 522 + kref_get(&cfid->refcount); 510 523 } 511 524 spin_unlock(&cfids->cfid_list_lock); 512 525 513 526 list_for_each_entry_safe(cfid, q, &entry, entry) { 514 527 list_del(&cfid->entry); 515 528 cancel_work_sync(&cfid->lease_break); 516 - if (cfid->has_lease) { 517 - /* 518 - * We lease was never cancelled from the server so we 519 - * need to drop the reference. 520 - */ 521 - spin_lock(&cfids->cfid_list_lock); 522 - cfid->has_lease = false; 523 - spin_unlock(&cfids->cfid_list_lock); 524 - kref_put(&cfid->refcount, smb2_close_cached_fid); 525 - } 526 - /* Drop the extra reference opened above*/ 529 + /* 530 + * Drop the ref-count from above, either the lease-ref (if there 531 + * was one) or the extra one acquired. 532 + */ 527 533 kref_put(&cfid->refcount, smb2_close_cached_fid); 528 534 } 529 535 } ··· 533 541 struct cached_fid *cfid = container_of(work, 534 542 struct cached_fid, lease_break); 535 543 536 - spin_lock(&cfid->cfids->cfid_list_lock); 537 - cfid->has_lease = false; 538 - spin_unlock(&cfid->cfids->cfid_list_lock); 539 544 kref_put(&cfid->refcount, smb2_close_cached_fid); 540 545 } 541 546 ··· 550 561 !memcmp(lease_key, 551 562 cfid->fid.lease_key, 552 563 SMB2_LEASE_KEY_SIZE)) { 564 + cfid->has_lease = false; 553 565 cfid->time = 0; 554 566 /* 555 567 * We found a lease remove it from the list ··· 628 638 cfid->on_list = false; 629 639 list_move(&cfid->entry, &entry); 630 640 cfids->num_entries--; 631 - /* To prevent race with smb2_cached_lease_break() */ 632 - kref_get(&cfid->refcount); 641 + if (cfid->has_lease) { 642 + /* 643 + * Our lease has not yet been cancelled from the 644 + * server. Steal that reference. 645 + */ 646 + cfid->has_lease = false; 647 + } else 648 + kref_get(&cfid->refcount); 633 649 } 634 650 } 635 651 spin_unlock(&cfids->cfid_list_lock); ··· 647 651 * with it. 648 652 */ 649 653 cancel_work_sync(&cfid->lease_break); 650 - if (cfid->has_lease) { 651 - /* 652 - * Our lease has not yet been cancelled from the server 653 - * so we need to drop the reference. 654 - */ 655 - spin_lock(&cfids->cfid_list_lock); 656 - cfid->has_lease = false; 657 - spin_unlock(&cfids->cfid_list_lock); 658 - kref_put(&cfid->refcount, smb2_close_cached_fid); 659 - } 660 - /* Drop the extra reference opened above */ 654 + /* 655 + * Drop the ref-count from above, either the lease-ref (if there 656 + * was one) or the extra one acquired. 657 + */ 661 658 kref_put(&cfid->refcount, smb2_close_cached_fid); 662 659 } 663 660 queue_delayed_work(cifsiod_wq, &cfids->laundromat_work,
+16
fs/smb/client/cifs_spnego.c
··· 82 82 /* strlen of ";pid=0x" */ 83 83 #define PID_KEY_LEN 7 84 84 85 + /* strlen of ";upcall_target=" */ 86 + #define UPCALL_TARGET_KEY_LEN 15 87 + 85 88 /* get a key struct with a SPNEGO security blob, suitable for session setup */ 86 89 struct key * 87 90 cifs_get_spnego_key(struct cifs_ses *sesInfo, ··· 110 107 111 108 if (sesInfo->user_name) 112 109 desc_len += USER_KEY_LEN + strlen(sesInfo->user_name); 110 + 111 + if (sesInfo->upcall_target == UPTARGET_MOUNT) 112 + desc_len += UPCALL_TARGET_KEY_LEN + 5; // strlen("mount") 113 + else 114 + desc_len += UPCALL_TARGET_KEY_LEN + 3; // strlen("app") 113 115 114 116 spnego_key = ERR_PTR(-ENOMEM); 115 117 description = kzalloc(desc_len, GFP_KERNEL); ··· 163 155 164 156 dp = description + strlen(description); 165 157 sprintf(dp, ";pid=0x%x", current->pid); 158 + 159 + if (sesInfo->upcall_target == UPTARGET_MOUNT) { 160 + dp = description + strlen(description); 161 + sprintf(dp, ";upcall_target=mount"); 162 + } else { 163 + dp = description + strlen(description); 164 + sprintf(dp, ";upcall_target=app"); 165 + } 166 166 167 167 cifs_dbg(FYI, "key description = %s\n", description); 168 168 saved_cred = override_creds(spnego_cred);
+33 -21
fs/smb/client/cifsacl.c
··· 885 885 * Fill in the special SID based on the mode. See 886 886 * https://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx 887 887 */ 888 - unsigned int setup_special_mode_ACE(struct smb_ace *pntace, __u64 nmode) 888 + unsigned int setup_special_mode_ACE(struct smb_ace *pntace, 889 + bool posix, 890 + __u64 nmode) 889 891 { 890 892 int i; 891 893 unsigned int ace_size = 28; 892 894 893 - pntace->type = ACCESS_DENIED_ACE_TYPE; 895 + if (posix) 896 + pntace->type = ACCESS_ALLOWED_ACE_TYPE; 897 + else 898 + pntace->type = ACCESS_DENIED_ACE_TYPE; 894 899 pntace->flags = 0x0; 895 900 pntace->access_req = 0; 896 901 pntace->sid.num_subauth = 3; ··· 938 933 struct smb_sid *pownersid, 939 934 struct smb_sid *pgrpsid, 940 935 __u64 *pnmode, u32 *pnum_aces, u16 *pnsize, 941 - bool modefromsid) 936 + bool modefromsid, 937 + bool posix) 942 938 { 943 939 __u64 nmode; 944 940 u32 num_aces = 0; ··· 956 950 num_aces = *pnum_aces; 957 951 nsize = *pnsize; 958 952 959 - if (modefromsid) { 953 + if (modefromsid || posix) { 960 954 pnntace = (struct smb_ace *) (nacl_base + nsize); 961 - nsize += setup_special_mode_ACE(pnntace, nmode); 955 + nsize += setup_special_mode_ACE(pnntace, posix, nmode); 962 956 num_aces++; 963 - pnntace = (struct smb_ace *) (nacl_base + nsize); 964 - nsize += setup_authusers_ACE(pnntace); 965 - num_aces++; 957 + if (modefromsid) { 958 + pnntace = (struct smb_ace *) (nacl_base + nsize); 959 + nsize += setup_authusers_ACE(pnntace); 960 + num_aces++; 961 + } 966 962 goto set_size; 967 963 } 968 964 ··· 1084 1076 1085 1077 static int set_chmod_dacl(struct smb_acl *pdacl, struct smb_acl *pndacl, 1086 1078 struct smb_sid *pownersid, struct smb_sid *pgrpsid, 1087 - __u64 *pnmode, bool mode_from_sid) 1079 + __u64 *pnmode, bool mode_from_sid, bool posix) 1088 1080 { 1089 1081 int i; 1090 1082 u16 size = 0; ··· 1102 1094 nsize = sizeof(struct smb_acl); 1103 1095 1104 1096 /* If pdacl is NULL, we don't have a src. Simply populate new ACL. */ 1105 - if (!pdacl) { 1097 + if (!pdacl || posix) { 1106 1098 populate_new_aces(nacl_base, 1107 1099 pownersid, pgrpsid, 1108 1100 pnmode, &num_aces, &nsize, 1109 - mode_from_sid); 1101 + mode_from_sid, posix); 1110 1102 goto finalize_dacl; 1111 1103 } 1112 1104 ··· 1123 1115 populate_new_aces(nacl_base, 1124 1116 pownersid, pgrpsid, 1125 1117 pnmode, &num_aces, &nsize, 1126 - mode_from_sid); 1118 + mode_from_sid, posix); 1127 1119 1128 1120 new_aces_set = true; 1129 1121 } ··· 1152 1144 populate_new_aces(nacl_base, 1153 1145 pownersid, pgrpsid, 1154 1146 pnmode, &num_aces, &nsize, 1155 - mode_from_sid); 1147 + mode_from_sid, posix); 1156 1148 1157 1149 new_aces_set = true; 1158 1150 } ··· 1259 1251 /* Convert permission bits from mode to equivalent CIFS ACL */ 1260 1252 static int build_sec_desc(struct smb_ntsd *pntsd, struct smb_ntsd *pnntsd, 1261 1253 __u32 secdesclen, __u32 *pnsecdesclen, __u64 *pnmode, kuid_t uid, kgid_t gid, 1262 - bool mode_from_sid, bool id_from_sid, int *aclflag) 1254 + bool mode_from_sid, bool id_from_sid, bool posix, int *aclflag) 1263 1255 { 1264 1256 int rc = 0; 1265 1257 __u32 dacloffset; ··· 1296 1288 ndacl_ptr->num_aces = cpu_to_le32(0); 1297 1289 1298 1290 rc = set_chmod_dacl(dacl_ptr, ndacl_ptr, owner_sid_ptr, group_sid_ptr, 1299 - pnmode, mode_from_sid); 1291 + pnmode, mode_from_sid, posix); 1300 1292 1301 1293 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size); 1302 1294 /* copy the non-dacl portion of secdesc */ ··· 1592 1584 struct smb_ntsd *pntsd = NULL; /* acl obtained from server */ 1593 1585 struct smb_ntsd *pnntsd = NULL; /* modified acl to be sent to server */ 1594 1586 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 1595 - struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); 1587 + struct tcon_link *tlink; 1596 1588 struct smb_version_operations *ops; 1597 1589 bool mode_from_sid, id_from_sid; 1598 1590 const u32 info = 0; 1591 + bool posix; 1599 1592 1593 + tlink = cifs_sb_tlink(cifs_sb); 1600 1594 if (IS_ERR(tlink)) 1601 1595 return PTR_ERR(tlink); 1596 + posix = tlink_tcon(tlink)->posix_extensions; 1602 1597 1603 1598 ops = tlink_tcon(tlink)->ses->server->ops; 1604 1599 ··· 1633 1622 id_from_sid = false; 1634 1623 1635 1624 /* Potentially, five new ACEs can be added to the ACL for U,G,O mapping */ 1636 - nsecdesclen = secdesclen; 1637 1625 if (pnmode && *pnmode != NO_CHANGE_64) { /* chmod */ 1638 - if (mode_from_sid) 1639 - nsecdesclen += 2 * sizeof(struct smb_ace); 1626 + if (posix) 1627 + nsecdesclen = 1 * sizeof(struct smb_ace); 1628 + else if (mode_from_sid) 1629 + nsecdesclen = secdesclen + (2 * sizeof(struct smb_ace)); 1640 1630 else /* cifsacl */ 1641 - nsecdesclen += 5 * sizeof(struct smb_ace); 1631 + nsecdesclen = secdesclen + (5 * sizeof(struct smb_ace)); 1642 1632 } else { /* chown */ 1643 1633 /* When ownership changes, changes new owner sid length could be different */ 1644 1634 nsecdesclen = sizeof(struct smb_ntsd) + (sizeof(struct smb_sid) * 2); ··· 1669 1657 } 1670 1658 1671 1659 rc = build_sec_desc(pntsd, pnntsd, secdesclen, &nsecdesclen, pnmode, uid, gid, 1672 - mode_from_sid, id_from_sid, &aclflag); 1660 + mode_from_sid, id_from_sid, posix, &aclflag); 1673 1661 1674 1662 cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc); 1675 1663
+25
fs/smb/client/cifsfs.c
··· 546 546 return 0; 547 547 } 548 548 549 + static void 550 + cifs_show_upcall_target(struct seq_file *s, struct cifs_sb_info *cifs_sb) 551 + { 552 + if (cifs_sb->ctx->upcall_target == UPTARGET_UNSPECIFIED) { 553 + seq_puts(s, ",upcall_target=app"); 554 + return; 555 + } 556 + 557 + seq_puts(s, ",upcall_target="); 558 + 559 + switch (cifs_sb->ctx->upcall_target) { 560 + case UPTARGET_APP: 561 + seq_puts(s, "app"); 562 + break; 563 + case UPTARGET_MOUNT: 564 + seq_puts(s, "mount"); 565 + break; 566 + default: 567 + /* shouldn't ever happen */ 568 + seq_puts(s, "unknown"); 569 + break; 570 + } 571 + } 572 + 549 573 /* 550 574 * cifs_show_options() is for displaying mount options in /proc/mounts. 551 575 * Not all settable options are displayed but most of the important ··· 586 562 seq_show_option(s, "vers", tcon->ses->server->vals->version_string); 587 563 cifs_show_security(s, tcon->ses); 588 564 cifs_show_cache_flavor(s, cifs_sb); 565 + cifs_show_upcall_target(s, cifs_sb); 589 566 590 567 if (tcon->no_lease) 591 568 seq_puts(s, ",nolease");
+9 -2
fs/smb/client/cifsglob.h
··· 153 153 Kerberos, /* Kerberos via SPNEGO */ 154 154 }; 155 155 156 + enum upcall_target_enum { 157 + UPTARGET_UNSPECIFIED, /* not specified, defaults to app */ 158 + UPTARGET_MOUNT, /* upcall to the mount namespace */ 159 + UPTARGET_APP, /* upcall to the application namespace which did the mount */ 160 + }; 161 + 156 162 enum cifs_reparse_type { 157 163 CIFS_REPARSE_TYPE_NFS, 158 164 CIFS_REPARSE_TYPE_WSL, ··· 1090 1084 struct session_key auth_key; 1091 1085 struct ntlmssp_auth *ntlmssp; /* ciphertext, flags, server challenge */ 1092 1086 enum securityEnum sectype; /* what security flavor was specified? */ 1087 + enum upcall_target_enum upcall_target; /* what upcall target was specified? */ 1093 1088 bool sign; /* is signing required? */ 1094 1089 bool domainAuto:1; 1095 1090 bool expired_pwd; /* track if access denied or expired pwd so can know if need to update */ ··· 2230 2223 struct kvec *iov = &rqst[i].rq_iov[j]; 2231 2224 2232 2225 addr = (unsigned long)iov->iov_base + skip; 2233 - if (unlikely(is_vmalloc_addr((void *)addr))) { 2226 + if (is_vmalloc_or_module_addr((void *)addr)) { 2234 2227 len = iov->iov_len - skip; 2235 2228 nents += DIV_ROUND_UP(offset_in_page(addr) + len, 2236 2229 PAGE_SIZE); ··· 2257 2250 unsigned int off = offset_in_page(addr); 2258 2251 2259 2252 addr &= PAGE_MASK; 2260 - if (unlikely(is_vmalloc_addr((void *)addr))) { 2253 + if (is_vmalloc_or_module_addr((void *)addr)) { 2261 2254 do { 2262 2255 unsigned int len = min_t(unsigned int, buflen, PAGE_SIZE - off); 2263 2256
+3 -8
fs/smb/client/cifsproto.h
··· 244 244 extern int set_cifs_acl(struct smb_ntsd *pntsd, __u32 len, struct inode *ino, 245 245 const char *path, int flag); 246 246 extern unsigned int setup_authusers_ACE(struct smb_ace *pace); 247 - extern unsigned int setup_special_mode_ACE(struct smb_ace *pace, __u64 nmode); 247 + extern unsigned int setup_special_mode_ACE(struct smb_ace *pace, 248 + bool posix, 249 + __u64 nmode); 248 250 extern unsigned int setup_special_user_owner_ACE(struct smb_ace *pace); 249 251 250 252 extern void dequeue_mid(struct mid_q_entry *mid, bool malformed); ··· 551 549 struct TCP_Server_Info *server); 552 550 553 551 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 554 - extern int CIFSSMBCopy(unsigned int xid, 555 - struct cifs_tcon *source_tcon, 556 - const char *fromName, 557 - const __u16 target_tid, 558 - const char *toName, const int flags, 559 - const struct nls_table *nls_codepage, 560 - int remap_special_chars); 561 552 extern ssize_t CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon, 562 553 const unsigned char *searchName, 563 554 const unsigned char *ea_name, char *EAData,
+1 -64
fs/smb/client/cifssmb.c
··· 2340 2340 } 2341 2341 2342 2342 int 2343 - CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon, 2344 - const char *fromName, const __u16 target_tid, const char *toName, 2345 - const int flags, const struct nls_table *nls_codepage, int remap) 2346 - { 2347 - int rc = 0; 2348 - COPY_REQ *pSMB = NULL; 2349 - COPY_RSP *pSMBr = NULL; 2350 - int bytes_returned; 2351 - int name_len, name_len2; 2352 - __u16 count; 2353 - 2354 - cifs_dbg(FYI, "In CIFSSMBCopy\n"); 2355 - copyRetry: 2356 - rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB, 2357 - (void **) &pSMBr); 2358 - if (rc) 2359 - return rc; 2360 - 2361 - pSMB->BufferFormat = 0x04; 2362 - pSMB->Tid2 = target_tid; 2363 - 2364 - pSMB->Flags = cpu_to_le16(flags & COPY_TREE); 2365 - 2366 - if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 2367 - name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName, 2368 - fromName, PATH_MAX, nls_codepage, 2369 - remap); 2370 - name_len++; /* trailing null */ 2371 - name_len *= 2; 2372 - pSMB->OldFileName[name_len] = 0x04; /* pad */ 2373 - /* protocol requires ASCII signature byte on Unicode string */ 2374 - pSMB->OldFileName[name_len + 1] = 0x00; 2375 - name_len2 = 2376 - cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2], 2377 - toName, PATH_MAX, nls_codepage, remap); 2378 - name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; 2379 - name_len2 *= 2; /* convert to bytes */ 2380 - } else { 2381 - name_len = copy_path_name(pSMB->OldFileName, fromName); 2382 - pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */ 2383 - name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, toName); 2384 - name_len2++; /* signature byte */ 2385 - } 2386 - 2387 - count = 1 /* 1st signature byte */ + name_len + name_len2; 2388 - inc_rfc1001_len(pSMB, count); 2389 - pSMB->ByteCount = cpu_to_le16(count); 2390 - 2391 - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 2392 - (struct smb_hdr *) pSMBr, &bytes_returned, 0); 2393 - if (rc) { 2394 - cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n", 2395 - rc, le16_to_cpu(pSMBr->CopyCount)); 2396 - } 2397 - cifs_buf_release(pSMB); 2398 - 2399 - if (rc == -EAGAIN) 2400 - goto copyRetry; 2401 - 2402 - return rc; 2403 - } 2404 - 2405 - int 2406 2343 CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon, 2407 2344 const char *fromName, const char *toName, 2408 2345 const struct nls_table *nls_codepage, int remap) ··· 5343 5406 param_offset = offsetof(struct smb_com_transaction2_spi_req, 5344 5407 InformationLevel) - 4; 5345 5408 offset = param_offset + params; 5346 - data_offset = (char *) (&pSMB->hdr.Protocol) + offset; 5409 + data_offset = (char *)pSMB + offsetof(typeof(*pSMB), hdr.Protocol) + offset; 5347 5410 pSMB->ParameterOffset = cpu_to_le16(param_offset); 5348 5411 pSMB->DataOffset = cpu_to_le16(offset); 5349 5412 pSMB->SetupCount = 1;
+20
fs/smb/client/connect.c
··· 2339 2339 2340 2340 ses->sectype = ctx->sectype; 2341 2341 ses->sign = ctx->sign; 2342 + 2343 + /* 2344 + *Explicitly marking upcall_target mount option for easier handling 2345 + * by cifs_spnego.c and eventually cifs.upcall.c 2346 + */ 2347 + 2348 + switch (ctx->upcall_target) { 2349 + case UPTARGET_UNSPECIFIED: /* default to app */ 2350 + case UPTARGET_APP: 2351 + ses->upcall_target = UPTARGET_APP; 2352 + break; 2353 + case UPTARGET_MOUNT: 2354 + ses->upcall_target = UPTARGET_MOUNT; 2355 + break; 2356 + default: 2357 + // should never happen 2358 + ses->upcall_target = UPTARGET_APP; 2359 + break; 2360 + } 2361 + 2342 2362 ses->local_nls = load_nls(ctx->local_nls->charset); 2343 2363 2344 2364 /* add server as first channel */
+4 -4
fs/smb/client/dfs_cache.c
··· 173 173 "cache entry: path=%s,type=%s,ttl=%d,etime=%ld,hdr_flags=0x%x,ref_flags=0x%x,interlink=%s,path_consumed=%d,expired=%s\n", 174 174 ce->path, ce->srvtype == DFS_TYPE_ROOT ? "root" : "link", 175 175 ce->ttl, ce->etime.tv_nsec, ce->hdr_flags, ce->ref_flags, 176 - DFS_INTERLINK(ce->hdr_flags) ? "yes" : "no", 177 - ce->path_consumed, cache_entry_expired(ce) ? "yes" : "no"); 176 + str_yes_no(DFS_INTERLINK(ce->hdr_flags)), 177 + ce->path_consumed, str_yes_no(cache_entry_expired(ce))); 178 178 179 179 list_for_each_entry(t, &ce->tlist, list) { 180 180 seq_printf(m, " %s%s\n", ··· 242 242 ce->srvtype == DFS_TYPE_ROOT ? "root" : "link", ce->ttl, 243 243 ce->etime.tv_nsec, 244 244 ce->hdr_flags, ce->ref_flags, 245 - DFS_INTERLINK(ce->hdr_flags) ? "yes" : "no", 245 + str_yes_no(DFS_INTERLINK(ce->hdr_flags)), 246 246 ce->path_consumed, 247 - cache_entry_expired(ce) ? "yes" : "no"); 247 + str_yes_no(cache_entry_expired(ce))); 248 248 dump_tgts(ce); 249 249 } 250 250
+39
fs/smb/client/fs_context.c
··· 67 67 { Opt_sec_err, NULL } 68 68 }; 69 69 70 + static const match_table_t cifs_upcall_target = { 71 + { Opt_upcall_target_mount, "mount" }, 72 + { Opt_upcall_target_application, "app" }, 73 + { Opt_upcall_target_err, NULL } 74 + }; 75 + 70 76 const struct fs_parameter_spec smb3_fs_parameters[] = { 71 77 /* Mount options that take no arguments */ 72 78 fsparam_flag_no("user_xattr", Opt_user_xattr), ··· 184 178 fsparam_string("sec", Opt_sec), 185 179 fsparam_string("cache", Opt_cache), 186 180 fsparam_string("reparse", Opt_reparse), 181 + fsparam_string("upcall_target", Opt_upcalltarget), 187 182 188 183 /* Arguments that should be ignored */ 189 184 fsparam_flag("guest", Opt_ignore), ··· 249 242 break; 250 243 default: 251 244 cifs_errorf(fc, "bad security option: %s\n", value); 245 + return 1; 246 + } 247 + 248 + return 0; 249 + } 250 + 251 + static int 252 + cifs_parse_upcall_target(struct fs_context *fc, char *value, struct smb3_fs_context *ctx) 253 + { 254 + substring_t args[MAX_OPT_ARGS]; 255 + 256 + ctx->upcall_target = UPTARGET_UNSPECIFIED; 257 + 258 + switch (match_token(value, cifs_upcall_target, args)) { 259 + case Opt_upcall_target_mount: 260 + ctx->upcall_target = UPTARGET_MOUNT; 261 + break; 262 + case Opt_upcall_target_application: 263 + ctx->upcall_target = UPTARGET_APP; 264 + break; 265 + 266 + default: 267 + cifs_errorf(fc, "bad upcall target: %s\n", value); 252 268 return 1; 253 269 } 254 270 ··· 1480 1450 if (cifs_parse_security_flavors(fc, param->string, ctx) != 0) 1481 1451 goto cifs_parse_mount_err; 1482 1452 break; 1453 + case Opt_upcalltarget: 1454 + if (cifs_parse_upcall_target(fc, param->string, ctx) != 0) 1455 + goto cifs_parse_mount_err; 1456 + break; 1483 1457 case Opt_cache: 1484 1458 if (cifs_parse_cache_flavor(fc, param->string, ctx) != 0) 1485 1459 goto cifs_parse_mount_err; ··· 1660 1626 break; 1661 1627 } 1662 1628 /* case Opt_ignore: - is ignored as expected ... */ 1629 + 1630 + if (ctx->multiuser && ctx->upcall_target == UPTARGET_MOUNT) { 1631 + cifs_errorf(fc, "multiuser mount option not supported with upcalltarget set as 'mount'\n"); 1632 + goto cifs_parse_mount_err; 1633 + } 1663 1634 1664 1635 return 0; 1665 1636
+10
fs/smb/client/fs_context.h
··· 61 61 Opt_sec_err 62 62 }; 63 63 64 + enum cifs_upcall_target_param { 65 + Opt_upcall_target_mount, 66 + Opt_upcall_target_application, 67 + Opt_upcall_target_err 68 + }; 69 + 64 70 enum cifs_param { 65 71 /* Mount options that take no arguments */ 66 72 Opt_user_xattr, ··· 120 114 Opt_multichannel, 121 115 Opt_compress, 122 116 Opt_witness, 117 + Opt_is_upcall_target_mount, 118 + Opt_is_upcall_target_application, 123 119 124 120 /* Mount options which take numeric value */ 125 121 Opt_backupuid, ··· 165 157 Opt_sec, 166 158 Opt_cache, 167 159 Opt_reparse, 160 + Opt_upcalltarget, 168 161 169 162 /* Mount options to be ignored */ 170 163 Opt_ignore, ··· 207 198 umode_t file_mode; 208 199 umode_t dir_mode; 209 200 enum securityEnum sectype; /* sectype requested via mnt opts */ 201 + enum upcall_target_enum upcall_target; /* where to upcall for mount */ 210 202 bool sign; /* was signing requested via mnt opts? */ 211 203 bool ignore_signature:1; 212 204 bool retry:1;
+25 -1
fs/smb/client/inode.c
··· 598 598 mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); 599 599 mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); 600 600 fattr->cf_rdev = MKDEV(mjr, mnr); 601 + } else if (bytes_read == 16) { 602 + /* 603 + * Windows NFS server before Windows Server 2012 604 + * stores major and minor number in SFU-modified 605 + * style, just as 32-bit numbers. Recognize it. 606 + */ 607 + __u32 mjr; /* major */ 608 + __u32 mnr; /* minor */ 609 + mjr = le32_to_cpu(*(__le32 *)(pbuf+8)); 610 + mnr = le32_to_cpu(*(__le32 *)(pbuf+12)); 611 + fattr->cf_rdev = MKDEV(mjr, mnr); 601 612 } 602 613 } else if (memcmp("IntxCHR\0", pbuf, 8) == 0) { 603 614 cifs_dbg(FYI, "Char device\n"); ··· 620 609 __u64 mnr; /* minor */ 621 610 mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); 622 611 mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); 612 + fattr->cf_rdev = MKDEV(mjr, mnr); 613 + } else if (bytes_read == 16) { 614 + /* 615 + * Windows NFS server before Windows Server 2012 616 + * stores major and minor number in SFU-modified 617 + * style, just as 32-bit numbers. Recognize it. 618 + */ 619 + __u32 mjr; /* major */ 620 + __u32 mnr; /* minor */ 621 + mjr = le32_to_cpu(*(__le32 *)(pbuf+8)); 622 + mnr = le32_to_cpu(*(__le32 *)(pbuf+12)); 623 623 fattr->cf_rdev = MKDEV(mjr, mnr); 624 624 } 625 625 } else if (memcmp("LnxSOCK", pbuf, 8) == 0) { ··· 3084 3062 int rc = -EACCES; 3085 3063 __u32 dosattr = 0; 3086 3064 __u64 mode = NO_CHANGE_64; 3065 + bool posix = cifs_sb_master_tcon(cifs_sb)->posix_extensions; 3087 3066 3088 3067 xid = get_xid(); 3089 3068 ··· 3175 3152 mode = attrs->ia_mode; 3176 3153 rc = 0; 3177 3154 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) || 3178 - (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)) { 3155 + (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) || 3156 + posix) { 3179 3157 rc = id_mode_to_cifs_acl(inode, full_path, &mode, 3180 3158 INVALID_UID, INVALID_GID); 3181 3159 if (rc) {
+4 -1
fs/smb/client/reparse.c
··· 35 35 u16 len, plen; 36 36 int rc = 0; 37 37 38 + if (strlen(symname) > REPARSE_SYM_PATH_MAX) 39 + return -ENAMETOOLONG; 40 + 38 41 sym = kstrdup(symname, GFP_KERNEL); 39 42 if (!sym) 40 43 return -ENOMEM; ··· 67 64 if (rc < 0) 68 65 goto out; 69 66 70 - plen = 2 * UniStrnlen((wchar_t *)path, PATH_MAX); 67 + plen = 2 * UniStrnlen((wchar_t *)path, REPARSE_SYM_PATH_MAX); 71 68 len = sizeof(*buf) + plen * 2; 72 69 buf = kzalloc(len, GFP_KERNEL); 73 70 if (!buf) {
+2
fs/smb/client/reparse.h
··· 12 12 #include "fs_context.h" 13 13 #include "cifsglob.h" 14 14 15 + #define REPARSE_SYM_PATH_MAX 4060 16 + 15 17 /* 16 18 * Used only by cifs.ko to ignore reparse points from files when client or 17 19 * server doesn't support FSCTL_GET_REPARSE_POINT.
+4 -35
fs/smb/client/smb2ops.c
··· 2606 2606 struct cifs_ses *ses = tcon->ses; 2607 2607 struct TCP_Server_Info *server = ses->server; 2608 2608 unsigned long len = smb_rqst_len(server, rqst); 2609 - int i, num_padding; 2609 + int num_padding; 2610 2610 2611 2611 shdr = (struct smb2_hdr *)(rqst->rq_iov[0].iov_base); 2612 2612 if (shdr == NULL) { ··· 2615 2615 } 2616 2616 2617 2617 /* SMB headers in a compound are 8 byte aligned. */ 2618 - 2619 - /* No padding needed */ 2620 - if (!(len & 7)) 2621 - goto finished; 2622 - 2623 - num_padding = 8 - (len & 7); 2624 - if (!smb3_encryption_required(tcon)) { 2625 - /* 2626 - * If we do not have encryption then we can just add an extra 2627 - * iov for the padding. 2628 - */ 2618 + if (!IS_ALIGNED(len, 8)) { 2619 + num_padding = 8 - (len & 7); 2629 2620 rqst->rq_iov[rqst->rq_nvec].iov_base = smb2_padding; 2630 2621 rqst->rq_iov[rqst->rq_nvec].iov_len = num_padding; 2631 2622 rqst->rq_nvec++; 2632 2623 len += num_padding; 2633 - } else { 2634 - /* 2635 - * We can not add a small padding iov for the encryption case 2636 - * because the encryption framework can not handle the padding 2637 - * iovs. 2638 - * We have to flatten this into a single buffer and add 2639 - * the padding to it. 2640 - */ 2641 - for (i = 1; i < rqst->rq_nvec; i++) { 2642 - memcpy(rqst->rq_iov[0].iov_base + 2643 - rqst->rq_iov[0].iov_len, 2644 - rqst->rq_iov[i].iov_base, 2645 - rqst->rq_iov[i].iov_len); 2646 - rqst->rq_iov[0].iov_len += rqst->rq_iov[i].iov_len; 2647 - } 2648 - memset(rqst->rq_iov[0].iov_base + rqst->rq_iov[0].iov_len, 2649 - 0, num_padding); 2650 - rqst->rq_iov[0].iov_len += num_padding; 2651 - len += num_padding; 2652 - rqst->rq_nvec = 1; 2653 2624 } 2654 - 2655 - finished: 2656 2625 shdr->NextCommand = cpu_to_le32(len); 2657 2626 } 2658 2627 ··· 4049 4080 if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE) 4050 4081 return SMB2_LEASE_WRITE_CACHING_LE | SMB2_LEASE_READ_CACHING_LE; 4051 4082 else if (oplock == SMB2_OPLOCK_LEVEL_II) 4052 - return SMB2_LEASE_READ_CACHING_LE; 4083 + return SMB2_LEASE_READ_CACHING_LE | SMB2_LEASE_HANDLE_CACHING_LE; 4053 4084 else if (oplock == SMB2_OPLOCK_LEVEL_BATCH) 4054 4085 return SMB2_LEASE_HANDLE_CACHING_LE | SMB2_LEASE_READ_CACHING_LE | 4055 4086 SMB2_LEASE_WRITE_CACHING_LE;
+1 -10
fs/smb/client/smb2pdu.c
··· 2683 2683 ptr += sizeof(struct smb3_acl); 2684 2684 2685 2685 /* create one ACE to hold the mode embedded in reserved special SID */ 2686 - acelen = setup_special_mode_ACE((struct smb_ace *)ptr, (__u64)mode); 2686 + acelen = setup_special_mode_ACE((struct smb_ace *)ptr, false, (__u64)mode); 2687 2687 ptr += acelen; 2688 2688 acl_size = acelen + sizeof(struct smb3_acl); 2689 2689 ace_count = 1; ··· 3313 3313 return rc; 3314 3314 3315 3315 if (indatalen) { 3316 - unsigned int len; 3317 - 3318 - if (WARN_ON_ONCE(smb3_encryption_required(tcon) && 3319 - (check_add_overflow(total_len - 1, 3320 - ALIGN(indatalen, 8), &len) || 3321 - len > MAX_CIFS_SMALL_BUFFER_SIZE))) { 3322 - cifs_small_buf_release(req); 3323 - return -EIO; 3324 - } 3325 3316 /* 3326 3317 * indatalen is usually small at a couple of bytes max, so 3327 3318 * just allocate through generic pool
-2
fs/smb/client/smb2proto.h
··· 37 37 struct smb_rqst *rqst); 38 38 extern struct mid_q_entry *smb2_setup_async_request( 39 39 struct TCP_Server_Info *server, struct smb_rqst *rqst); 40 - extern struct cifs_ses *smb2_find_smb_ses(struct TCP_Server_Info *server, 41 - __u64 ses_id); 42 40 extern struct cifs_tcon *smb2_find_smb_tcon(struct TCP_Server_Info *server, 43 41 __u64 ses_id, __u32 tid); 44 42 extern int smb2_calc_signature(struct smb_rqst *rqst,
+40 -16
fs/smb/client/smb2transport.c
··· 74 74 75 75 76 76 static 77 - int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key) 77 + int smb3_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key) 78 78 { 79 79 struct cifs_chan *chan; 80 80 struct TCP_Server_Info *pserver; ··· 168 168 return NULL; 169 169 } 170 170 171 - struct cifs_ses * 172 - smb2_find_smb_ses(struct TCP_Server_Info *server, __u64 ses_id) 171 + static int smb2_get_sign_key(struct TCP_Server_Info *server, 172 + __u64 ses_id, u8 *key) 173 173 { 174 174 struct cifs_ses *ses; 175 + int rc = -ENOENT; 176 + 177 + if (SERVER_IS_CHAN(server)) 178 + server = server->primary_server; 175 179 176 180 spin_lock(&cifs_tcp_ses_lock); 177 - ses = smb2_find_smb_ses_unlocked(server, ses_id); 178 - spin_unlock(&cifs_tcp_ses_lock); 181 + list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { 182 + if (ses->Suid != ses_id) 183 + continue; 179 184 180 - return ses; 185 + rc = 0; 186 + spin_lock(&ses->ses_lock); 187 + switch (ses->ses_status) { 188 + case SES_EXITING: /* SMB2_LOGOFF */ 189 + case SES_GOOD: 190 + if (likely(ses->auth_key.response)) { 191 + memcpy(key, ses->auth_key.response, 192 + SMB2_NTLMV2_SESSKEY_SIZE); 193 + } else { 194 + rc = -EIO; 195 + } 196 + break; 197 + default: 198 + rc = -EAGAIN; 199 + break; 200 + } 201 + spin_unlock(&ses->ses_lock); 202 + break; 203 + } 204 + spin_unlock(&cifs_tcp_ses_lock); 205 + return rc; 181 206 } 182 207 183 208 static struct cifs_tcon * ··· 261 236 unsigned char *sigptr = smb2_signature; 262 237 struct kvec *iov = rqst->rq_iov; 263 238 struct smb2_hdr *shdr = (struct smb2_hdr *)iov[0].iov_base; 264 - struct cifs_ses *ses; 265 239 struct shash_desc *shash = NULL; 266 240 struct smb_rqst drqst; 241 + __u64 sid = le64_to_cpu(shdr->SessionId); 242 + u8 key[SMB2_NTLMV2_SESSKEY_SIZE]; 267 243 268 - ses = smb2_find_smb_ses(server, le64_to_cpu(shdr->SessionId)); 269 - if (unlikely(!ses)) { 270 - cifs_server_dbg(FYI, "%s: Could not find session\n", __func__); 271 - return -ENOENT; 244 + rc = smb2_get_sign_key(server, sid, key); 245 + if (unlikely(rc)) { 246 + cifs_server_dbg(FYI, "%s: [sesid=0x%llx] couldn't find signing key: %d\n", 247 + __func__, sid, rc); 248 + return rc; 272 249 } 273 250 274 251 memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE); ··· 287 260 shash = server->secmech.hmacsha256; 288 261 } 289 262 290 - rc = crypto_shash_setkey(shash->tfm, ses->auth_key.response, 291 - SMB2_NTLMV2_SESSKEY_SIZE); 263 + rc = crypto_shash_setkey(shash->tfm, key, sizeof(key)); 292 264 if (rc) { 293 265 cifs_server_dbg(VFS, 294 266 "%s: Could not update with response\n", ··· 329 303 out: 330 304 if (allocate_crypto) 331 305 cifs_free_hash(&shash); 332 - if (ses) 333 - cifs_put_smb_ses(ses); 334 306 return rc; 335 307 } 336 308 ··· 594 570 struct smb_rqst drqst; 595 571 u8 key[SMB3_SIGN_KEY_SIZE]; 596 572 597 - rc = smb2_get_sign_key(le64_to_cpu(shdr->SessionId), server, key); 573 + rc = smb3_get_sign_key(le64_to_cpu(shdr->SessionId), server, key); 598 574 if (unlikely(rc)) { 599 575 cifs_server_dbg(FYI, "%s: Could not get signing key\n", __func__); 600 576 return rc;
+13 -27
fs/smb/client/transport.c
··· 418 418 return rc; 419 419 } 420 420 421 - struct send_req_vars { 422 - struct smb2_transform_hdr tr_hdr; 423 - struct smb_rqst rqst[MAX_COMPOUND]; 424 - struct kvec iov; 425 - }; 426 - 427 421 static int 428 422 smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, 429 423 struct smb_rqst *rqst, int flags) 430 424 { 431 - struct send_req_vars *vars; 432 - struct smb_rqst *cur_rqst; 433 - struct kvec *iov; 425 + struct smb2_transform_hdr tr_hdr; 426 + struct smb_rqst new_rqst[MAX_COMPOUND] = {}; 427 + struct kvec iov = { 428 + .iov_base = &tr_hdr, 429 + .iov_len = sizeof(tr_hdr), 430 + }; 434 431 int rc; 435 432 436 433 if (flags & CIFS_COMPRESS_REQ) ··· 444 447 return -EIO; 445 448 } 446 449 447 - vars = kzalloc(sizeof(*vars), GFP_NOFS); 448 - if (!vars) 449 - return -ENOMEM; 450 - cur_rqst = vars->rqst; 451 - iov = &vars->iov; 452 - 453 - iov->iov_base = &vars->tr_hdr; 454 - iov->iov_len = sizeof(vars->tr_hdr); 455 - cur_rqst[0].rq_iov = iov; 456 - cur_rqst[0].rq_nvec = 1; 450 + new_rqst[0].rq_iov = &iov; 451 + new_rqst[0].rq_nvec = 1; 457 452 458 453 rc = server->ops->init_transform_rq(server, num_rqst + 1, 459 - &cur_rqst[0], rqst); 460 - if (rc) 461 - goto out; 462 - 463 - rc = __smb_send_rqst(server, num_rqst + 1, &cur_rqst[0]); 464 - smb3_free_compound_rqst(num_rqst, &cur_rqst[1]); 465 - out: 466 - kfree(vars); 454 + new_rqst, rqst); 455 + if (!rc) { 456 + rc = __smb_send_rqst(server, num_rqst + 1, new_rqst); 457 + smb3_free_compound_rqst(num_rqst, &new_rqst[1]); 458 + } 467 459 return rc; 468 460 } 469 461