Skip to content

Commit f64a72b

Browse files
committed
Merge tag 'v6.15rc-part1-ksmbd-server-fixes' of git://git.samba.org/ksmbd
Pull smb server updates from Steve French: - Two fixes for bounds checks of open contexts - Two multichannel fixes, including one for important UAF - Oplock/lease break fix for potential ksmbd connection refcount leak - Security fix to free crypto data more securely - Fix to enable allowing Kerberos authentication by default - Two RDMA/smbdirect fixes - Minor cleanup * tag 'v6.15rc-part1-ksmbd-server-fixes' of git://git.samba.org/ksmbd: ksmbd: fix r_count dec/increment mismatch ksmbd: fix multichannel connection failure ksmbd: fix use-after-free in ksmbd_sessions_deregister() ksmbd: use ib_device_get_netdev() instead of calling ops.get_netdev ksmbd: use aead_request_free to match aead_request_alloc Revert "ksmbd: fix missing RDMA-capable flag for IPoIB device in ksmbd_rdma_capable_netdev()" ksmbd: add bounds check for create lease context ksmbd: add bounds check for durable handle context ksmbd: make SMB_SERVER_KERBEROS5 enable by default ksmbd: Use str_read_write() and str_true_false() helpers
2 parents 8b175e2 + ddb7ea3 commit f64a72b

File tree

7 files changed

+68
-43
lines changed

7 files changed

+68
-43
lines changed

fs/smb/server/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,4 @@ config SMB_SERVER_CHECK_CAP_NET_ADMIN
7070
config SMB_SERVER_KERBEROS5
7171
bool "Support for Kerberos 5"
7272
depends on SMB_SERVER
73-
default n
73+
default y

fs/smb/server/auth.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1218,7 +1218,7 @@ int ksmbd_crypt_message(struct ksmbd_work *work, struct kvec *iov,
12181218
free_sg:
12191219
kfree(sg);
12201220
free_req:
1221-
kfree(req);
1221+
aead_request_free(req);
12221222
free_ctx:
12231223
ksmbd_release_crypto_ctx(ctx);
12241224
return rc;

fs/smb/server/mgmt/user_session.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,9 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
230230
if (!ksmbd_chann_del(conn, sess) &&
231231
xa_empty(&sess->ksmbd_chann_list)) {
232232
hash_del(&sess->hlist);
233+
down_write(&conn->session_lock);
234+
xa_erase(&conn->sessions, sess->id);
235+
up_write(&conn->session_lock);
233236
ksmbd_session_destroy(sess);
234237
}
235238
}
@@ -256,6 +259,22 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
256259
up_write(&sessions_table_lock);
257260
}
258261

262+
bool is_ksmbd_session_in_connection(struct ksmbd_conn *conn,
263+
unsigned long long id)
264+
{
265+
struct ksmbd_session *sess;
266+
267+
down_read(&conn->session_lock);
268+
sess = xa_load(&conn->sessions, id);
269+
if (sess) {
270+
up_read(&conn->session_lock);
271+
return true;
272+
}
273+
up_read(&conn->session_lock);
274+
275+
return false;
276+
}
277+
259278
struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
260279
unsigned long long id)
261280
{

fs/smb/server/mgmt/user_session.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ void ksmbd_session_destroy(struct ksmbd_session *sess);
8787
struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id);
8888
struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
8989
unsigned long long id);
90+
bool is_ksmbd_session_in_connection(struct ksmbd_conn *conn,
91+
unsigned long long id);
9092
int ksmbd_session_register(struct ksmbd_conn *conn,
9193
struct ksmbd_session *sess);
9294
void ksmbd_sessions_deregister(struct ksmbd_conn *conn);

fs/smb/server/oplock.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -724,8 +724,8 @@ static int smb2_oplock_break_noti(struct oplock_info *opinfo)
724724
work->conn = conn;
725725
work->sess = opinfo->sess;
726726

727+
ksmbd_conn_r_count_inc(conn);
727728
if (opinfo->op_state == OPLOCK_ACK_WAIT) {
728-
ksmbd_conn_r_count_inc(conn);
729729
INIT_WORK(&work->work, __smb2_oplock_break_noti);
730730
ksmbd_queue_work(work);
731731

@@ -833,8 +833,8 @@ static int smb2_lease_break_noti(struct oplock_info *opinfo)
833833
work->conn = conn;
834834
work->sess = opinfo->sess;
835835

836+
ksmbd_conn_r_count_inc(conn);
836837
if (opinfo->op_state == OPLOCK_ACK_WAIT) {
837-
ksmbd_conn_r_count_inc(conn);
838838
INIT_WORK(&work->work, __smb2_lease_break_noti);
839839
ksmbd_queue_work(work);
840840
wait_for_break_ack(opinfo);
@@ -1505,6 +1505,10 @@ struct lease_ctx_info *parse_lease_state(void *open_req)
15051505
if (sizeof(struct lease_context_v2) == le32_to_cpu(cc->DataLength)) {
15061506
struct create_lease_v2 *lc = (struct create_lease_v2 *)cc;
15071507

1508+
if (le16_to_cpu(cc->DataOffset) + le32_to_cpu(cc->DataLength) <
1509+
sizeof(struct create_lease_v2) - 4)
1510+
return NULL;
1511+
15081512
memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
15091513
lreq->req_state = lc->lcontext.LeaseState;
15101514
lreq->flags = lc->lcontext.LeaseFlags;
@@ -1517,6 +1521,10 @@ struct lease_ctx_info *parse_lease_state(void *open_req)
15171521
} else {
15181522
struct create_lease *lc = (struct create_lease *)cc;
15191523

1524+
if (le16_to_cpu(cc->DataOffset) + le32_to_cpu(cc->DataLength) <
1525+
sizeof(struct create_lease))
1526+
return NULL;
1527+
15201528
memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
15211529
lreq->req_state = lc->lcontext.LeaseState;
15221530
lreq->flags = lc->lcontext.LeaseFlags;

fs/smb/server/smb2pdu.c

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1707,44 +1707,38 @@ int smb2_sess_setup(struct ksmbd_work *work)
17071707

17081708
if (conn->dialect != sess->dialect) {
17091709
rc = -EINVAL;
1710-
ksmbd_user_session_put(sess);
17111710
goto out_err;
17121711
}
17131712

17141713
if (!(req->hdr.Flags & SMB2_FLAGS_SIGNED)) {
17151714
rc = -EINVAL;
1716-
ksmbd_user_session_put(sess);
17171715
goto out_err;
17181716
}
17191717

17201718
if (strncmp(conn->ClientGUID, sess->ClientGUID,
17211719
SMB2_CLIENT_GUID_SIZE)) {
17221720
rc = -ENOENT;
1723-
ksmbd_user_session_put(sess);
17241721
goto out_err;
17251722
}
17261723

17271724
if (sess->state == SMB2_SESSION_IN_PROGRESS) {
17281725
rc = -EACCES;
1729-
ksmbd_user_session_put(sess);
17301726
goto out_err;
17311727
}
17321728

17331729
if (sess->state == SMB2_SESSION_EXPIRED) {
17341730
rc = -EFAULT;
1735-
ksmbd_user_session_put(sess);
17361731
goto out_err;
17371732
}
1738-
ksmbd_user_session_put(sess);
17391733

17401734
if (ksmbd_conn_need_reconnect(conn)) {
17411735
rc = -EFAULT;
1736+
ksmbd_user_session_put(sess);
17421737
sess = NULL;
17431738
goto out_err;
17441739
}
17451740

1746-
sess = ksmbd_session_lookup(conn, sess_id);
1747-
if (!sess) {
1741+
if (is_ksmbd_session_in_connection(conn, sess_id)) {
17481742
rc = -EACCES;
17491743
goto out_err;
17501744
}
@@ -1910,6 +1904,8 @@ int smb2_sess_setup(struct ksmbd_work *work)
19101904

19111905
sess->last_active = jiffies;
19121906
sess->state = SMB2_SESSION_EXPIRED;
1907+
ksmbd_user_session_put(sess);
1908+
work->sess = NULL;
19131909
if (try_delay) {
19141910
ksmbd_conn_set_need_reconnect(conn);
19151911
ssleep(5);
@@ -2708,6 +2704,13 @@ static int parse_durable_handle_context(struct ksmbd_work *work,
27082704
goto out;
27092705
}
27102706

2707+
if (le16_to_cpu(context->DataOffset) +
2708+
le32_to_cpu(context->DataLength) <
2709+
sizeof(struct create_durable_reconn_v2_req)) {
2710+
err = -EINVAL;
2711+
goto out;
2712+
}
2713+
27112714
recon_v2 = (struct create_durable_reconn_v2_req *)context;
27122715
persistent_id = recon_v2->Fid.PersistentFileId;
27132716
dh_info->fp = ksmbd_lookup_durable_fd(persistent_id);
@@ -2741,6 +2744,13 @@ static int parse_durable_handle_context(struct ksmbd_work *work,
27412744
goto out;
27422745
}
27432746

2747+
if (le16_to_cpu(context->DataOffset) +
2748+
le32_to_cpu(context->DataLength) <
2749+
sizeof(struct create_durable_reconn_req)) {
2750+
err = -EINVAL;
2751+
goto out;
2752+
}
2753+
27442754
recon = (struct create_durable_reconn_req *)context;
27452755
persistent_id = recon->Data.Fid.PersistentFileId;
27462756
dh_info->fp = ksmbd_lookup_durable_fd(persistent_id);
@@ -2766,6 +2776,13 @@ static int parse_durable_handle_context(struct ksmbd_work *work,
27662776
goto out;
27672777
}
27682778

2779+
if (le16_to_cpu(context->DataOffset) +
2780+
le32_to_cpu(context->DataLength) <
2781+
sizeof(struct create_durable_req_v2)) {
2782+
err = -EINVAL;
2783+
goto out;
2784+
}
2785+
27692786
durable_v2_blob =
27702787
(struct create_durable_req_v2 *)context;
27712788
ksmbd_debug(SMB, "Request for durable v2 open\n");

fs/smb/server/transport_rdma.c

Lines changed: 10 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/mempool.h>
1515
#include <linux/highmem.h>
1616
#include <linux/scatterlist.h>
17+
#include <linux/string_choices.h>
1718
#include <rdma/ib_verbs.h>
1819
#include <rdma/rdma_cm.h>
1920
#include <rdma/rw.h>
@@ -1396,7 +1397,7 @@ static int smb_direct_rdma_xmit(struct smb_direct_transport *t,
13961397
}
13971398

13981399
ksmbd_debug(RDMA, "RDMA %s, len %#x, needed credits %#x\n",
1399-
is_read ? "read" : "write", buf_len, credits_needed);
1400+
str_read_write(is_read), buf_len, credits_needed);
14001401

14011402
ret = wait_for_rw_credits(t, credits_needed);
14021403
if (ret < 0)
@@ -2241,38 +2242,16 @@ bool ksmbd_rdma_capable_netdev(struct net_device *netdev)
22412242
for (i = 0; i < smb_dev->ib_dev->phys_port_cnt; i++) {
22422243
struct net_device *ndev;
22432244

2244-
if (smb_dev->ib_dev->ops.get_netdev) {
2245-
ndev = smb_dev->ib_dev->ops.get_netdev(
2246-
smb_dev->ib_dev, i + 1);
2247-
if (!ndev)
2248-
continue;
2245+
ndev = ib_device_get_netdev(smb_dev->ib_dev, i + 1);
2246+
if (!ndev)
2247+
continue;
22492248

2250-
if (ndev == netdev) {
2251-
dev_put(ndev);
2252-
rdma_capable = true;
2253-
goto out;
2254-
}
2249+
if (ndev == netdev) {
22552250
dev_put(ndev);
2256-
/* if ib_dev does not implement ops.get_netdev
2257-
* check for matching infiniband GUID in hw_addr
2258-
*/
2259-
} else if (netdev->type == ARPHRD_INFINIBAND) {
2260-
struct netdev_hw_addr *ha;
2261-
union ib_gid gid;
2262-
u32 port_num;
2263-
int ret;
2264-
2265-
netdev_hw_addr_list_for_each(
2266-
ha, &netdev->dev_addrs) {
2267-
memcpy(&gid, ha->addr + 4, sizeof(gid));
2268-
ret = ib_find_gid(smb_dev->ib_dev, &gid,
2269-
&port_num, NULL);
2270-
if (!ret) {
2271-
rdma_capable = true;
2272-
goto out;
2273-
}
2274-
}
2251+
rdma_capable = true;
2252+
goto out;
22752253
}
2254+
dev_put(ndev);
22762255
}
22772256
}
22782257
out:
@@ -2289,7 +2268,7 @@ bool ksmbd_rdma_capable_netdev(struct net_device *netdev)
22892268
}
22902269

22912270
ksmbd_debug(RDMA, "netdev(%s) rdma capable : %s\n",
2292-
netdev->name, rdma_capable ? "true" : "false");
2271+
netdev->name, str_true_false(rdma_capable));
22932272

22942273
return rdma_capable;
22952274
}

0 commit comments

Comments
 (0)