mirror of
https://github.com/torvalds/linux.git
synced 2026-01-25 15:03:52 +08:00
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
This commit is contained in:
@@ -70,4 +70,4 @@ config SMB_SERVER_CHECK_CAP_NET_ADMIN
|
||||
config SMB_SERVER_KERBEROS5
|
||||
bool "Support for Kerberos 5"
|
||||
depends on SMB_SERVER
|
||||
default n
|
||||
default y
|
||||
|
||||
@@ -1218,7 +1218,7 @@ free_iv:
|
||||
free_sg:
|
||||
kfree(sg);
|
||||
free_req:
|
||||
kfree(req);
|
||||
aead_request_free(req);
|
||||
free_ctx:
|
||||
ksmbd_release_crypto_ctx(ctx);
|
||||
return rc;
|
||||
|
||||
@@ -230,6 +230,9 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
|
||||
if (!ksmbd_chann_del(conn, sess) &&
|
||||
xa_empty(&sess->ksmbd_chann_list)) {
|
||||
hash_del(&sess->hlist);
|
||||
down_write(&conn->session_lock);
|
||||
xa_erase(&conn->sessions, sess->id);
|
||||
up_write(&conn->session_lock);
|
||||
ksmbd_session_destroy(sess);
|
||||
}
|
||||
}
|
||||
@@ -256,6 +259,22 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
|
||||
up_write(&sessions_table_lock);
|
||||
}
|
||||
|
||||
bool is_ksmbd_session_in_connection(struct ksmbd_conn *conn,
|
||||
unsigned long long id)
|
||||
{
|
||||
struct ksmbd_session *sess;
|
||||
|
||||
down_read(&conn->session_lock);
|
||||
sess = xa_load(&conn->sessions, id);
|
||||
if (sess) {
|
||||
up_read(&conn->session_lock);
|
||||
return true;
|
||||
}
|
||||
up_read(&conn->session_lock);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
|
||||
unsigned long long id)
|
||||
{
|
||||
|
||||
@@ -87,6 +87,8 @@ void ksmbd_session_destroy(struct ksmbd_session *sess);
|
||||
struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id);
|
||||
struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
|
||||
unsigned long long id);
|
||||
bool is_ksmbd_session_in_connection(struct ksmbd_conn *conn,
|
||||
unsigned long long id);
|
||||
int ksmbd_session_register(struct ksmbd_conn *conn,
|
||||
struct ksmbd_session *sess);
|
||||
void ksmbd_sessions_deregister(struct ksmbd_conn *conn);
|
||||
|
||||
@@ -724,8 +724,8 @@ static int smb2_oplock_break_noti(struct oplock_info *opinfo)
|
||||
work->conn = conn;
|
||||
work->sess = opinfo->sess;
|
||||
|
||||
ksmbd_conn_r_count_inc(conn);
|
||||
if (opinfo->op_state == OPLOCK_ACK_WAIT) {
|
||||
ksmbd_conn_r_count_inc(conn);
|
||||
INIT_WORK(&work->work, __smb2_oplock_break_noti);
|
||||
ksmbd_queue_work(work);
|
||||
|
||||
@@ -833,8 +833,8 @@ static int smb2_lease_break_noti(struct oplock_info *opinfo)
|
||||
work->conn = conn;
|
||||
work->sess = opinfo->sess;
|
||||
|
||||
ksmbd_conn_r_count_inc(conn);
|
||||
if (opinfo->op_state == OPLOCK_ACK_WAIT) {
|
||||
ksmbd_conn_r_count_inc(conn);
|
||||
INIT_WORK(&work->work, __smb2_lease_break_noti);
|
||||
ksmbd_queue_work(work);
|
||||
wait_for_break_ack(opinfo);
|
||||
@@ -1505,6 +1505,10 @@ struct lease_ctx_info *parse_lease_state(void *open_req)
|
||||
if (sizeof(struct lease_context_v2) == le32_to_cpu(cc->DataLength)) {
|
||||
struct create_lease_v2 *lc = (struct create_lease_v2 *)cc;
|
||||
|
||||
if (le16_to_cpu(cc->DataOffset) + le32_to_cpu(cc->DataLength) <
|
||||
sizeof(struct create_lease_v2) - 4)
|
||||
return NULL;
|
||||
|
||||
memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
|
||||
lreq->req_state = lc->lcontext.LeaseState;
|
||||
lreq->flags = lc->lcontext.LeaseFlags;
|
||||
@@ -1517,6 +1521,10 @@ struct lease_ctx_info *parse_lease_state(void *open_req)
|
||||
} else {
|
||||
struct create_lease *lc = (struct create_lease *)cc;
|
||||
|
||||
if (le16_to_cpu(cc->DataOffset) + le32_to_cpu(cc->DataLength) <
|
||||
sizeof(struct create_lease))
|
||||
return NULL;
|
||||
|
||||
memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
|
||||
lreq->req_state = lc->lcontext.LeaseState;
|
||||
lreq->flags = lc->lcontext.LeaseFlags;
|
||||
|
||||
@@ -1707,44 +1707,38 @@ int smb2_sess_setup(struct ksmbd_work *work)
|
||||
|
||||
if (conn->dialect != sess->dialect) {
|
||||
rc = -EINVAL;
|
||||
ksmbd_user_session_put(sess);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (!(req->hdr.Flags & SMB2_FLAGS_SIGNED)) {
|
||||
rc = -EINVAL;
|
||||
ksmbd_user_session_put(sess);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (strncmp(conn->ClientGUID, sess->ClientGUID,
|
||||
SMB2_CLIENT_GUID_SIZE)) {
|
||||
rc = -ENOENT;
|
||||
ksmbd_user_session_put(sess);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (sess->state == SMB2_SESSION_IN_PROGRESS) {
|
||||
rc = -EACCES;
|
||||
ksmbd_user_session_put(sess);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (sess->state == SMB2_SESSION_EXPIRED) {
|
||||
rc = -EFAULT;
|
||||
ksmbd_user_session_put(sess);
|
||||
goto out_err;
|
||||
}
|
||||
ksmbd_user_session_put(sess);
|
||||
|
||||
if (ksmbd_conn_need_reconnect(conn)) {
|
||||
rc = -EFAULT;
|
||||
ksmbd_user_session_put(sess);
|
||||
sess = NULL;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
sess = ksmbd_session_lookup(conn, sess_id);
|
||||
if (!sess) {
|
||||
if (is_ksmbd_session_in_connection(conn, sess_id)) {
|
||||
rc = -EACCES;
|
||||
goto out_err;
|
||||
}
|
||||
@@ -1910,6 +1904,8 @@ out_err:
|
||||
|
||||
sess->last_active = jiffies;
|
||||
sess->state = SMB2_SESSION_EXPIRED;
|
||||
ksmbd_user_session_put(sess);
|
||||
work->sess = NULL;
|
||||
if (try_delay) {
|
||||
ksmbd_conn_set_need_reconnect(conn);
|
||||
ssleep(5);
|
||||
@@ -2708,6 +2704,13 @@ static int parse_durable_handle_context(struct ksmbd_work *work,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (le16_to_cpu(context->DataOffset) +
|
||||
le32_to_cpu(context->DataLength) <
|
||||
sizeof(struct create_durable_reconn_v2_req)) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
recon_v2 = (struct create_durable_reconn_v2_req *)context;
|
||||
persistent_id = recon_v2->Fid.PersistentFileId;
|
||||
dh_info->fp = ksmbd_lookup_durable_fd(persistent_id);
|
||||
@@ -2741,6 +2744,13 @@ static int parse_durable_handle_context(struct ksmbd_work *work,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (le16_to_cpu(context->DataOffset) +
|
||||
le32_to_cpu(context->DataLength) <
|
||||
sizeof(struct create_durable_reconn_req)) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
recon = (struct create_durable_reconn_req *)context;
|
||||
persistent_id = recon->Data.Fid.PersistentFileId;
|
||||
dh_info->fp = ksmbd_lookup_durable_fd(persistent_id);
|
||||
@@ -2766,6 +2776,13 @@ static int parse_durable_handle_context(struct ksmbd_work *work,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (le16_to_cpu(context->DataOffset) +
|
||||
le32_to_cpu(context->DataLength) <
|
||||
sizeof(struct create_durable_req_v2)) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
durable_v2_blob =
|
||||
(struct create_durable_req_v2 *)context;
|
||||
ksmbd_debug(SMB, "Request for durable v2 open\n");
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <linux/mempool.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/string_choices.h>
|
||||
#include <rdma/ib_verbs.h>
|
||||
#include <rdma/rdma_cm.h>
|
||||
#include <rdma/rw.h>
|
||||
@@ -1396,7 +1397,7 @@ static int smb_direct_rdma_xmit(struct smb_direct_transport *t,
|
||||
}
|
||||
|
||||
ksmbd_debug(RDMA, "RDMA %s, len %#x, needed credits %#x\n",
|
||||
is_read ? "read" : "write", buf_len, credits_needed);
|
||||
str_read_write(is_read), buf_len, credits_needed);
|
||||
|
||||
ret = wait_for_rw_credits(t, credits_needed);
|
||||
if (ret < 0)
|
||||
@@ -2241,38 +2242,16 @@ bool ksmbd_rdma_capable_netdev(struct net_device *netdev)
|
||||
for (i = 0; i < smb_dev->ib_dev->phys_port_cnt; i++) {
|
||||
struct net_device *ndev;
|
||||
|
||||
if (smb_dev->ib_dev->ops.get_netdev) {
|
||||
ndev = smb_dev->ib_dev->ops.get_netdev(
|
||||
smb_dev->ib_dev, i + 1);
|
||||
if (!ndev)
|
||||
continue;
|
||||
ndev = ib_device_get_netdev(smb_dev->ib_dev, i + 1);
|
||||
if (!ndev)
|
||||
continue;
|
||||
|
||||
if (ndev == netdev) {
|
||||
dev_put(ndev);
|
||||
rdma_capable = true;
|
||||
goto out;
|
||||
}
|
||||
if (ndev == netdev) {
|
||||
dev_put(ndev);
|
||||
/* if ib_dev does not implement ops.get_netdev
|
||||
* check for matching infiniband GUID in hw_addr
|
||||
*/
|
||||
} else if (netdev->type == ARPHRD_INFINIBAND) {
|
||||
struct netdev_hw_addr *ha;
|
||||
union ib_gid gid;
|
||||
u32 port_num;
|
||||
int ret;
|
||||
|
||||
netdev_hw_addr_list_for_each(
|
||||
ha, &netdev->dev_addrs) {
|
||||
memcpy(&gid, ha->addr + 4, sizeof(gid));
|
||||
ret = ib_find_gid(smb_dev->ib_dev, &gid,
|
||||
&port_num, NULL);
|
||||
if (!ret) {
|
||||
rdma_capable = true;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
rdma_capable = true;
|
||||
goto out;
|
||||
}
|
||||
dev_put(ndev);
|
||||
}
|
||||
}
|
||||
out:
|
||||
@@ -2289,7 +2268,7 @@ out:
|
||||
}
|
||||
|
||||
ksmbd_debug(RDMA, "netdev(%s) rdma capable : %s\n",
|
||||
netdev->name, rdma_capable ? "true" : "false");
|
||||
netdev->name, str_true_false(rdma_capable));
|
||||
|
||||
return rdma_capable;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user