Commit 9f635d44 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'v6.12-rc3-ksmbd-fixes' of git://git.samba.org/ksmbd

Pull smb server fixes from Steve French:

 - fix race between session setup and session logoff

 - add supplementary group support

* tag 'v6.12-rc3-ksmbd-fixes' of git://git.samba.org/ksmbd:
  ksmbd: add support for supplementary groups
  ksmbd: fix user-after-free from session log off
parents 6f6fc393 a77e0e02
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -512,6 +512,7 @@ int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob,
			    int in_len, char *out_blob, int *out_len)
{
	struct ksmbd_spnego_authen_response *resp;
	struct ksmbd_login_response_ext *resp_ext = NULL;
	struct ksmbd_user *user = NULL;
	int retval;

@@ -540,7 +541,10 @@ int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob,
		goto out;
	}

	user = ksmbd_alloc_user(&resp->login_response);
	if (resp->login_response.status & KSMBD_USER_FLAG_EXTENSION)
		resp_ext = ksmbd_ipc_login_request_ext(resp->login_response.account);

	user = ksmbd_alloc_user(&resp->login_response, resp_ext);
	if (!user) {
		ksmbd_debug(AUTH, "login failure\n");
		retval = -ENOMEM;
+17 −0
Original line number Diff line number Diff line
@@ -51,6 +51,9 @@
 *  - KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST/RESPONSE(ksmbd_spnego_authen_request/response)
 *    This event is to make kerberos authentication to be processed in
 *    userspace.
 *
 *  - KSMBD_EVENT_LOGIN_REQUEST_EXT/RESPONSE_EXT(ksmbd_login_request_ext/response_ext)
 *    This event is to get user account extension info to user IPC daemon.
 */

#define KSMBD_GENL_NAME		"SMBD_GENL"
@@ -145,6 +148,16 @@ struct ksmbd_login_response {
	__u32	reserved[16];			/* Reserved room */
};

/*
 * IPC user login response extension.
 */
struct ksmbd_login_response_ext {
	__u32	handle;
	__s32	ngroups;			/* supplementary group count */
	__s8	reserved[128];			/* Reserved room */
	__s8	____payload[];
};

/*
 * IPC request to fetch net share config.
 */
@@ -306,6 +319,9 @@ enum ksmbd_event {
	KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST,
	KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE	= 15,

	KSMBD_EVENT_LOGIN_REQUEST_EXT,
	KSMBD_EVENT_LOGIN_RESPONSE_EXT,

	__KSMBD_EVENT_MAX,
	KSMBD_EVENT_MAX = __KSMBD_EVENT_MAX - 1
};
@@ -336,6 +352,7 @@ enum KSMBD_TREE_CONN_STATUS {
#define KSMBD_USER_FLAG_BAD_USER	BIT(3)
#define KSMBD_USER_FLAG_GUEST_ACCOUNT	BIT(4)
#define KSMBD_USER_FLAG_DELAY_SESSION	BIT(5)
#define KSMBD_USER_FLAG_EXTENSION	BIT(6)

/*
 * Share config flags.
+37 −8
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
struct ksmbd_user *ksmbd_login_user(const char *account)
{
	struct ksmbd_login_response *resp;
	struct ksmbd_login_response_ext *resp_ext = NULL;
	struct ksmbd_user *user = NULL;

	resp = ksmbd_ipc_login_request(account);
@@ -21,15 +22,19 @@ struct ksmbd_user *ksmbd_login_user(const char *account)
	if (!(resp->status & KSMBD_USER_FLAG_OK))
		goto out;

	user = ksmbd_alloc_user(resp);
	if (resp->status & KSMBD_USER_FLAG_EXTENSION)
		resp_ext = ksmbd_ipc_login_request_ext(account);

	user = ksmbd_alloc_user(resp, resp_ext);
out:
	kvfree(resp);
	return user;
}

struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp)
struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp,
		struct ksmbd_login_response_ext *resp_ext)
{
	struct ksmbd_user *user = NULL;
	struct ksmbd_user *user;

	user = kmalloc(sizeof(struct ksmbd_user), GFP_KERNEL);
	if (!user)
@@ -44,18 +49,42 @@ struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp)
	if (user->passkey)
		memcpy(user->passkey, resp->hash, resp->hash_sz);

	if (!user->name || !user->passkey) {
	user->ngroups = 0;
	user->sgid = NULL;

	if (!user->name || !user->passkey)
		goto err_free;

	if (resp_ext) {
		if (resp_ext->ngroups > NGROUPS_MAX) {
			pr_err("ngroups(%u) from login response exceeds max groups(%d)\n",
					resp_ext->ngroups, NGROUPS_MAX);
			goto err_free;
		}

		user->sgid = kmemdup(resp_ext->____payload,
				     resp_ext->ngroups * sizeof(gid_t),
				     GFP_KERNEL);
		if (!user->sgid)
			goto err_free;

		user->ngroups = resp_ext->ngroups;
		ksmbd_debug(SMB, "supplementary groups : %d\n", user->ngroups);
	}

	return user;

err_free:
	kfree(user->name);
	kfree(user->passkey);
	kfree(user);
		user = NULL;
	}
	return user;
	return NULL;
}

void ksmbd_free_user(struct ksmbd_user *user)
{
	ksmbd_ipc_logout_request(user->name, user->flags);
	kfree(user->sgid);
	kfree(user->name);
	kfree(user->passkey);
	kfree(user);
+4 −1
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ struct ksmbd_user {

	size_t			passkey_sz;
	char			*passkey;
	int			ngroups;
	gid_t			*sgid;
};

static inline bool user_guest(struct ksmbd_user *user)
@@ -60,7 +62,8 @@ static inline unsigned int user_gid(struct ksmbd_user *user)
}

struct ksmbd_user *ksmbd_login_user(const char *account);
struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp);
struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp,
		struct ksmbd_login_response_ext *resp_ext);
void ksmbd_free_user(struct ksmbd_user *user);
int ksmbd_anonymous_user(struct ksmbd_user *user);
bool ksmbd_compare_user(struct ksmbd_user *u1, struct ksmbd_user *u2);
+21 −5
Original line number Diff line number Diff line
@@ -177,9 +177,10 @@ static void ksmbd_expire_session(struct ksmbd_conn *conn)

	down_write(&conn->session_lock);
	xa_for_each(&conn->sessions, id, sess) {
		if (sess->state != SMB2_SESSION_VALID ||
		if (atomic_read(&sess->refcnt) == 0 &&
		    (sess->state != SMB2_SESSION_VALID ||
		     time_after(jiffies,
			       sess->last_active + SMB2_SESSION_TIMEOUT)) {
			       sess->last_active + SMB2_SESSION_TIMEOUT))) {
			xa_erase(&conn->sessions, sess->id);
			hash_del(&sess->hlist);
			ksmbd_session_destroy(sess);
@@ -269,8 +270,6 @@ struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id)

	down_read(&sessions_table_lock);
	sess = __session_lookup(id);
	if (sess)
		sess->last_active = jiffies;
	up_read(&sessions_table_lock);

	return sess;
@@ -289,6 +288,22 @@ struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,
	return sess;
}

void ksmbd_user_session_get(struct ksmbd_session *sess)
{
	atomic_inc(&sess->refcnt);
}

void ksmbd_user_session_put(struct ksmbd_session *sess)
{
	if (!sess)
		return;

	if (atomic_read(&sess->refcnt) <= 0)
		WARN_ON(1);
	else
		atomic_dec(&sess->refcnt);
}

struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn,
						    u64 sess_id)
{
@@ -393,6 +408,7 @@ static struct ksmbd_session *__session_create(int protocol)
	xa_init(&sess->rpc_handle_list);
	sess->sequence_number = 1;
	rwlock_init(&sess->tree_conns_lock);
	atomic_set(&sess->refcnt, 1);

	ret = __init_smb2_session(sess);
	if (ret)
Loading