Skip to content

Commit 7e74f75

Browse files
committed
Merge tag 'v6.15-rc2-ksmbd-server-fixes' of git://git.samba.org/ksmbd
Pull smb server fixes from Steve French: - Fix integer overflow in server disconnect deadtime calculation - Three fixes for potential use after frees: one for oplocks, and one for leases and one for kerberos authentication - Fix to prevent attempted write to directory - Fix locking warning for durable scavenger thread * tag 'v6.15-rc2-ksmbd-server-fixes' of git://git.samba.org/ksmbd: ksmbd: Prevent integer overflow in calculation of deadtime ksmbd: fix the warning from __kernel_write_iter ksmbd: fix use-after-free in smb_break_all_levII_oplock() ksmbd: fix use-after-free in __smb2_lease_break_noti() ksmbd: fix WARNING "do not call blocking ops when !TASK_RUNNING" ksmbd: Fix dangling pointer in krb_authenticate
2 parents f7c2ca2 + a93ff74 commit 7e74f75

File tree

9 files changed

+34
-37
lines changed

9 files changed

+34
-37
lines changed

fs/smb/server/connection.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,10 @@ void ksmbd_conn_free(struct ksmbd_conn *conn)
3939
xa_destroy(&conn->sessions);
4040
kvfree(conn->request_buf);
4141
kfree(conn->preauth_info);
42-
if (atomic_dec_and_test(&conn->refcnt))
42+
if (atomic_dec_and_test(&conn->refcnt)) {
43+
ksmbd_free_transport(conn->transport);
4344
kfree(conn);
45+
}
4446
}
4547

4648
/**

fs/smb/server/oplock.c

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -129,14 +129,6 @@ static void free_opinfo(struct oplock_info *opinfo)
129129
kfree(opinfo);
130130
}
131131

132-
static inline void opinfo_free_rcu(struct rcu_head *rcu_head)
133-
{
134-
struct oplock_info *opinfo;
135-
136-
opinfo = container_of(rcu_head, struct oplock_info, rcu_head);
137-
free_opinfo(opinfo);
138-
}
139-
140132
struct oplock_info *opinfo_get(struct ksmbd_file *fp)
141133
{
142134
struct oplock_info *opinfo;
@@ -157,8 +149,8 @@ static struct oplock_info *opinfo_get_list(struct ksmbd_inode *ci)
157149
if (list_empty(&ci->m_op_list))
158150
return NULL;
159151

160-
rcu_read_lock();
161-
opinfo = list_first_or_null_rcu(&ci->m_op_list, struct oplock_info,
152+
down_read(&ci->m_lock);
153+
opinfo = list_first_entry(&ci->m_op_list, struct oplock_info,
162154
op_entry);
163155
if (opinfo) {
164156
if (opinfo->conn == NULL ||
@@ -171,8 +163,7 @@ static struct oplock_info *opinfo_get_list(struct ksmbd_inode *ci)
171163
}
172164
}
173165
}
174-
175-
rcu_read_unlock();
166+
up_read(&ci->m_lock);
176167

177168
return opinfo;
178169
}
@@ -185,15 +176,15 @@ void opinfo_put(struct oplock_info *opinfo)
185176
if (!atomic_dec_and_test(&opinfo->refcount))
186177
return;
187178

188-
call_rcu(&opinfo->rcu_head, opinfo_free_rcu);
179+
free_opinfo(opinfo);
189180
}
190181

191182
static void opinfo_add(struct oplock_info *opinfo)
192183
{
193184
struct ksmbd_inode *ci = opinfo->o_fp->f_ci;
194185

195186
down_write(&ci->m_lock);
196-
list_add_rcu(&opinfo->op_entry, &ci->m_op_list);
187+
list_add(&opinfo->op_entry, &ci->m_op_list);
197188
up_write(&ci->m_lock);
198189
}
199190

@@ -207,7 +198,7 @@ static void opinfo_del(struct oplock_info *opinfo)
207198
write_unlock(&lease_list_lock);
208199
}
209200
down_write(&ci->m_lock);
210-
list_del_rcu(&opinfo->op_entry);
201+
list_del(&opinfo->op_entry);
211202
up_write(&ci->m_lock);
212203
}
213204

@@ -1347,8 +1338,8 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,
13471338
ci = fp->f_ci;
13481339
op = opinfo_get(fp);
13491340

1350-
rcu_read_lock();
1351-
list_for_each_entry_rcu(brk_op, &ci->m_op_list, op_entry) {
1341+
down_read(&ci->m_lock);
1342+
list_for_each_entry(brk_op, &ci->m_op_list, op_entry) {
13521343
if (brk_op->conn == NULL)
13531344
continue;
13541345

@@ -1358,7 +1349,6 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,
13581349
if (ksmbd_conn_releasing(brk_op->conn))
13591350
continue;
13601351

1361-
rcu_read_unlock();
13621352
if (brk_op->is_lease && (brk_op->o_lease->state &
13631353
(~(SMB2_LEASE_READ_CACHING_LE |
13641354
SMB2_LEASE_HANDLE_CACHING_LE)))) {
@@ -1388,9 +1378,8 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,
13881378
oplock_break(brk_op, SMB2_OPLOCK_LEVEL_NONE, NULL);
13891379
next:
13901380
opinfo_put(brk_op);
1391-
rcu_read_lock();
13921381
}
1393-
rcu_read_unlock();
1382+
up_read(&ci->m_lock);
13941383

13951384
if (op)
13961385
opinfo_put(op);

fs/smb/server/oplock.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ struct oplock_info {
7171
struct list_head lease_entry;
7272
wait_queue_head_t oplock_q; /* Other server threads */
7373
wait_queue_head_t oplock_brk; /* oplock breaking wait */
74-
struct rcu_head rcu_head;
7574
};
7675

7776
struct lease_break_info {

fs/smb/server/smb2pdu.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1602,8 +1602,10 @@ static int krb5_authenticate(struct ksmbd_work *work,
16021602
if (prev_sess_id && prev_sess_id != sess->id)
16031603
destroy_previous_session(conn, sess->user, prev_sess_id);
16041604

1605-
if (sess->state == SMB2_SESSION_VALID)
1605+
if (sess->state == SMB2_SESSION_VALID) {
16061606
ksmbd_free_user(sess->user);
1607+
sess->user = NULL;
1608+
}
16071609

16081610
retval = ksmbd_krb5_authenticate(sess, in_blob, in_len,
16091611
out_blob, &out_len);

fs/smb/server/transport_ipc.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,11 @@ static int ipc_server_config_on_startup(struct ksmbd_startup_request *req)
310310
server_conf.signing = req->signing;
311311
server_conf.tcp_port = req->tcp_port;
312312
server_conf.ipc_timeout = req->ipc_timeout * HZ;
313-
server_conf.deadtime = req->deadtime * SMB_ECHO_INTERVAL;
313+
if (check_mul_overflow(req->deadtime, SMB_ECHO_INTERVAL,
314+
&server_conf.deadtime)) {
315+
ret = -EINVAL;
316+
goto out;
317+
}
314318
server_conf.share_fake_fscaps = req->share_fake_fscaps;
315319
ksmbd_init_domain(req->sub_auth);
316320

@@ -337,6 +341,7 @@ static int ipc_server_config_on_startup(struct ksmbd_startup_request *req)
337341
server_conf.bind_interfaces_only = req->bind_interfaces_only;
338342
ret |= ksmbd_tcp_set_interfaces(KSMBD_STARTUP_CONFIG_INTERFACES(req),
339343
req->ifc_list_sz);
344+
out:
340345
if (ret) {
341346
pr_err("Server configuration error: %s %s %s\n",
342347
req->netbios_name, req->server_string,

fs/smb/server/transport_tcp.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,17 +93,21 @@ static struct tcp_transport *alloc_transport(struct socket *client_sk)
9393
return t;
9494
}
9595

96-
static void free_transport(struct tcp_transport *t)
96+
void ksmbd_free_transport(struct ksmbd_transport *kt)
9797
{
98-
kernel_sock_shutdown(t->sock, SHUT_RDWR);
99-
sock_release(t->sock);
100-
t->sock = NULL;
98+
struct tcp_transport *t = TCP_TRANS(kt);
10199

102-
ksmbd_conn_free(KSMBD_TRANS(t)->conn);
100+
sock_release(t->sock);
103101
kfree(t->iov);
104102
kfree(t);
105103
}
106104

105+
static void free_transport(struct tcp_transport *t)
106+
{
107+
kernel_sock_shutdown(t->sock, SHUT_RDWR);
108+
ksmbd_conn_free(KSMBD_TRANS(t)->conn);
109+
}
110+
107111
/**
108112
* kvec_array_init() - initialize a IO vector segment
109113
* @new: IO vector to be initialized

fs/smb/server/transport_tcp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
int ksmbd_tcp_set_interfaces(char *ifc_list, int ifc_list_sz);
1010
struct interface *ksmbd_find_netdev_name_iface_list(char *netdev_name);
11+
void ksmbd_free_transport(struct ksmbd_transport *kt);
1112
int ksmbd_tcp_init(void);
1213
void ksmbd_tcp_destroy(void);
1314

fs/smb/server/vfs.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,8 @@ int ksmbd_vfs_write(struct ksmbd_work *work, struct ksmbd_file *fp,
479479
int err = 0;
480480

481481
if (work->conn->connection_type) {
482-
if (!(fp->daccess & (FILE_WRITE_DATA_LE | FILE_APPEND_DATA_LE))) {
482+
if (!(fp->daccess & (FILE_WRITE_DATA_LE | FILE_APPEND_DATA_LE)) ||
483+
S_ISDIR(file_inode(fp->filp)->i_mode)) {
483484
pr_err("no right to write(%pD)\n", fp->filp);
484485
err = -EACCES;
485486
goto out;

fs/smb/server/vfs_cache.c

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -713,12 +713,8 @@ static bool tree_conn_fd_check(struct ksmbd_tree_connect *tcon,
713713

714714
static bool ksmbd_durable_scavenger_alive(void)
715715
{
716-
mutex_lock(&durable_scavenger_lock);
717-
if (!durable_scavenger_running) {
718-
mutex_unlock(&durable_scavenger_lock);
716+
if (!durable_scavenger_running)
719717
return false;
720-
}
721-
mutex_unlock(&durable_scavenger_lock);
722718

723719
if (kthread_should_stop())
724720
return false;
@@ -799,9 +795,7 @@ static int ksmbd_durable_scavenger(void *dummy)
799795
break;
800796
}
801797

802-
mutex_lock(&durable_scavenger_lock);
803798
durable_scavenger_running = false;
804-
mutex_unlock(&durable_scavenger_lock);
805799

806800
module_put(THIS_MODULE);
807801

0 commit comments

Comments
 (0)