Skip to content

Commit cd89d48

Browse files
committed
Merge tag '6.17-rc6-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6
Pull smb client fixes from Steve French: - Two unlink fixes: one for rename and one for deferred close - Four smbdirect/RDMA fixes: fix buffer leak in negotiate, two fixes for races in smbd_destroy, fix offset and length checks in recv_done * tag '6.17-rc6-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: smb: client: fix smbdirect_recv_io leak in smbd_negotiate() error path smb: client: fix file open check in __cifs_unlink() smb: client: let smbd_destroy() call disable_work_sync(&info->post_send_credits_work) smb: client: use disable[_delayed]_work_sync in smbdirect.c smb: client: fix filename matching of deferred files smb: client: let recv_done verify data_offset, data_length and remaining_data_length
2 parents 497b9a7 + daac51c commit cd89d48

4 files changed

Lines changed: 64 additions & 34 deletions

File tree

fs/smb/client/cifsproto.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,8 +312,8 @@ extern void cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode);
312312

313313
extern void cifs_close_all_deferred_files(struct cifs_tcon *cifs_tcon);
314314

315-
extern void cifs_close_deferred_file_under_dentry(struct cifs_tcon *cifs_tcon,
316-
const char *path);
315+
void cifs_close_deferred_file_under_dentry(struct cifs_tcon *cifs_tcon,
316+
struct dentry *dentry);
317317

318318
extern void cifs_mark_open_handles_for_deleted_file(struct inode *inode,
319319
const char *path);

fs/smb/client/inode.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1984,7 +1984,7 @@ static int __cifs_unlink(struct inode *dir, struct dentry *dentry, bool sillyren
19841984
}
19851985

19861986
netfs_wait_for_outstanding_io(inode);
1987-
cifs_close_deferred_file_under_dentry(tcon, full_path);
1987+
cifs_close_deferred_file_under_dentry(tcon, dentry);
19881988
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
19891989
if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
19901990
le64_to_cpu(tcon->fsUnixInfo.Capability))) {
@@ -2003,8 +2003,21 @@ static int __cifs_unlink(struct inode *dir, struct dentry *dentry, bool sillyren
20032003
goto psx_del_no_retry;
20042004
}
20052005

2006-
if (sillyrename || (server->vals->protocol_id > SMB10_PROT_ID &&
2007-
d_is_positive(dentry) && d_count(dentry) > 2))
2006+
/* For SMB2+, if the file is open, we always perform a silly rename.
2007+
*
2008+
* We check for d_count() right after calling
2009+
* cifs_close_deferred_file_under_dentry() to make sure that the
2010+
* dentry's refcount gets dropped in case the file had any deferred
2011+
* close.
2012+
*/
2013+
if (!sillyrename && server->vals->protocol_id > SMB10_PROT_ID) {
2014+
spin_lock(&dentry->d_lock);
2015+
if (d_count(dentry) > 1)
2016+
sillyrename = true;
2017+
spin_unlock(&dentry->d_lock);
2018+
}
2019+
2020+
if (sillyrename)
20082021
rc = -EBUSY;
20092022
else
20102023
rc = server->ops->unlink(xid, tcon, full_path, cifs_sb, dentry);
@@ -2538,10 +2551,10 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
25382551
goto cifs_rename_exit;
25392552
}
25402553

2541-
cifs_close_deferred_file_under_dentry(tcon, from_name);
2554+
cifs_close_deferred_file_under_dentry(tcon, source_dentry);
25422555
if (d_inode(target_dentry) != NULL) {
25432556
netfs_wait_for_outstanding_io(d_inode(target_dentry));
2544-
cifs_close_deferred_file_under_dentry(tcon, to_name);
2557+
cifs_close_deferred_file_under_dentry(tcon, target_dentry);
25452558
}
25462559

25472560
rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry,

fs/smb/client/misc.c

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -832,33 +832,28 @@ cifs_close_all_deferred_files(struct cifs_tcon *tcon)
832832
kfree(tmp_list);
833833
}
834834
}
835-
void
836-
cifs_close_deferred_file_under_dentry(struct cifs_tcon *tcon, const char *path)
835+
836+
void cifs_close_deferred_file_under_dentry(struct cifs_tcon *tcon,
837+
struct dentry *dentry)
837838
{
838-
struct cifsFileInfo *cfile;
839839
struct file_list *tmp_list, *tmp_next_list;
840-
void *page;
841-
const char *full_path;
840+
struct cifsFileInfo *cfile;
842841
LIST_HEAD(file_head);
843842

844-
page = alloc_dentry_path();
845843
spin_lock(&tcon->open_file_lock);
846844
list_for_each_entry(cfile, &tcon->openFileList, tlist) {
847-
full_path = build_path_from_dentry(cfile->dentry, page);
848-
if (strstr(full_path, path)) {
849-
if (delayed_work_pending(&cfile->deferred)) {
850-
if (cancel_delayed_work(&cfile->deferred)) {
851-
spin_lock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
852-
cifs_del_deferred_close(cfile);
853-
spin_unlock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
854-
855-
tmp_list = kmalloc(sizeof(struct file_list), GFP_ATOMIC);
856-
if (tmp_list == NULL)
857-
break;
858-
tmp_list->cfile = cfile;
859-
list_add_tail(&tmp_list->list, &file_head);
860-
}
861-
}
845+
if ((cfile->dentry == dentry) &&
846+
delayed_work_pending(&cfile->deferred) &&
847+
cancel_delayed_work(&cfile->deferred)) {
848+
spin_lock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
849+
cifs_del_deferred_close(cfile);
850+
spin_unlock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
851+
852+
tmp_list = kmalloc(sizeof(struct file_list), GFP_ATOMIC);
853+
if (tmp_list == NULL)
854+
break;
855+
tmp_list->cfile = cfile;
856+
list_add_tail(&tmp_list->list, &file_head);
862857
}
863858
}
864859
spin_unlock(&tcon->open_file_lock);
@@ -868,7 +863,6 @@ cifs_close_deferred_file_under_dentry(struct cifs_tcon *tcon, const char *path)
868863
list_del(&tmp_list->list);
869864
kfree(tmp_list);
870865
}
871-
free_dentry_path(page);
872866
}
873867

874868
/*

fs/smb/client/smbdirect.c

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -453,9 +453,12 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
453453
struct smbdirect_recv_io *response =
454454
container_of(wc->wr_cqe, struct smbdirect_recv_io, cqe);
455455
struct smbdirect_socket *sc = response->socket;
456+
struct smbdirect_socket_parameters *sp = &sc->parameters;
456457
struct smbd_connection *info =
457458
container_of(sc, struct smbd_connection, socket);
458-
int data_length = 0;
459+
u32 data_offset = 0;
460+
u32 data_length = 0;
461+
u32 remaining_data_length = 0;
459462

460463
log_rdma_recv(INFO, "response=0x%p type=%d wc status=%d wc opcode %d byte_len=%d pkey_index=%u\n",
461464
response, sc->recv_io.expected, wc->status, wc->opcode,
@@ -487,7 +490,22 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
487490
/* SMBD data transfer packet */
488491
case SMBDIRECT_EXPECT_DATA_TRANSFER:
489492
data_transfer = smbdirect_recv_io_payload(response);
493+
494+
if (wc->byte_len <
495+
offsetof(struct smbdirect_data_transfer, padding))
496+
goto error;
497+
498+
remaining_data_length = le32_to_cpu(data_transfer->remaining_data_length);
499+
data_offset = le32_to_cpu(data_transfer->data_offset);
490500
data_length = le32_to_cpu(data_transfer->data_length);
501+
if (wc->byte_len < data_offset ||
502+
(u64)wc->byte_len < (u64)data_offset + data_length)
503+
goto error;
504+
505+
if (remaining_data_length > sp->max_fragmented_recv_size ||
506+
data_length > sp->max_fragmented_recv_size ||
507+
(u64)remaining_data_length + (u64)data_length > (u64)sp->max_fragmented_recv_size)
508+
goto error;
491509

492510
if (data_length) {
493511
if (sc->recv_io.reassembly.full_packet_received)
@@ -1090,8 +1108,10 @@ static int smbd_negotiate(struct smbd_connection *info)
10901108
log_rdma_event(INFO, "smbd_post_recv rc=%d iov.addr=0x%llx iov.length=%u iov.lkey=0x%x\n",
10911109
rc, response->sge.addr,
10921110
response->sge.length, response->sge.lkey);
1093-
if (rc)
1111+
if (rc) {
1112+
put_receive_buffer(info, response);
10941113
return rc;
1114+
}
10951115

10961116
init_completion(&info->negotiate_completion);
10971117
info->negotiate_done = false;
@@ -1329,13 +1349,16 @@ void smbd_destroy(struct TCP_Server_Info *server)
13291349
sc->status == SMBDIRECT_SOCKET_DISCONNECTED);
13301350
}
13311351

1352+
log_rdma_event(INFO, "cancelling post_send_credits_work\n");
1353+
disable_work_sync(&info->post_send_credits_work);
1354+
13321355
log_rdma_event(INFO, "destroying qp\n");
13331356
ib_drain_qp(sc->ib.qp);
13341357
rdma_destroy_qp(sc->rdma.cm_id);
13351358
sc->ib.qp = NULL;
13361359

13371360
log_rdma_event(INFO, "cancelling idle timer\n");
1338-
cancel_delayed_work_sync(&info->idle_timer_work);
1361+
disable_delayed_work_sync(&info->idle_timer_work);
13391362

13401363
/* It's not possible for upper layer to get to reassembly */
13411364
log_rdma_event(INFO, "drain the reassembly queue\n");
@@ -1708,7 +1731,7 @@ static struct smbd_connection *_smbd_get_connection(
17081731
return NULL;
17091732

17101733
negotiation_failed:
1711-
cancel_delayed_work_sync(&info->idle_timer_work);
1734+
disable_delayed_work_sync(&info->idle_timer_work);
17121735
destroy_caches_and_workqueue(info);
17131736
sc->status = SMBDIRECT_SOCKET_NEGOTIATE_FAILED;
17141737
rdma_disconnect(sc->rdma.cm_id);
@@ -2067,7 +2090,7 @@ static void destroy_mr_list(struct smbd_connection *info)
20672090
struct smbdirect_socket *sc = &info->socket;
20682091
struct smbd_mr *mr, *tmp;
20692092

2070-
cancel_work_sync(&info->mr_recovery_work);
2093+
disable_work_sync(&info->mr_recovery_work);
20712094
list_for_each_entry_safe(mr, tmp, &info->mr_list, list) {
20722095
if (mr->state == MR_INVALIDATED)
20732096
ib_dma_unmap_sg(sc->ib.dev, mr->sgt.sgl,

0 commit comments

Comments
 (0)