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

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag '6.17-rc1-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull smb client fixes from Steve French:

- Fix unlink race and rename races

- SMB3.1.1 compression fix

- Avoid unneeded strlen calls in cifs_get_spnego_key

- Fix slab out of bounds in parse_server_interfaces()

- Fix mid leak and server buffer leak

- smbdirect send error path fix

- update internal version #

- Fix unneeded response time update in negotiate protocol

* tag '6.17-rc1-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6:
smb: client: remove redundant lstrp update in negotiate protocol
cifs: update internal version number
smb: client: don't wait for info->send_pending == 0 on error
smb: client: fix mid_q_entry memleak leak with per-mid locking
smb3: fix for slab out of bounds on mount to ksmbd
cifs: avoid extra calls to strlen() in cifs_get_spnego_key()
cifs: Fix collect_sample() to handle any iterator type
smb: client: fix race with concurrent opens in rename(2)
smb: client: fix race with concurrent opens in unlink(2)

+123 -105
+18 -29
fs/smb/client/cifs_spnego.c
··· 124 124 dp = description; 125 125 /* start with version and hostname portion of UNC string */ 126 126 spnego_key = ERR_PTR(-EINVAL); 127 - sprintf(dp, "ver=0x%x;host=%s;", CIFS_SPNEGO_UPCALL_VERSION, 128 - hostname); 129 - dp = description + strlen(description); 127 + dp += sprintf(dp, "ver=0x%x;host=%s;", CIFS_SPNEGO_UPCALL_VERSION, 128 + hostname); 130 129 131 130 /* add the server address */ 132 131 if (server->dstaddr.ss_family == AF_INET) 133 - sprintf(dp, "ip4=%pI4", &sa->sin_addr); 132 + dp += sprintf(dp, "ip4=%pI4", &sa->sin_addr); 134 133 else if (server->dstaddr.ss_family == AF_INET6) 135 - sprintf(dp, "ip6=%pI6", &sa6->sin6_addr); 134 + dp += sprintf(dp, "ip6=%pI6", &sa6->sin6_addr); 136 135 else 137 136 goto out; 138 137 139 - dp = description + strlen(description); 140 - 141 138 /* for now, only sec=krb5 and sec=mskrb5 and iakerb are valid */ 142 139 if (server->sec_kerberos) 143 - sprintf(dp, ";sec=krb5"); 140 + dp += sprintf(dp, ";sec=krb5"); 144 141 else if (server->sec_mskerberos) 145 - sprintf(dp, ";sec=mskrb5"); 142 + dp += sprintf(dp, ";sec=mskrb5"); 146 143 else if (server->sec_iakerb) 147 - sprintf(dp, ";sec=iakerb"); 144 + dp += sprintf(dp, ";sec=iakerb"); 148 145 else { 149 146 cifs_dbg(VFS, "unknown or missing server auth type, use krb5\n"); 150 - sprintf(dp, ";sec=krb5"); 147 + dp += sprintf(dp, ";sec=krb5"); 151 148 } 152 149 153 - dp = description + strlen(description); 154 - sprintf(dp, ";uid=0x%x", 155 - from_kuid_munged(&init_user_ns, sesInfo->linux_uid)); 150 + dp += sprintf(dp, ";uid=0x%x", 151 + from_kuid_munged(&init_user_ns, sesInfo->linux_uid)); 156 152 157 - dp = description + strlen(description); 158 - sprintf(dp, ";creduid=0x%x", 153 + dp += sprintf(dp, ";creduid=0x%x", 159 154 from_kuid_munged(&init_user_ns, sesInfo->cred_uid)); 160 155 161 - if (sesInfo->user_name) { 162 - dp = description + strlen(description); 163 - sprintf(dp, ";user=%s", sesInfo->user_name); 164 - } 156 + if (sesInfo->user_name) 157 + dp += sprintf(dp, ";user=%s", sesInfo->user_name); 165 158 166 - dp = description + strlen(description); 167 - sprintf(dp, ";pid=0x%x", current->pid); 159 + dp += sprintf(dp, ";pid=0x%x", current->pid); 168 160 169 - if (sesInfo->upcall_target == UPTARGET_MOUNT) { 170 - dp = description + strlen(description); 171 - sprintf(dp, ";upcall_target=mount"); 172 - } else { 173 - dp = description + strlen(description); 174 - sprintf(dp, ";upcall_target=app"); 175 - } 161 + if (sesInfo->upcall_target == UPTARGET_MOUNT) 162 + dp += sprintf(dp, ";upcall_target=mount"); 163 + else 164 + dp += sprintf(dp, ";upcall_target=app"); 176 165 177 166 cifs_dbg(FYI, "key description = %s\n", description); 178 167 saved_cred = override_creds(spnego_cred);
+2 -2
fs/smb/client/cifsfs.h
··· 145 145 #endif /* CONFIG_CIFS_NFSD_EXPORT */ 146 146 147 147 /* when changing internal version - update following two lines at same time */ 148 - #define SMB3_PRODUCT_BUILD 55 149 - #define CIFS_VERSION "2.55" 148 + #define SMB3_PRODUCT_BUILD 56 149 + #define CIFS_VERSION "2.56" 150 150 #endif /* _CIFSFS_H */
+21
fs/smb/client/cifsglob.h
··· 1732 1732 int mid_rc; /* rc for MID_RC */ 1733 1733 __le16 command; /* smb command code */ 1734 1734 unsigned int optype; /* operation type */ 1735 + spinlock_t mid_lock; 1735 1736 bool wait_cancelled:1; /* Cancelled while waiting for response */ 1736 1737 bool deleted_from_q:1; /* Whether Mid has been dequeued frem pending_mid_q */ 1737 1738 bool large_buf:1; /* if valid response, is pointer to large buf */ ··· 2037 2036 * cifsFileInfo->file_info_lock cifsFileInfo->count cifs_new_fileinfo 2038 2037 * ->invalidHandle initiate_cifs_search 2039 2038 * ->oplock_break_cancelled 2039 + * mid_q_entry->mid_lock mid_q_entry->callback alloc_mid 2040 + * smb2_mid_entry_alloc 2041 + * (Any fields of mid_q_entry that will need protection) 2040 2042 ****************************************************************************/ 2041 2043 2042 2044 #ifdef DECLARE_GLOBALS_HERE ··· 2377 2373 } 2378 2374 } 2379 2375 return ret; 2376 + } 2377 + 2378 + /* 2379 + * Execute mid callback atomically - ensures callback runs exactly once 2380 + * and prevents sleeping in atomic context. 2381 + */ 2382 + static inline void mid_execute_callback(struct mid_q_entry *mid) 2383 + { 2384 + void (*callback)(struct mid_q_entry *mid); 2385 + 2386 + spin_lock(&mid->mid_lock); 2387 + callback = mid->callback; 2388 + mid->callback = NULL; /* Mark as executed, */ 2389 + spin_unlock(&mid->mid_lock); 2390 + 2391 + if (callback) 2392 + callback(mid); 2380 2393 } 2381 2394 2382 2395 #define CIFS_REPARSE_SUPPORT(tcon) \
+9 -10
fs/smb/client/cifstransport.c
··· 46 46 temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS); 47 47 memset(temp, 0, sizeof(struct mid_q_entry)); 48 48 kref_init(&temp->refcount); 49 + spin_lock_init(&temp->mid_lock); 49 50 temp->mid = get_mid(smb_buffer); 50 51 temp->pid = current->pid; 51 52 temp->command = cpu_to_le16(smb_buffer->Command); ··· 346 345 rc = wait_for_response(server, midQ); 347 346 if (rc != 0) { 348 347 send_cancel(server, &rqst, midQ); 349 - spin_lock(&server->mid_queue_lock); 350 - if (midQ->mid_state == MID_REQUEST_SUBMITTED || 351 - midQ->mid_state == MID_RESPONSE_RECEIVED) { 348 + spin_lock(&midQ->mid_lock); 349 + if (midQ->callback) { 352 350 /* no longer considered to be "in-flight" */ 353 351 midQ->callback = release_mid; 354 - spin_unlock(&server->mid_queue_lock); 352 + spin_unlock(&midQ->mid_lock); 355 353 add_credits(server, &credits, 0); 356 354 return rc; 357 355 } 358 - spin_unlock(&server->mid_queue_lock); 356 + spin_unlock(&midQ->mid_lock); 359 357 } 360 358 361 359 rc = cifs_sync_mid_result(midQ, server); ··· 527 527 rc = wait_for_response(server, midQ); 528 528 if (rc) { 529 529 send_cancel(server, &rqst, midQ); 530 - spin_lock(&server->mid_queue_lock); 531 - if (midQ->mid_state == MID_REQUEST_SUBMITTED || 532 - midQ->mid_state == MID_RESPONSE_RECEIVED) { 530 + spin_lock(&midQ->mid_lock); 531 + if (midQ->callback) { 533 532 /* no longer considered to be "in-flight" */ 534 533 midQ->callback = release_mid; 535 - spin_unlock(&server->mid_queue_lock); 534 + spin_unlock(&midQ->mid_lock); 536 535 return rc; 537 536 } 538 - spin_unlock(&server->mid_queue_lock); 537 + spin_unlock(&midQ->mid_lock); 539 538 } 540 539 541 540 /* We got the response - restart system call. */
+16 -45
fs/smb/client/compress.c
··· 155 155 } 156 156 157 157 /* 158 - * TODO: 159 - * Support other iter types, if required. 160 - * Only ITER_XARRAY is supported for now. 158 + * Collect some 2K samples with 2K gaps between. 161 159 */ 162 - static int collect_sample(const struct iov_iter *iter, ssize_t max, u8 *sample) 160 + static int collect_sample(const struct iov_iter *source, ssize_t max, u8 *sample) 163 161 { 164 - struct folio *folios[16], *folio; 165 - unsigned int nr, i, j, npages; 166 - loff_t start = iter->xarray_start + iter->iov_offset; 167 - pgoff_t last, index = start / PAGE_SIZE; 168 - size_t len, off, foff; 169 - void *p; 170 - int s = 0; 162 + struct iov_iter iter = *source; 163 + size_t s = 0; 171 164 172 - last = (start + max - 1) / PAGE_SIZE; 173 - do { 174 - nr = xa_extract(iter->xarray, (void **)folios, index, last, ARRAY_SIZE(folios), 175 - XA_PRESENT); 176 - if (nr == 0) 177 - return -EIO; 165 + while (iov_iter_count(&iter) >= SZ_2K) { 166 + size_t part = umin(umin(iov_iter_count(&iter), SZ_2K), max); 167 + size_t n; 178 168 179 - for (i = 0; i < nr; i++) { 180 - folio = folios[i]; 181 - npages = folio_nr_pages(folio); 182 - foff = start - folio_pos(folio); 183 - off = foff % PAGE_SIZE; 169 + n = copy_from_iter(sample + s, part, &iter); 170 + if (n != part) 171 + return -EFAULT; 184 172 185 - for (j = foff / PAGE_SIZE; j < npages; j++) { 186 - size_t len2; 173 + s += n; 174 + max -= n; 187 175 188 - len = min_t(size_t, max, PAGE_SIZE - off); 189 - len2 = min_t(size_t, len, SZ_2K); 176 + if (iov_iter_count(&iter) < PAGE_SIZE - SZ_2K) 177 + break; 190 178 191 - p = kmap_local_page(folio_page(folio, j)); 192 - memcpy(&sample[s], p, len2); 193 - kunmap_local(p); 194 - 195 - s += len2; 196 - 197 - if (len2 < SZ_2K || s >= max - SZ_2K) 198 - return s; 199 - 200 - max -= len; 201 - if (max <= 0) 202 - return s; 203 - 204 - start += len; 205 - off = 0; 206 - index++; 207 - } 208 - } 209 - } while (nr == ARRAY_SIZE(folios)); 179 + iov_iter_advance(&iter, SZ_2K); 180 + } 210 181 211 182 return s; 212 183 }
+4 -5
fs/smb/client/connect.c
··· 335 335 cifs_dbg(FYI, "%s: issuing mid callbacks\n", __func__); 336 336 list_for_each_entry_safe(mid, nmid, &retry_list, qhead) { 337 337 list_del_init(&mid->qhead); 338 - mid->callback(mid); 338 + mid_execute_callback(mid); 339 339 release_mid(mid); 340 340 } 341 341 ··· 919 919 list_del_init(&mid->qhead); 920 920 mid->mid_rc = mid_rc; 921 921 mid->mid_state = MID_RC; 922 - mid->callback(mid); 922 + mid_execute_callback(mid); 923 923 release_mid(mid); 924 924 } 925 925 ··· 1117 1117 mid_entry = list_entry(tmp, struct mid_q_entry, qhead); 1118 1118 cifs_dbg(FYI, "Callback mid %llu\n", mid_entry->mid); 1119 1119 list_del_init(&mid_entry->qhead); 1120 - mid_entry->callback(mid_entry); 1120 + mid_execute_callback(mid_entry); 1121 1121 release_mid(mid_entry); 1122 1122 } 1123 1123 /* 1/8th of sec is more than enough time for them to exit */ ··· 1394 1394 } 1395 1395 1396 1396 if (!mids[i]->multiRsp || mids[i]->multiEnd) 1397 - mids[i]->callback(mids[i]); 1397 + mid_execute_callback(mids[i]); 1398 1398 1399 1399 release_mid(mids[i]); 1400 1400 } else if (server->ops->is_oplock_break && ··· 4205 4205 return 0; 4206 4206 } 4207 4207 4208 - server->lstrp = jiffies; 4209 4208 server->tcpStatus = CifsInNegotiate; 4210 4209 server->neg_start = jiffies; 4211 4210 spin_unlock(&server->srv_lock);
+32 -2
fs/smb/client/inode.c
··· 1943 1943 struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 1944 1944 struct tcon_link *tlink; 1945 1945 struct cifs_tcon *tcon; 1946 + __u32 dosattr = 0, origattr = 0; 1946 1947 struct TCP_Server_Info *server; 1947 1948 struct iattr *attrs = NULL; 1948 - __u32 dosattr = 0, origattr = 0; 1949 + bool rehash = false; 1949 1950 1950 1951 cifs_dbg(FYI, "cifs_unlink, dir=0x%p, dentry=0x%p\n", dir, dentry); 1951 1952 1952 1953 if (unlikely(cifs_forced_shutdown(cifs_sb))) 1953 1954 return -EIO; 1955 + 1956 + /* Unhash dentry in advance to prevent any concurrent opens */ 1957 + spin_lock(&dentry->d_lock); 1958 + if (!d_unhashed(dentry)) { 1959 + __d_drop(dentry); 1960 + rehash = true; 1961 + } 1962 + spin_unlock(&dentry->d_lock); 1954 1963 1955 1964 tlink = cifs_sb_tlink(cifs_sb); 1956 1965 if (IS_ERR(tlink)) ··· 2012 2003 cifs_drop_nlink(inode); 2013 2004 } 2014 2005 } else if (rc == -ENOENT) { 2015 - d_drop(dentry); 2006 + if (simple_positive(dentry)) 2007 + d_delete(dentry); 2016 2008 } else if (rc == -EBUSY) { 2017 2009 if (server->ops->rename_pending_delete) { 2018 2010 rc = server->ops->rename_pending_delete(full_path, ··· 2066 2056 kfree(attrs); 2067 2057 free_xid(xid); 2068 2058 cifs_put_tlink(tlink); 2059 + if (rehash) 2060 + d_rehash(dentry); 2069 2061 return rc; 2070 2062 } 2071 2063 ··· 2474 2462 struct cifs_sb_info *cifs_sb; 2475 2463 struct tcon_link *tlink; 2476 2464 struct cifs_tcon *tcon; 2465 + bool rehash = false; 2477 2466 unsigned int xid; 2478 2467 int rc, tmprc; 2479 2468 int retry_count = 0; ··· 2489 2476 cifs_sb = CIFS_SB(source_dir->i_sb); 2490 2477 if (unlikely(cifs_forced_shutdown(cifs_sb))) 2491 2478 return -EIO; 2479 + 2480 + /* 2481 + * Prevent any concurrent opens on the target by unhashing the dentry. 2482 + * VFS already unhashes the target when renaming directories. 2483 + */ 2484 + if (d_is_positive(target_dentry) && !d_is_dir(target_dentry)) { 2485 + if (!d_unhashed(target_dentry)) { 2486 + d_drop(target_dentry); 2487 + rehash = true; 2488 + } 2489 + } 2492 2490 2493 2491 tlink = cifs_sb_tlink(cifs_sb); 2494 2492 if (IS_ERR(tlink)) ··· 2542 2518 } 2543 2519 } 2544 2520 2521 + if (!rc) 2522 + rehash = false; 2545 2523 /* 2546 2524 * No-replace is the natural behavior for CIFS, so skip unlink hacks. 2547 2525 */ ··· 2602 2576 goto cifs_rename_exit; 2603 2577 rc = cifs_do_rename(xid, source_dentry, from_name, 2604 2578 target_dentry, to_name); 2579 + if (!rc) 2580 + rehash = false; 2605 2581 } 2606 2582 2607 2583 /* force revalidate to go get info when needed */ 2608 2584 CIFS_I(source_dir)->time = CIFS_I(target_dir)->time = 0; 2609 2585 2610 2586 cifs_rename_exit: 2587 + if (rehash) 2588 + d_rehash(target_dentry); 2611 2589 kfree(info_buf_source); 2612 2590 free_dentry_path(page2); 2613 2591 free_dentry_path(page1);
+12 -3
fs/smb/client/smb2ops.c
··· 772 772 bytes_left -= sizeof(*p); 773 773 break; 774 774 } 775 + /* Validate that Next doesn't point beyond the buffer */ 776 + if (next > bytes_left) { 777 + cifs_dbg(VFS, "%s: invalid Next pointer %zu > %zd\n", 778 + __func__, next, bytes_left); 779 + rc = -EINVAL; 780 + goto out; 781 + } 775 782 p = (struct network_interface_info_ioctl_rsp *)((u8 *)p+next); 776 783 bytes_left -= next; 777 784 } ··· 790 783 } 791 784 792 785 /* Azure rounds the buffer size up 8, to a 16 byte boundary */ 793 - if ((bytes_left > 8) || p->Next) 786 + if ((bytes_left > 8) || 787 + (bytes_left >= offsetof(struct network_interface_info_ioctl_rsp, Next) 788 + + sizeof(p->Next) && p->Next)) 794 789 cifs_dbg(VFS, "%s: incomplete interface info\n", __func__); 795 790 796 791 ses->iface_last_update = jiffies; ··· 4814 4805 dw->server->ops->is_network_name_deleted(dw->buf, 4815 4806 dw->server); 4816 4807 4817 - mid->callback(mid); 4808 + mid_execute_callback(mid); 4818 4809 } else { 4819 4810 spin_lock(&dw->server->srv_lock); 4820 4811 if (dw->server->tcpStatus == CifsNeedReconnect) { ··· 4822 4813 mid->mid_state = MID_RETRY_NEEDED; 4823 4814 spin_unlock(&dw->server->mid_queue_lock); 4824 4815 spin_unlock(&dw->server->srv_lock); 4825 - mid->callback(mid); 4816 + mid_execute_callback(mid); 4826 4817 } else { 4827 4818 spin_lock(&dw->server->mid_queue_lock); 4828 4819 mid->mid_state = MID_REQUEST_SUBMITTED;
+1
fs/smb/client/smb2transport.c
··· 771 771 temp = mempool_alloc(cifs_mid_poolp, GFP_NOFS); 772 772 memset(temp, 0, sizeof(struct mid_q_entry)); 773 773 kref_init(&temp->refcount); 774 + spin_lock_init(&temp->mid_lock); 774 775 temp->mid = le64_to_cpu(shdr->MessageId); 775 776 temp->credits = credits > 0 ? credits : 1; 776 777 temp->pid = current->pid;
+5 -5
fs/smb/client/smbdirect.c
··· 1337 1337 log_rdma_event(INFO, "cancelling idle timer\n"); 1338 1338 cancel_delayed_work_sync(&info->idle_timer_work); 1339 1339 1340 - log_rdma_event(INFO, "wait for all send posted to IB to finish\n"); 1341 - wait_event(info->wait_send_pending, 1342 - atomic_read(&info->send_pending) == 0); 1343 - 1344 1340 /* It's not possible for upper layer to get to reassembly */ 1345 1341 log_rdma_event(INFO, "drain the reassembly queue\n"); 1346 1342 do { ··· 1982 1986 */ 1983 1987 1984 1988 wait_event(info->wait_send_pending, 1985 - atomic_read(&info->send_pending) == 0); 1989 + atomic_read(&info->send_pending) == 0 || 1990 + sc->status != SMBDIRECT_SOCKET_CONNECTED); 1991 + 1992 + if (sc->status != SMBDIRECT_SOCKET_CONNECTED && rc == 0) 1993 + rc = -EAGAIN; 1986 1994 1987 1995 return rc; 1988 1996 }
+3 -4
fs/smb/client/transport.c
··· 1005 1005 cifs_server_dbg(FYI, "Cancelling wait for mid %llu cmd: %d\n", 1006 1006 midQ[i]->mid, le16_to_cpu(midQ[i]->command)); 1007 1007 send_cancel(server, &rqst[i], midQ[i]); 1008 - spin_lock(&server->mid_queue_lock); 1008 + spin_lock(&midQ[i]->mid_lock); 1009 1009 midQ[i]->wait_cancelled = true; 1010 - if (midQ[i]->mid_state == MID_REQUEST_SUBMITTED || 1011 - midQ[i]->mid_state == MID_RESPONSE_RECEIVED) { 1010 + if (midQ[i]->callback) { 1012 1011 midQ[i]->callback = cifs_cancelled_callback; 1013 1012 cancelled_mid[i] = true; 1014 1013 credits[i].value = 0; 1015 1014 } 1016 - spin_unlock(&server->mid_queue_lock); 1015 + spin_unlock(&midQ[i]->mid_lock); 1017 1016 } 1018 1017 } 1019 1018