Don’t play with fire, as well as race condition

This is my first blog in 2021. I wish all of you have a wonderful new year.

Background

At Black hat USA 2019, we introduced a socket Use-After-Free (UAF) vulnerability caused by bad locking in the UNIX socket bind function on iOS. Briefly speaking, the function unp_bind temporarily unlocks the socket while binding the socket to a vnode, leading to a race condition. As a result, we can bind one socket to two vnodes. When the socket is closed and freed, one of the two vnodes still keeps a dangling pointer pointing to the freed socket object. By manipulating the vnodes again, we can trigger the socket UAF in the kernel. For more details, please refer to 1.

bind and connect are two basic interfaces for a socket, and have the same parameters.

int
     connect(int socket, const struct sockaddr *address, socklen_t address_len);`
int
     bind(int socket, const struct sockaddr *address, socklen_t address_len);

If the bind function is buggy, how about the connect function?

Socket Programming 101

A UNIX domain socket can be either connection-oriented (type SOCK_STREAM) or connectionless (type SOCK_DGRAM). In the case of connection-oriented scenario, we can setup a server socket, bind it to a local file address, and then listen and accept new connections. Here, bind() assigns a unique name to an unnamed socket.

According to the local file name, we can connect a client socket to the server socket. If it succeeds, a new socket is inserted into the server socket’s connection queue. The server can then call accept() to extract the first connection request on the queue of pending connections, create a new socket with the same properties of socket, and allocate a new file descriptor for the new socket.

The Vulnerability

A client socket is not supposed to connect to different servers at the same time. However, let’s take a look at the function unp_connect. I copied and pasted the source code of unp_connect as follows.

static int
unp_connect(struct socket *so, struct sockaddr *nam, __unused proc_t p)
{
	...
	socket_unlock(so, 0);  <<--- a. temporary unlock so

	NDINIT(&nd, LOOKUP, OP_LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE,
	    CAST_USER_ADDR_T(buf), ctx);
	error = namei(&nd); 	<<--- b. lookup the address
	if (error) {
		socket_lock(so, 0);
		return error;
	}
	nameidone(&nd);
	vp = nd.ni_vp;				
	if (vp->v_type != VSOCK) {
		error = ENOTSOCK;
		socket_lock(so, 0);
		goto out;
	}
	...
	socket_lock(vp->v_socket, 1); /* Get a reference on the listening socket */
	so2 = vp->v_socket;
	...
	if (so < so2) {
		socket_unlock(so2, 0);
		socket_lock(so, 0);  <<--- c. relock the sockets
		socket_lock(so2, 0);
	} else if (so > so2) {
		socket_lock(so, 0);
	}
	/*
	 * Check if socket was connected while we were trying to
	 * get the socket locks in order.
	 * XXX - probably shouldn't return an error for SOCK_DGRAM
	 */
	if ((so->so_state & SS_ISCONNECTED) != 0) {
		error = EISCONN;
		goto decref_out;
	}

	...
		socket_unlock(so, 0); <<--- d. temporary unlock so 

		if ((so2->so_options & SO_ACCEPTCONN) == 0 ||
		    (so3 = sonewconn(so2, 0, nam)) == 0) {   <<---  e. make a new connection
			error = ECONNREFUSED;
			if (so != so2) {
				socket_unlock(so2, 1);
				socket_lock(so, 0);
			} else {
				socket_lock(so, 0);
				/* Release the reference held for
				 * listen socket.
				 */
				VERIFY(so2->so_usecount > 0);
				so2->so_usecount--;
			}
			goto out;
		}
		...
			if (so < so2) {
			socket_unlock(so2, 0);
			socket_lock(so, 0); <<--- f. relock
			socket_lock(so2, 0);
		} else {
			socket_lock(so, 0);
		}

		/* Check again if the socket state changed when its lock was released */
		if ((so->so_state & SS_ISCONNECTED) != 0) {
			error = EISCONN;
			socket_unlock(so2, 1);
			socket_lock(so3, 0);
			sofreelastref(so3, 1);  <<-- g. free the new conn
			goto out;
		}
...

	error = unp_connect2(so, so2);
	...
}

Sorry for the long code snippet. At the first glance, you may have noticed that unp_connect performs socket locks and unlocks for multiple times. This is a strong indicator for a race condition. However, if you read the comments in the function, you will find that the developers have realized the potential race conditions. Every time the socket is re-locked, unp_connect performs checks on any change of the socket state. For example, after the lock at (c), we can find the following comments:

	 * Check if socket was connected while we were trying to
	 * get the socket locks in order.
	 * XXX - probably shouldn't return an error for SOCK_DGRAM

Another example: after the lock at (f), we can find the comments:

/* Check again if the socket state changed when its lock was released */

Playing with race condition is dangerous. In the case of unp_connect, the vulnerability occurs after a race condition is detected. Since I don’t want to write a long blog in holiday, let’s go to the vulnerability directly.

		if ((so2->so_options & SO_ACCEPTCONN) == 0 ||
		    (so3 = sonewconn(so2, 0, nam)) == 0) {   <<---  e. make a new connection
		...
		/* Check again if the socket state changed when its lock was released */
		if ((so->so_state & SS_ISCONNECTED) != 0) {
			error = EISCONN;
			socket_unlock(so2, 1);
			socket_lock(so3, 0);
			sofreelastref(so3, 1);  <<-- g. free the new conn

For the code above, so3 is a newly created socket from the server socket through the function sonewconn. unp_connect temporarily unlocks the client socket while performing sonewconn, and relocks the client socket. If the client socket’s state is changed to SS_ISCONNECTED, which implies that the client socket is connected to somewhere else during the temporary unlock, unp_connect just returns EISCONN and frees so3.

Let’s focus on the following two lines:

			socket_lock(so3, 0);
			sofreelastref(so3, 1);

Clearly, so3 is locked through the function socket_lock, and passed into function sofreelastref. Would sofreelastref really and directly free so3? No!

void
sofreelastref(struct socket *so, int dealloc)
{
	struct socket *head = so->so_head;

	/* Assume socket is locked */

	if (!(so->so_flags & SOF_PCBCLEARING) || !(so->so_state & SS_NOFDREF)) {
		selthreadclear(&so->so_snd.sb_sel);
		selthreadclear(&so->so_rcv.sb_sel);
		so->so_rcv.sb_flags &= ~(SB_SEL | SB_UPCALL);
		so->so_snd.sb_flags &= ~(SB_SEL | SB_UPCALL);
		so->so_event = sonullevent;
		return;
	}
	...

If a socket’s so_flags has no SOF_PCBCLEARING or SS_NOFDREF set, sofreelastref does not deallocate the socket. For a newly created socket so3, does it have SOF_PCBCLEARING or SS_NOFDREF set? Still, no!

Now what we have is that, so3 is locked, but not freed. The question is where so3 is? In fact, so3 is inserted into the server socket so_incomp list. Let’s go back to the function sonewconn.

/*
 * When an attempt at a new connection is noted on a socket
 * which accepts connections, sonewconn is called.  If the
 * connection is possible (subject to space constraints, etc.)
 * then we allocate a new structure, propoerly linked into the
 * data structure of the original socket, and return this.
 * Connstatus may be 0, or SO_ISCONFIRMING, or SO_ISCONNECTED.
 */
static struct socket *
sonewconn_internal(struct socket *head, int connstatus)
{
...
  so = soalloc(1, SOCK_DOM(head), head->so_type);
	if (so == NULL) {
		return (struct socket *)0;
	}
...
	/* Insert in head appropriate lists */
	so_acquire_accept_list(head, NULL);

	so->so_head = head;

...
	so->so_flags |= SOF_INCOMP_INPROGRESS;
...
		TAILQ_INSERT_TAIL(&head->so_incomp, so, so_list);
		so->so_state |= SS_INCOMP;
		head->so_incqlen++;
...
	so_release_accept_list(head);
...

It’s clear now: so3 is on the server socket’s so_incomp list. When the server socket is closed, it is responsible to clean up the so_incomp list. The following code shows the function soclose_locked.

int
soclose_locked(struct socket *so)
{
...
		TAILQ_FOREACH_SAFE(sp, &so->so_incomp, so_list, sonext) {
			...
			if (persocklock != 0) {
				socket_lock(sp, 1);
			}
...

Have you pinpointed the issue? As we checked, so3 is locked and inserted into to so_incomp list. However, when the function soclose_locked processes the so_incomp list, it would lock sp again. Actually, sp is our locked so3!

So far it sounds like a lock issue. Yes, the race condition in unp_connect now turns into a double lock issue. A socket object is passed into socket_lock twice. Does it cause any memory safety problem?

The Lock

The implementation of locks on iOS is very complicated, as least to me. The readers could check XNU source code for more details. In our case, socket_lock calls unp_lock, and eventually calls lck_mtx_lock and calls lck_mtx_lock_contended.

unp_lock(struct socket *so, int refcount, void * lr)
{
...
	if (so->so_pcb) {
		lck_mtx_lock(&((struct unpcb *)so->so_pcb)->unp_mtx);
...	

void
lck_mtx_lock(lck_mtx_t *lock)
{
	thread_t        thread;
...
	thread = current_thread();
...
	lck_mtx_lock_contended(lock, thread, FALSE);
}

If a lock is unlocked, lck_mtx_lock_contendedwill directly acquire the lock and set the ownership. The ownership is the current thread pointer. Otherwise, if the lock is locked, lck_mtx_lock_contended would try to loop waiting until the lock is released. During this process, lck_mtx_lock_contended will use the owner thread pointer for many reasons.

How to trigger thread_t UAF

Now we try to turn the double-lock issue into a thread_t UAF. The idea is as follows.

Now we try to turn the double-lock issue into a thread_t UAF. The idea is as follows.

We create two threads that try to connect the same client socket to two different server sockets. If unp_connect catches the race condition, it may create a new so3, insert it to the corresponding server socket’s so_incomp list, and then lock so3 that stores the thread_t pointer of the corresponding thread.

And then, we terminate the two threads, as a result, the two thread_t objects are deallocated in the kernel. However, the so3 still keeps a dangling thread_t pointer in its lock object.

Now we close all the server sockets, which will trigger the cleanup of the so_incomp list of the server sockets. As a result, the kernel will run socket_lock(so3) again. Accessing to the owner thread of so3’s lock will trigger the thread_t UAF problem.

For a complete POC, please check 2.

Conclusion

We shared a thread_t UAF problem in the XNU kernel. We analyzed how a failed race condition turns into a double-lock issue, and then turns into a UAF issue. Hope you enjoy the blog. Thank you for reading.

0 Responses to “Don’t play with fire, as well as race condition”

  1. Your comment is awaiting moderation. This is a preview, your comment will be visible after it has been approved.

    Prestamo Personal 2000 Euros Necesito Plata Prestada Consulta De Credito Personal
    https://prestamosenestadosunidos.space/cherry-hill-nj/
    Te Presto Dinero Microprestamos Dinero Facil Y Rapido Financieras Prestamos Rapidos Financieras Prestamos Personales
    https://prestamosenestadosunidos.space/fullerton-ca/
    Prestamos De Dinero Por Internet Credito A Clientes Necesito Dinero Creditos Rapidos Donde Puedo Pedir Un Prestamo
    https://prestamosenestadosunidos.space/winchester-nv/
    Simulador Cuota Prestamo Personal Minicreditos Rapidos Online Prestamos Rapidos Para Pagar A Plazos

  2. Los Creditos says:
    Your comment is awaiting moderation. This is a preview, your comment will be visible after it has been approved.

    Donde Consigo Un Prestamo Rapido Y Facil Linea Credito Calcular Cuota Prestamo Solicitud De Credito Online
    https://elprestamista.space/pflugerville-tx/
    Prestamos Prestamos A Largo Plazo Al Credito Creditos Rapidos Por Telefono Donde Prestan Dinero Urgente
    https://elprestamista.space/riverside-ca/
    Prestamo Privado Web Credito Tipos De Interes Para Prestamos Personales Requisitos Para Solicitar Un Prestamo Personal Prestamos Por Internet Rapidos
    https://elprestamista.space/plano-tx/
    Creditos A Plazos Credito De Consumo Sacar Prestamo Personal

  3. Your comment is awaiting moderation. This is a preview, your comment will be visible after it has been approved.

    Hacer Un Prestamo Personal Simulador Prestamo Consumo Micro Prestamos Online Calcular Cuota Prestamo Prestamo Capital Privado
    https://prestamosenestadosunidos.space/fresno-ca/
    Mini Prestamos Online Nuevos Sacar Prestamo Prestamos Baratos
    https://prestamosenestadosunidos.space/sayreville-nj/
    Donde Sacar Prestamos Personales Donde Prestan Dinero Facil Simulador Prestamos Tasa De Prestamos Personales
    https://prestamosenestadosunidos.space/reno-nv/
    Mini Prestamos A Plazos Companias Que Prestan Dinero Solicitar Prestamo Personal Por Internet Creditos Y Prestamos Rapidos

  4. Your comment is awaiting moderation. This is a preview, your comment will be visible after it has been approved.

    Credito De 300 Euros Prestamos Para Pagar A Plazos Credito De 300 Prestamos Personales Por Internet 24 Horas Quien Hace Prestamos Personales
    https://prestamosenestadosunidos.space/peachtree-city-ga/
    Donde Sacar Prestamos Personales Entidades De Prestamos De Dinero Credito Personal Que Cuenta Es Calcular Cuota Prestamo Prestamos En Linea Por Internet
    https://prestamosenestadosunidos.space/missouri-city-tx/
    Donde Sacar Prestamos Personales Euro Credito En Linea Mini Prestamos Rapidos Online Como Conseguir Un Prestamo Facil Empresas Que Prestan Dinero
    https://prestamosenestadosunidos.space/spring-tx/
    Sucursales De Prestamos Personales Presto Credito Credito Consumo

  5. Your comment is awaiting moderation. This is a preview, your comment will be visible after it has been approved.

    Sacar Un Credito Personal Simulador Prestamos Personales Online Pedir Credito Online
    https://prestamosurgente.space/escondido-ca/
    Credit Opiniones Financieras Para Prestamos Personales Pequenos Prestamos Rapidos Online Creditos A Plazos Online
    https://prestamosurgente.space/fresno-ca/
    Credito Particular Solicitar Dinero Tasa Interes Prestamos Personales Prestamos A Pagar Por Mes Prestamos Personales Con Nomina
    https://prestamosurgente.space/albuquerque-nm/
    Agencias De Prestamos Personales Tasas Creditos Personales Sacar Un Credito Personal

  6. Your comment is awaiting moderation. This is a preview, your comment will be visible after it has been approved.

    Todo Facil Prestamos Prestamos Personales Simulador De Cuotas Prestamos Online Bajo Interes Entidades De Credito
    https://prestamosenestadosunidos.space/ventura-ca/
    Donde Puedo Pedir Un Prestamo Personal Requisitos Para Solicitar Un Prestamo Personal Creditos A Plazos Online Prestamistas Urgentes
    https://prestamosenestadosunidos.space/allen-tx/
    Mini Creditos Cual Es El Mejor Banco Para Prestamos Personales Prestamos Minicreditos
    https://prestamosenestadosunidos.space/gilbert-az/
    Prestamos Rapidos Y Faciles En Linea Mi Primer Prestamo Creditos Rapidos Conseguir Prestamo Rapido Como Solicitar Un Credito

  7. Your comment is awaiting moderation. This is a preview, your comment will be visible after it has been approved.

    Pedir Prestamo Personal Por Mensaje Empresa De Prestamos De Dinero Simulador De Credito De Nomina Como Calcular Un Credito Personal
    https://prestamosurgente.space/brownsville-tx/
    Como Saber Tu Credito Personal Prestamos X Dia Solicitud De Prestamos En Linea
    https://prestamosurgente.space/corona-ca/
    Pedir Dinero Urgente Mini Creditos A Plazos Prestamos Con Tarjeta De Credito Online
    https://prestamosurgente.space/orlando-fl/
    Solicitar Credito Rapido Prestamos Y Creditos Online En Donde Prestan Dinero Rapido Prestamos Al Consumo

  8. Your comment is awaiting moderation. This is a preview, your comment will be visible after it has been approved.

    Simulador De Credito Dinero Express Prestamos Con Poco Interes Credito Dineo Como Hacer Credito Rapido
    https://creditosrapidosenusa.space/los-angeles-ca/
    Prestamo De Consumo Solicitud De Prestamo Personal Online Credito Personal Requisitos
    https://creditosrapidosenusa.space/dalton-ga/
    Credil Prestamos Personales Pedir Credito Rapido Cotizador De Creditos Personales Que Es Un Prestamo Personal
    https://creditosrapidosenusa.space/east-brunswick-nj/
    Buscar Creditos Personales Requisitos Para Obtener Un Prestamo Personal Credito Nomina Creditos Rapidos Para Pagar A Plazos

  9. Your comment is awaiting moderation. This is a preview, your comment will be visible after it has been approved.

    Creditos Pequenos Rapidos Credito Rapido 300 Euros Donde Prestan Dinero Urgente
    https://prestamosurgente.space/port-arthur-tx/
    Creditos Y Prestamos Online Personas Hagan Prestamos Tasa De Interes Prestamos Personales Como Conseguir Un Prestamo Personal Creditos Por Internet
    https://prestamosurgente.space/east-point-ga/
    Prestamos Personales Online Prestamos Rapidos Nuevos Como Conseguir Un Prestamo De Dinero Credito Personal Requisitos Prestamos De 300
    https://prestamosurgente.space/pahrump-nv/
    Casa De Prestamos De Dinero Quiero Sacar Un Prestamo Personal Prestamo 300 Euros Creditos Rapidos

  10. Your comment is awaiting moderation. This is a preview, your comment will be visible after it has been approved.

    Empresas De Creditos Personales Calcular Prestamo Online Necesito Prestamo De Dinero Urgente Solicitar Credito Online Quiero Un Credito Personal
    https://prestamosurgente.space/santa-clara-ca/
    Credito Consumo Online Prestamos Personales De Dinero Prestamos Baratos Prestamos En Linea Urgentes
    https://prestamosurgente.space/palm-bay-fl/
    Donde Me Pueden Prestar Dinero Facil Y Rapido Prestamos Personales Rapidos Por Internet A Cuanto Esta El Interes De Un Prestamo Personal Donde Sacar Un Prestamo Facil Y Rapido
    https://prestamosurgente.space/vallejo-ca/
    Como Pedir El Prestamo De Personal Como Conseguir Un Prestamo Facil Simulador De Prestamos Personales Como Solicitar Un Prestamo Personal

  11. Your comment is awaiting moderation. This is a preview, your comment will be visible after it has been approved.

    Paginas Que Prestan Dinero Creditos Rapidisimos Creditos Rapidos Para Pagar A Plazos Que Interes Tiene Un Prestamo Personal Personas Que Hagan Prestamos Personales
    https://creditosrapidosenusa.space/st-petersburg-fl/
    Como Conseguir Un Prestamo De Dinero Microcredito Simulador De Credito Personal Credito Con Dinero Tipo Interes Credito Personal
    https://creditosrapidosenusa.space/pembroke-pines-fl/
    Prestamos Directos Online Quiero Un Credito Rapido Creditos Baratos Creditos Via Internet Donde Conseguir Un Prestamo
    https://creditosrapidosenusa.space/rialto-ca/
    Credito Rapido On Line Pedir Dinero Rapido Un Prestamo Credito Requisitos Prestamos De Dinero Con Dni

Leave a Reply

Your email address will not be published. Required fields are marked *