Commit b3fee71e authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'v6.18rc1-part1-ksmbd-server-fixes' of git://git.samba.org/ksmbd

Pull smb server fixes from Steve French:

 - Fix potential UAFs and corruptions in rpc open and close

 - Fix copy_file_range when ranges overlap

 - Improve session, share, connection lookup performance

 - Fix potential hash collisions in share and session lists

 - Debugging improvement - making per-connection threads easier to
   identify

 - Improve socket creation

 - Fix return code mapping for posix query fs info

 - Add support for limiting the maximum number of connections per IP
   address, extending the existing connection limiting mechanism to
   enforce per-IP connection limits alongside the global connection
   limit

* tag 'v6.18rc1-part1-ksmbd-server-fixes' of git://git.samba.org/ksmbd:
  ksmbd: increase session and share hash table bits
  ksmbd: replace connection list with hash table
  ksmbd: add an error print when maximum IP connections limit is reached
  ksmbd: add max ip connections parameter
  ksmbd: fix error code overwriting in smb2_get_info_filesystem()
  ksmbd: copy overlapped range within the same file
  ksmbd: use sock_create_kern interface to create kernel socket
  ksmbd: make ksmbd thread names distinct by client IP
  ksmbd: Fix race condition in RPC handle list access
parents 86d563ac e28c5bc4
Loading
Loading
Loading
Loading
+11 −12
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@ static DEFINE_MUTEX(init_lock);

static struct ksmbd_conn_ops default_conn_ops;

LIST_HEAD(conn_list);
DEFINE_HASHTABLE(conn_list, CONN_HASH_BITS);
DECLARE_RWSEM(conn_list_lock);

/**
@@ -33,7 +33,7 @@ DECLARE_RWSEM(conn_list_lock);
void ksmbd_conn_free(struct ksmbd_conn *conn)
{
	down_write(&conn_list_lock);
	list_del(&conn->conns_list);
	hash_del(&conn->hlist);
	up_write(&conn_list_lock);

	xa_destroy(&conn->sessions);
@@ -77,7 +77,6 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)

	init_waitqueue_head(&conn->req_running_q);
	init_waitqueue_head(&conn->r_count_q);
	INIT_LIST_HEAD(&conn->conns_list);
	INIT_LIST_HEAD(&conn->requests);
	INIT_LIST_HEAD(&conn->async_requests);
	spin_lock_init(&conn->request_lock);
@@ -90,19 +89,17 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)

	init_rwsem(&conn->session_lock);

	down_write(&conn_list_lock);
	list_add(&conn->conns_list, &conn_list);
	up_write(&conn_list_lock);
	return conn;
}

bool ksmbd_conn_lookup_dialect(struct ksmbd_conn *c)
{
	struct ksmbd_conn *t;
	int bkt;
	bool ret = false;

	down_read(&conn_list_lock);
	list_for_each_entry(t, &conn_list, conns_list) {
	hash_for_each(conn_list, bkt, t, hlist) {
		if (memcmp(t->ClientGUID, c->ClientGUID, SMB2_CLIENT_GUID_SIZE))
			continue;

@@ -163,9 +160,10 @@ void ksmbd_conn_unlock(struct ksmbd_conn *conn)
void ksmbd_all_conn_set_status(u64 sess_id, u32 status)
{
	struct ksmbd_conn *conn;
	int bkt;

	down_read(&conn_list_lock);
	list_for_each_entry(conn, &conn_list, conns_list) {
	hash_for_each(conn_list, bkt, conn, hlist) {
		if (conn->binding || xa_load(&conn->sessions, sess_id))
			WRITE_ONCE(conn->status, status);
	}
@@ -181,14 +179,14 @@ int ksmbd_conn_wait_idle_sess_id(struct ksmbd_conn *curr_conn, u64 sess_id)
{
	struct ksmbd_conn *conn;
	int rc, retry_count = 0, max_timeout = 120;
	int rcount = 1;
	int rcount = 1, bkt;

retry_idle:
	if (retry_count >= max_timeout)
		return -EIO;

	down_read(&conn_list_lock);
	list_for_each_entry(conn, &conn_list, conns_list) {
	hash_for_each(conn_list, bkt, conn, hlist) {
		if (conn->binding || xa_load(&conn->sessions, sess_id)) {
			if (conn == curr_conn)
				rcount = 2;
@@ -480,10 +478,11 @@ static void stop_sessions(void)
{
	struct ksmbd_conn *conn;
	struct ksmbd_transport *t;
	int bkt;

again:
	down_read(&conn_list_lock);
	list_for_each_entry(conn, &conn_list, conns_list) {
	hash_for_each(conn_list, bkt, conn, hlist) {
		t = conn->transport;
		ksmbd_conn_set_exiting(conn);
		if (t->ops->shutdown) {
@@ -494,7 +493,7 @@ static void stop_sessions(void)
	}
	up_read(&conn_list_lock);

	if (!list_empty(&conn_list)) {
	if (!hash_empty(conn_list)) {
		msleep(100);
		goto again;
	}
+4 −2
Original line number Diff line number Diff line
@@ -54,11 +54,12 @@ struct ksmbd_conn {
		u8			inet6_addr[16];
#endif
	};
	unsigned int			inet_hash;
	char				*request_buf;
	struct ksmbd_transport		*transport;
	struct nls_table		*local_nls;
	struct unicode_map		*um;
	struct list_head		conns_list;
	struct hlist_node		hlist;
	struct rw_semaphore		session_lock;
	/* smb session 1 per user */
	struct xarray			sessions;
@@ -153,7 +154,8 @@ struct ksmbd_transport {
#define KSMBD_TCP_SEND_TIMEOUT	(5 * HZ)
#define KSMBD_TCP_PEER_SOCKADDR(c)	((struct sockaddr *)&((c)->peer_addr))

extern struct list_head conn_list;
#define CONN_HASH_BITS	12
extern DECLARE_HASHTABLE(conn_list, CONN_HASH_BITS);
extern struct rw_semaphore conn_list_lock;

bool ksmbd_conn_alive(struct ksmbd_conn *conn);
+3 −2
Original line number Diff line number Diff line
@@ -112,10 +112,11 @@ struct ksmbd_startup_request {
	__u32	smbd_max_io_size;	/* smbd read write size */
	__u32	max_connections;	/* Number of maximum simultaneous connections */
	__s8	bind_interfaces_only;
	__s8	reserved[503];		/* Reserved room */
	__u32	max_ip_connections;	/* Number of maximum connection per ip address */
	__s8	reserved[499];		/* Reserved room */
	__u32	ifc_list_sz;		/* interfaces list size */
	__s8	____payload[];
};
} __packed;

#define KSMBD_STARTUP_CONFIG_INTERFACES(s)	((s)->____payload)

+1 −1
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@
#include "../transport_ipc.h"
#include "../misc.h"

#define SHARE_HASH_BITS		3
#define SHARE_HASH_BITS		12
static DEFINE_HASHTABLE(shares_table, SHARE_HASH_BITS);
static DECLARE_RWSEM(shares_table_lock);

+18 −10
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@

static DEFINE_IDA(session_ida);

#define SESSION_HASH_BITS		3
#define SESSION_HASH_BITS		12
static DEFINE_HASHTABLE(sessions_table, SESSION_HASH_BITS);
static DECLARE_RWSEM(sessions_table_lock);

@@ -104,29 +104,32 @@ int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name)
	if (!entry)
		return -ENOMEM;

	down_read(&sess->rpc_lock);
	entry->method = method;
	entry->id = id = ksmbd_ipc_id_alloc();
	if (id < 0)
		goto free_entry;

	down_write(&sess->rpc_lock);
	old = xa_store(&sess->rpc_handle_list, id, entry, KSMBD_DEFAULT_GFP);
	if (xa_is_err(old))
	if (xa_is_err(old)) {
		up_write(&sess->rpc_lock);
		goto free_id;
	}

	resp = ksmbd_rpc_open(sess, id);
	if (!resp)
		goto erase_xa;
	if (!resp) {
		xa_erase(&sess->rpc_handle_list, entry->id);
		up_write(&sess->rpc_lock);
		goto free_id;
	}

	up_read(&sess->rpc_lock);
	up_write(&sess->rpc_lock);
	kvfree(resp);
	return id;
erase_xa:
	xa_erase(&sess->rpc_handle_list, entry->id);
free_id:
	ksmbd_rpc_id_free(entry->id);
free_entry:
	kfree(entry);
	up_read(&sess->rpc_lock);
	return -EINVAL;
}

@@ -144,9 +147,14 @@ void ksmbd_session_rpc_close(struct ksmbd_session *sess, int id)
int ksmbd_session_rpc_method(struct ksmbd_session *sess, int id)
{
	struct ksmbd_session_rpc *entry;
	int method;

	down_read(&sess->rpc_lock);
	entry = xa_load(&sess->rpc_handle_list, id);
	return entry ? entry->method : 0;
	method = entry ? entry->method : 0;
	up_read(&sess->rpc_lock);

	return method;
}

void ksmbd_session_destroy(struct ksmbd_session *sess)
Loading