two ksmbd server fixes
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmcPUXEACgkQiiy9cAdy T1Gm7QwAlPW5//Cb4B0gpjzRcUws51IZ4yFhp4IQWmsd0RqdjZ4TxSCOPF3u3HR3 0OPxyLdbUn6h5g0S2ayzqomHx2VBOQTjgyuMtaTWzokToMNu8kqvxK1MTslkBior 9YEHUz9+5f0OJ+JBGNUzjfy4Plygr5y09udaLfqIknuY8+SeuooxNNUNfkIvrP7C JsSAWJznN9VMpKJmszYc4ntyTiz1XVXyyjJmjhRQ27ah8LUghqZ0mamgigTS5UFa U7eYBDfs6+9i5Lvkd4bJPdGyov9g/EPViLURZMfNaz3+p0TfosN8s2UZuhHC+zuv BDQ+wHGRqzmteZspLanrGBt9y9svHXp1CD7MwqWeGR3GhKsfsxCMJpE931fBhsxM vlJdd/xCs128fv48AvNyHA9abN0U1FpskOJhOzjDgvhKqDoIQ4TCC7QFDEttsPRv ZiQmyOCPyZZY28EmfoltU4CFcMIwKQ81nPUSOJFgKmHBbSpc+Qtnv5QgRHZCzj7n StJfaIMv =WhJj -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
9f635d44d7
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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) {
|
||||
kfree(user->name);
|
||||
kfree(user->passkey);
|
||||
kfree(user);
|
||||
user = NULL;
|
||||
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);
|
||||
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);
|
||||
|
@ -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);
|
||||
|
@ -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 ||
|
||||
time_after(jiffies,
|
||||
sess->last_active + SMB2_SESSION_TIMEOUT)) {
|
||||
if (atomic_read(&sess->refcnt) == 0 &&
|
||||
(sess->state != SMB2_SESSION_VALID ||
|
||||
time_after(jiffies,
|
||||
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)
|
||||
|
@ -61,6 +61,8 @@ struct ksmbd_session {
|
||||
struct ksmbd_file_table file_table;
|
||||
unsigned long last_active;
|
||||
rwlock_t tree_conns_lock;
|
||||
|
||||
atomic_t refcnt;
|
||||
};
|
||||
|
||||
static inline int test_session_flag(struct ksmbd_session *sess, int bit)
|
||||
@ -104,4 +106,6 @@ void ksmbd_release_tree_conn_id(struct ksmbd_session *sess, int id);
|
||||
int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name);
|
||||
void ksmbd_session_rpc_close(struct ksmbd_session *sess, int id);
|
||||
int ksmbd_session_rpc_method(struct ksmbd_session *sess, int id);
|
||||
void ksmbd_user_session_get(struct ksmbd_session *sess);
|
||||
void ksmbd_user_session_put(struct ksmbd_session *sess);
|
||||
#endif /* __USER_SESSION_MANAGEMENT_H__ */
|
||||
|
@ -238,6 +238,8 @@ static void __handle_ksmbd_work(struct ksmbd_work *work,
|
||||
} while (is_chained == true);
|
||||
|
||||
send:
|
||||
if (work->sess)
|
||||
ksmbd_user_session_put(work->sess);
|
||||
if (work->tcon)
|
||||
ksmbd_tree_connect_put(work->tcon);
|
||||
smb3_preauth_hash_rsp(work);
|
||||
|
@ -605,8 +605,10 @@ int smb2_check_user_session(struct ksmbd_work *work)
|
||||
|
||||
/* Check for validity of user session */
|
||||
work->sess = ksmbd_session_lookup_all(conn, sess_id);
|
||||
if (work->sess)
|
||||
if (work->sess) {
|
||||
ksmbd_user_session_get(work->sess);
|
||||
return 1;
|
||||
}
|
||||
ksmbd_debug(SMB, "Invalid user session, Uid %llu\n", sess_id);
|
||||
return -ENOENT;
|
||||
}
|
||||
@ -1740,6 +1742,7 @@ int smb2_sess_setup(struct ksmbd_work *work)
|
||||
}
|
||||
|
||||
conn->binding = true;
|
||||
ksmbd_user_session_get(sess);
|
||||
} else if ((conn->dialect < SMB30_PROT_ID ||
|
||||
server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) &&
|
||||
(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) {
|
||||
@ -1766,6 +1769,7 @@ int smb2_sess_setup(struct ksmbd_work *work)
|
||||
}
|
||||
|
||||
conn->binding = false;
|
||||
ksmbd_user_session_get(sess);
|
||||
}
|
||||
work->sess = sess;
|
||||
|
||||
@ -2228,7 +2232,9 @@ int smb2_session_logoff(struct ksmbd_work *work)
|
||||
}
|
||||
|
||||
ksmbd_destroy_file_table(&sess->file_table);
|
||||
down_write(&conn->session_lock);
|
||||
sess->state = SMB2_SESSION_EXPIRED;
|
||||
up_write(&conn->session_lock);
|
||||
|
||||
ksmbd_free_user(sess->user);
|
||||
sess->user = NULL;
|
||||
|
@ -736,13 +736,15 @@ int __ksmbd_override_fsids(struct ksmbd_work *work,
|
||||
struct ksmbd_share_config *share)
|
||||
{
|
||||
struct ksmbd_session *sess = work->sess;
|
||||
struct ksmbd_user *user = sess->user;
|
||||
struct cred *cred;
|
||||
struct group_info *gi;
|
||||
unsigned int uid;
|
||||
unsigned int gid;
|
||||
int i;
|
||||
|
||||
uid = user_uid(sess->user);
|
||||
gid = user_gid(sess->user);
|
||||
uid = user_uid(user);
|
||||
gid = user_gid(user);
|
||||
if (share->force_uid != KSMBD_SHARE_INVALID_UID)
|
||||
uid = share->force_uid;
|
||||
if (share->force_gid != KSMBD_SHARE_INVALID_GID)
|
||||
@ -755,11 +757,18 @@ int __ksmbd_override_fsids(struct ksmbd_work *work,
|
||||
cred->fsuid = make_kuid(&init_user_ns, uid);
|
||||
cred->fsgid = make_kgid(&init_user_ns, gid);
|
||||
|
||||
gi = groups_alloc(0);
|
||||
gi = groups_alloc(user->ngroups);
|
||||
if (!gi) {
|
||||
abort_creds(cred);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (i = 0; i < user->ngroups; i++)
|
||||
gi->gid[i] = make_kgid(&init_user_ns, user->sgid[i]);
|
||||
|
||||
if (user->ngroups)
|
||||
groups_sort(gi);
|
||||
|
||||
set_groups(cred, gi);
|
||||
put_group_info(gi);
|
||||
|
||||
|
@ -120,6 +120,12 @@ static const struct nla_policy ksmbd_nl_policy[KSMBD_EVENT_MAX + 1] = {
|
||||
},
|
||||
[KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE] = {
|
||||
},
|
||||
[KSMBD_EVENT_LOGIN_REQUEST_EXT] = {
|
||||
.len = sizeof(struct ksmbd_login_request),
|
||||
},
|
||||
[KSMBD_EVENT_LOGIN_RESPONSE_EXT] = {
|
||||
.len = sizeof(struct ksmbd_login_response_ext),
|
||||
},
|
||||
};
|
||||
|
||||
static struct genl_ops ksmbd_genl_ops[] = {
|
||||
@ -187,6 +193,14 @@ static struct genl_ops ksmbd_genl_ops[] = {
|
||||
.cmd = KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE,
|
||||
.doit = handle_generic_event,
|
||||
},
|
||||
{
|
||||
.cmd = KSMBD_EVENT_LOGIN_REQUEST_EXT,
|
||||
.doit = handle_unsupported_event,
|
||||
},
|
||||
{
|
||||
.cmd = KSMBD_EVENT_LOGIN_RESPONSE_EXT,
|
||||
.doit = handle_generic_event,
|
||||
},
|
||||
};
|
||||
|
||||
static struct genl_family ksmbd_genl_family = {
|
||||
@ -198,7 +212,7 @@ static struct genl_family ksmbd_genl_family = {
|
||||
.module = THIS_MODULE,
|
||||
.ops = ksmbd_genl_ops,
|
||||
.n_ops = ARRAY_SIZE(ksmbd_genl_ops),
|
||||
.resv_start_op = KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE + 1,
|
||||
.resv_start_op = KSMBD_EVENT_LOGIN_RESPONSE_EXT + 1,
|
||||
};
|
||||
|
||||
static void ksmbd_nl_init_fixup(void)
|
||||
@ -459,16 +473,24 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry)
|
||||
{
|
||||
unsigned int msg_sz = entry->msg_sz;
|
||||
|
||||
if (entry->type == KSMBD_EVENT_RPC_REQUEST) {
|
||||
switch (entry->type) {
|
||||
case KSMBD_EVENT_RPC_REQUEST:
|
||||
{
|
||||
struct ksmbd_rpc_command *resp = entry->response;
|
||||
|
||||
msg_sz = sizeof(struct ksmbd_rpc_command) + resp->payload_sz;
|
||||
} else if (entry->type == KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST) {
|
||||
break;
|
||||
}
|
||||
case KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST:
|
||||
{
|
||||
struct ksmbd_spnego_authen_response *resp = entry->response;
|
||||
|
||||
msg_sz = sizeof(struct ksmbd_spnego_authen_response) +
|
||||
resp->session_key_len + resp->spnego_blob_len;
|
||||
} else if (entry->type == KSMBD_EVENT_SHARE_CONFIG_REQUEST) {
|
||||
break;
|
||||
}
|
||||
case KSMBD_EVENT_SHARE_CONFIG_REQUEST:
|
||||
{
|
||||
struct ksmbd_share_config_response *resp = entry->response;
|
||||
|
||||
if (resp->payload_sz) {
|
||||
@ -478,6 +500,17 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry)
|
||||
msg_sz = sizeof(struct ksmbd_share_config_response) +
|
||||
resp->payload_sz;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case KSMBD_EVENT_LOGIN_REQUEST_EXT:
|
||||
{
|
||||
struct ksmbd_login_response_ext *resp = entry->response;
|
||||
|
||||
if (resp->ngroups) {
|
||||
msg_sz = sizeof(struct ksmbd_login_response_ext) +
|
||||
resp->ngroups * sizeof(gid_t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return entry->msg_sz != msg_sz ? -EINVAL : 0;
|
||||
@ -560,6 +593,29 @@ struct ksmbd_login_response *ksmbd_ipc_login_request(const char *account)
|
||||
return resp;
|
||||
}
|
||||
|
||||
struct ksmbd_login_response_ext *ksmbd_ipc_login_request_ext(const char *account)
|
||||
{
|
||||
struct ksmbd_ipc_msg *msg;
|
||||
struct ksmbd_login_request *req;
|
||||
struct ksmbd_login_response_ext *resp;
|
||||
|
||||
if (strlen(account) >= KSMBD_REQ_MAX_ACCOUNT_NAME_SZ)
|
||||
return NULL;
|
||||
|
||||
msg = ipc_msg_alloc(sizeof(struct ksmbd_login_request));
|
||||
if (!msg)
|
||||
return NULL;
|
||||
|
||||
msg->type = KSMBD_EVENT_LOGIN_REQUEST_EXT;
|
||||
req = (struct ksmbd_login_request *)msg->payload;
|
||||
req->handle = ksmbd_acquire_id(&ipc_ida);
|
||||
strscpy(req->account, account, KSMBD_REQ_MAX_ACCOUNT_NAME_SZ);
|
||||
resp = ipc_msg_send_request(msg, req->handle);
|
||||
ipc_msg_handle_free(req->handle);
|
||||
ipc_msg_free(msg);
|
||||
return resp;
|
||||
}
|
||||
|
||||
struct ksmbd_spnego_authen_response *
|
||||
ksmbd_ipc_spnego_authen_request(const char *spnego_blob, int blob_len)
|
||||
{
|
||||
|
@ -12,6 +12,8 @@
|
||||
|
||||
struct ksmbd_login_response *
|
||||
ksmbd_ipc_login_request(const char *account);
|
||||
struct ksmbd_login_response_ext *
|
||||
ksmbd_ipc_login_request_ext(const char *account);
|
||||
|
||||
struct ksmbd_session;
|
||||
struct ksmbd_share_config;
|
||||
|
Loading…
Reference in New Issue
Block a user