Skip to content

Commit fe575dd

Browse files
committed
ksmbd: fix use-after-free in ksmbd_free_work_struct
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
1 parent a065811 commit fe575dd

File tree

4 files changed

+15
-27
lines changed

4 files changed

+15
-27
lines changed

ksmbd_work.c

-3
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ struct ksmbd_work *ksmbd_alloc_work_struct(void)
2626
INIT_LIST_HEAD(&work->request_entry);
2727
INIT_LIST_HEAD(&work->async_request_entry);
2828
INIT_LIST_HEAD(&work->fp_entry);
29-
INIT_LIST_HEAD(&work->interim_entry);
3029
INIT_LIST_HEAD(&work->aux_read_list);
3130
work->iov_alloc_cnt = 4;
3231
work->iov = kzalloc(sizeof(struct kvec) * work->iov_alloc_cnt,
@@ -59,8 +58,6 @@ void ksmbd_free_work_struct(struct ksmbd_work *work)
5958
kfree(work->tr_buf);
6059
kvfree(work->request_buf);
6160
kfree(work->iov);
62-
if (!list_empty(&work->interim_entry))
63-
list_del(&work->interim_entry);
6461

6562
if (work->async_id)
6663
ksmbd_release_id(&work->conn->async_ida, work->async_id);

ksmbd_work.h

-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ struct ksmbd_work {
8989
/* List head at conn->async_requests */
9090
struct list_head async_request_entry;
9191
struct list_head fp_entry;
92-
struct list_head interim_entry;
9392

9493
#ifdef CONFIG_SMB_INSECURE_SERVER
9594
/* Read data buffer */

oplock.c

+15-22
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ static struct oplock_info *alloc_opinfo(struct ksmbd_work *work,
5252
opinfo->is_smb2 = IS_SMB2(conn);
5353
#endif
5454
INIT_LIST_HEAD(&opinfo->op_entry);
55-
INIT_LIST_HEAD(&opinfo->interim_list);
5655
init_waitqueue_head(&opinfo->oplock_q);
5756
init_waitqueue_head(&opinfo->oplock_brk);
5857
atomic_set(&opinfo->refcount, 1);
@@ -1005,7 +1004,6 @@ static void __smb2_lease_break_noti(struct work_struct *wk)
10051004
static int smb2_lease_break_noti(struct oplock_info *opinfo)
10061005
{
10071006
struct ksmbd_conn *conn = opinfo->conn;
1008-
struct list_head *tmp, *t;
10091007
struct ksmbd_work *work;
10101008
struct lease_break_info *br_info;
10111009
struct lease *lease = opinfo->o_lease;
@@ -1033,16 +1031,6 @@ static int smb2_lease_break_noti(struct oplock_info *opinfo)
10331031
work->sess = opinfo->sess;
10341032

10351033
if (opinfo->op_state == OPLOCK_ACK_WAIT) {
1036-
list_for_each_safe(tmp, t, &opinfo->interim_list) {
1037-
struct ksmbd_work *in_work;
1038-
1039-
in_work = list_entry(tmp, struct ksmbd_work,
1040-
interim_entry);
1041-
setup_async_work(in_work, NULL, NULL);
1042-
smb2_send_interim_resp(in_work, STATUS_PENDING);
1043-
list_del_init(&in_work->interim_entry);
1044-
release_async_work(in_work);
1045-
}
10461034
INIT_WORK(&work->work, __smb2_lease_break_noti);
10471035
ksmbd_queue_work(work);
10481036
wait_for_break_ack(opinfo);
@@ -1073,7 +1061,8 @@ static void wait_lease_breaking(struct oplock_info *opinfo)
10731061
}
10741062
}
10751063

1076-
static int oplock_break(struct oplock_info *brk_opinfo, int req_op_level)
1064+
static int oplock_break(struct oplock_info *brk_opinfo, int req_op_level,
1065+
struct ksmbd_work *in_work)
10771066
{
10781067
int err = 0;
10791068

@@ -1116,9 +1105,15 @@ static int oplock_break(struct oplock_info *brk_opinfo, int req_op_level)
11161105
}
11171106

11181107
if (lease->state & (SMB2_LEASE_WRITE_CACHING_LE |
1119-
SMB2_LEASE_HANDLE_CACHING_LE))
1108+
SMB2_LEASE_HANDLE_CACHING_LE)) {
1109+
if (in_work) {
1110+
setup_async_work(in_work, NULL, NULL);
1111+
smb2_send_interim_resp(in_work, STATUS_PENDING);
1112+
release_async_work(in_work);
1113+
}
1114+
11201115
brk_opinfo->op_state = OPLOCK_ACK_WAIT;
1121-
else
1116+
} else
11221117
atomic_dec(&brk_opinfo->breaking_cnt);
11231118
} else {
11241119
err = oplock_break_pending(brk_opinfo, req_op_level);
@@ -1332,7 +1327,7 @@ void smb_send_parent_lease_break_noti(struct ksmbd_file *fp,
13321327
if (ksmbd_conn_releasing(opinfo->conn))
13331328
continue;
13341329

1335-
oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE);
1330+
oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE, NULL);
13361331
opinfo_put(opinfo);
13371332
}
13381333
}
@@ -1368,7 +1363,7 @@ void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp)
13681363

13691364
if (ksmbd_conn_releasing(opinfo->conn))
13701365
continue;
1371-
oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE);
1366+
oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE, NULL);
13721367
opinfo_put(opinfo);
13731368
}
13741369
}
@@ -1468,8 +1463,7 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,
14681463
goto op_break_not_needed;
14691464
}
14701465

1471-
list_add(&work->interim_entry, &prev_opinfo->interim_list);
1472-
err = oplock_break(prev_opinfo, SMB2_OPLOCK_LEVEL_II);
1466+
err = oplock_break(prev_opinfo, SMB2_OPLOCK_LEVEL_II, work);
14731467
opinfo_put(prev_opinfo);
14741468
if (err == -ENOENT)
14751469
goto set_lev;
@@ -1538,8 +1532,7 @@ static void smb_break_all_write_oplock(struct ksmbd_work *work,
15381532
}
15391533

15401534
brk_opinfo->open_trunc = is_trunc;
1541-
list_add(&work->interim_entry, &brk_opinfo->interim_list);
1542-
oplock_break(brk_opinfo, SMB2_OPLOCK_LEVEL_II);
1535+
oplock_break(brk_opinfo, SMB2_OPLOCK_LEVEL_II, work);
15431536
opinfo_put(brk_opinfo);
15441537
}
15451538

@@ -1633,7 +1626,7 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,
16331626
SMB2_LEASE_KEY_SIZE))
16341627
goto next;
16351628
brk_op->open_trunc = is_trunc;
1636-
oplock_break(brk_op, SMB2_OPLOCK_LEVEL_NONE);
1629+
oplock_break(brk_op, SMB2_OPLOCK_LEVEL_NONE, NULL);
16371630
next:
16381631
opinfo_put(brk_op);
16391632
rcu_read_lock();

oplock.h

-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ struct oplock_info {
7878
#endif
7979
bool open_trunc; /* truncate on open */
8080
struct lease *o_lease;
81-
struct list_head interim_list;
8281
struct list_head op_entry;
8382
struct list_head lease_entry;
8483
wait_queue_head_t oplock_q; /* Other server threads */

0 commit comments

Comments
 (0)