mirror of
https://github.com/torvalds/linux.git
synced 2026-05-27 16:44:58 +02:00
ksmbd: fix use-after-free in ksmbd_session_rpc_open
A UAF issue can occur due to a race condition between ksmbd_session_rpc_open() and __session_rpc_close(). Add rpc_lock to the session to protect it. Cc: stable@vger.kernel.org Reported-by: Norbert Szetei <norbert@doyensec.com> Tested-by: Norbert Szetei <norbert@doyensec.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org> Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
af5226abb4
commit
a1f46c99d9
|
|
@ -59,10 +59,12 @@ static void ksmbd_session_rpc_clear_list(struct ksmbd_session *sess)
|
||||||
struct ksmbd_session_rpc *entry;
|
struct ksmbd_session_rpc *entry;
|
||||||
long index;
|
long index;
|
||||||
|
|
||||||
|
down_write(&sess->rpc_lock);
|
||||||
xa_for_each(&sess->rpc_handle_list, index, entry) {
|
xa_for_each(&sess->rpc_handle_list, index, entry) {
|
||||||
xa_erase(&sess->rpc_handle_list, index);
|
xa_erase(&sess->rpc_handle_list, index);
|
||||||
__session_rpc_close(sess, entry);
|
__session_rpc_close(sess, entry);
|
||||||
}
|
}
|
||||||
|
up_write(&sess->rpc_lock);
|
||||||
|
|
||||||
xa_destroy(&sess->rpc_handle_list);
|
xa_destroy(&sess->rpc_handle_list);
|
||||||
}
|
}
|
||||||
|
|
@ -92,7 +94,7 @@ int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name)
|
||||||
{
|
{
|
||||||
struct ksmbd_session_rpc *entry, *old;
|
struct ksmbd_session_rpc *entry, *old;
|
||||||
struct ksmbd_rpc_command *resp;
|
struct ksmbd_rpc_command *resp;
|
||||||
int method;
|
int method, id;
|
||||||
|
|
||||||
method = __rpc_method(rpc_name);
|
method = __rpc_method(rpc_name);
|
||||||
if (!method)
|
if (!method)
|
||||||
|
|
@ -102,26 +104,29 @@ int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name)
|
||||||
if (!entry)
|
if (!entry)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
down_read(&sess->rpc_lock);
|
||||||
entry->method = method;
|
entry->method = method;
|
||||||
entry->id = ksmbd_ipc_id_alloc();
|
entry->id = id = ksmbd_ipc_id_alloc();
|
||||||
if (entry->id < 0)
|
if (id < 0)
|
||||||
goto free_entry;
|
goto free_entry;
|
||||||
old = xa_store(&sess->rpc_handle_list, entry->id, entry, KSMBD_DEFAULT_GFP);
|
old = xa_store(&sess->rpc_handle_list, id, entry, KSMBD_DEFAULT_GFP);
|
||||||
if (xa_is_err(old))
|
if (xa_is_err(old))
|
||||||
goto free_id;
|
goto free_id;
|
||||||
|
|
||||||
resp = ksmbd_rpc_open(sess, entry->id);
|
resp = ksmbd_rpc_open(sess, id);
|
||||||
if (!resp)
|
if (!resp)
|
||||||
goto erase_xa;
|
goto erase_xa;
|
||||||
|
|
||||||
|
up_read(&sess->rpc_lock);
|
||||||
kvfree(resp);
|
kvfree(resp);
|
||||||
return entry->id;
|
return id;
|
||||||
erase_xa:
|
erase_xa:
|
||||||
xa_erase(&sess->rpc_handle_list, entry->id);
|
xa_erase(&sess->rpc_handle_list, entry->id);
|
||||||
free_id:
|
free_id:
|
||||||
ksmbd_rpc_id_free(entry->id);
|
ksmbd_rpc_id_free(entry->id);
|
||||||
free_entry:
|
free_entry:
|
||||||
kfree(entry);
|
kfree(entry);
|
||||||
|
up_read(&sess->rpc_lock);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -129,9 +134,11 @@ void ksmbd_session_rpc_close(struct ksmbd_session *sess, int id)
|
||||||
{
|
{
|
||||||
struct ksmbd_session_rpc *entry;
|
struct ksmbd_session_rpc *entry;
|
||||||
|
|
||||||
|
down_write(&sess->rpc_lock);
|
||||||
entry = xa_erase(&sess->rpc_handle_list, id);
|
entry = xa_erase(&sess->rpc_handle_list, id);
|
||||||
if (entry)
|
if (entry)
|
||||||
__session_rpc_close(sess, entry);
|
__session_rpc_close(sess, entry);
|
||||||
|
up_write(&sess->rpc_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ksmbd_session_rpc_method(struct ksmbd_session *sess, int id)
|
int ksmbd_session_rpc_method(struct ksmbd_session *sess, int id)
|
||||||
|
|
@ -439,6 +446,7 @@ static struct ksmbd_session *__session_create(int protocol)
|
||||||
sess->sequence_number = 1;
|
sess->sequence_number = 1;
|
||||||
rwlock_init(&sess->tree_conns_lock);
|
rwlock_init(&sess->tree_conns_lock);
|
||||||
atomic_set(&sess->refcnt, 2);
|
atomic_set(&sess->refcnt, 2);
|
||||||
|
init_rwsem(&sess->rpc_lock);
|
||||||
|
|
||||||
ret = __init_smb2_session(sess);
|
ret = __init_smb2_session(sess);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ struct ksmbd_session {
|
||||||
rwlock_t tree_conns_lock;
|
rwlock_t tree_conns_lock;
|
||||||
|
|
||||||
atomic_t refcnt;
|
atomic_t refcnt;
|
||||||
|
struct rw_semaphore rpc_lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline int test_session_flag(struct ksmbd_session *sess, int bit)
|
static inline int test_session_flag(struct ksmbd_session *sess, int bit)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user