Skip to content

Commit

Permalink
vhost: fix crash caused by accessing a freed vsocket
Browse files Browse the repository at this point in the history
When a vhost user message handling error in the event dispatch thread,
vsocket reconn is added to the reconnection list of the reconnection
thread.
Since the reconnection, event dispatching and app configuration thread
do not have common thread protection restrictions, the app config
thread freed vsocket in the rte_vhost_driver_unregister process,
but vsocket reconn can still exist in the reconn_list through this
mechanism.
Then in the reconnection thread, the vsocket is connected again and
conn is added to the dispatch thread.
Finally, the vsocket that has been freed by rte_vhost_driver_unregister
is accessed again in the event dispatch thread, resulting in a
use-after-free error.

This patch adds a vhost threads read-write lock to restrict
reconnection, event dispatching and app configuration threads.
When the vhost driver unregisters, it exclusively holds the lock to
safely free the vsocket.

#0  0x0000000000000025 in ?? ()
DPDK#1  0x0000000003ed7ca0 in vhost_user_read_cb at lib/vhost/socket.c:323
DPDK#2  0x0000000003ed625f in fdset_event_dispatch at lib/vhost/fd_man.c:365
DPDK#3 0x0000000004168336 in ctrl_thread_init at
                         lib/eal/common/eal_common_thread.c:282
DPDK#4  0x00007ffff7bc6ea5 in start_thread () from /lib64/libpthread.so.0
DPDK#5  0x00007ffff6209b0d in clone () from /lib64/libc.so.6

Fixes: e623e0c ("vhost: add vhost-user client mode")
Cc: stable@dpdk.org

Signed-off-by: Gongming Chen <chengm11@chinatelecom.cn>
Signed-off-by: 0-day Robot <robot@bytheb.org>
  • Loading branch information
Gongming Chen authored and ovsrobot committed Jul 8, 2024
1 parent 95547dc commit 62c589c
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 18 deletions.
3 changes: 3 additions & 0 deletions lib/vhost/fd_man.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <rte_thread.h>

#include "fd_man.h"
#include "vhost_thread.h"

RTE_LOG_REGISTER_SUFFIX(vhost_fdset_logtype, fdset, INFO);
#define RTE_LOGTYPE_VHOST_FDMAN vhost_fdset_logtype
Expand Down Expand Up @@ -342,6 +343,7 @@ fdset_event_dispatch(void *arg)
if (numfds < 0)
continue;

vhost_thread_read_lock();
for (i = 0; i < numfds; i++) {
pthread_mutex_lock(&pfdset->fd_mutex);

Expand Down Expand Up @@ -379,6 +381,7 @@ fdset_event_dispatch(void *arg)
if (remove1 || remove2)
fdset_del(pfdset, fd);
}
vhost_thread_read_unlock();

if (pfdset->destroy)
break;
Expand Down
1 change: 1 addition & 0 deletions lib/vhost/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ sources = files(
'vdpa.c',
'vhost.c',
'vhost_crypto.c',
'vhost_thread.c',
'vhost_user.c',
'virtio_net.c',
'virtio_net_ctrl.c',
Expand Down
30 changes: 12 additions & 18 deletions lib/vhost/socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "fd_man.h"
#include "vduse.h"
#include "vhost.h"
#include "vhost_thread.h"
#include "vhost_user.h"


Expand Down Expand Up @@ -456,6 +457,7 @@ vhost_user_client_reconnect(void *arg __rte_unused)
struct vhost_user_reconnect *reconn, *next;

while (1) {
vhost_thread_read_lock();
pthread_mutex_lock(&reconn_list.mutex);

/*
Expand Down Expand Up @@ -487,6 +489,7 @@ vhost_user_client_reconnect(void *arg __rte_unused)
}

pthread_mutex_unlock(&reconn_list.mutex);
vhost_thread_read_unlock();
sleep(1);
}

Expand Down Expand Up @@ -1067,7 +1070,7 @@ rte_vhost_driver_unregister(const char *path)
if (path == NULL)
return -1;

again:
vhost_thread_write_lock();
pthread_mutex_lock(&vhost_user.mutex);

for (i = 0; i < vhost_user.vsocket_cnt; i++) {
Expand All @@ -1079,14 +1082,10 @@ rte_vhost_driver_unregister(const char *path)
vduse_device_destroy(path);
} else if (vsocket->is_server) {
/*
* If r/wcb is executing, release vhost_user's
* mutex lock, and try again since the r/wcb
* may use the mutex lock.
* The vhost thread write lock has been acquired,
* and fd must be deleted from fdset.
*/
if (fdset_try_del(vhost_user.fdset, vsocket->socket_fd) == -1) {
pthread_mutex_unlock(&vhost_user.mutex);
goto again;
}
fdset_del(vhost_user.fdset, vsocket->socket_fd);
} else if (vsocket->reconnect) {
vhost_user_remove_reconnect(vsocket);
}
Expand All @@ -1098,17 +1097,10 @@ rte_vhost_driver_unregister(const char *path)
next = TAILQ_NEXT(conn, next);

/*
* If r/wcb is executing, release vsocket's
* conn_mutex and vhost_user's mutex locks, and
* try again since the r/wcb may use the
* conn_mutex and mutex locks.
* The vhost thread write lock has been acquired,
* and fd must be deleted from fdset.
*/
if (fdset_try_del(vhost_user.fdset,
conn->connfd) == -1) {
pthread_mutex_unlock(&vsocket->conn_mutex);
pthread_mutex_unlock(&vhost_user.mutex);
goto again;
}
fdset_del(vhost_user.fdset, conn->connfd);

VHOST_CONFIG_LOG(path, INFO, "free connfd %d", conn->connfd);
close(conn->connfd);
Expand All @@ -1130,9 +1122,11 @@ rte_vhost_driver_unregister(const char *path)
vhost_user.vsockets[i] = vhost_user.vsockets[count];
vhost_user.vsockets[count] = NULL;
pthread_mutex_unlock(&vhost_user.mutex);
vhost_thread_write_unlock();
return 0;
}
pthread_mutex_unlock(&vhost_user.mutex);
vhost_thread_write_unlock();

return -1;
}
Expand Down
29 changes: 29 additions & 0 deletions lib/vhost/vhost_thread.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include <rte_rwlock.h>

#include "vhost_thread.h"

static rte_rwlock_t vhost_thread_lock = RTE_RWLOCK_INITIALIZER;

void
vhost_thread_read_lock(void)
{
rte_rwlock_read_lock(&vhost_thread_lock);
}

void
vhost_thread_read_unlock(void)
{
rte_rwlock_read_unlock(&vhost_thread_lock);
}

void
vhost_thread_write_lock(void)
{
rte_rwlock_write_lock(&vhost_thread_lock);
}

void
vhost_thread_write_unlock(void)
{
rte_rwlock_write_unlock(&vhost_thread_lock);
}
12 changes: 12 additions & 0 deletions lib/vhost/vhost_thread.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#ifndef _VHOST_THREAD_H_
#define _VHOST_THREAD_H_

void vhost_thread_read_lock(void);

void vhost_thread_read_unlock(void);

void vhost_thread_write_lock(void);

void vhost_thread_write_unlock(void);

#endif

0 comments on commit 62c589c

Please sign in to comment.