โฌข DragonFlyBSD Kernel Audit
DF-0724 / rfcomm_race_test.c
โ† back to finding โ†“ download raw
/*
 * DF-0724 โ€” Unsynchronized timer-vs-caller double-close race in
 * rfcomm_dlc_close (sys/netbt/rfcomm_dlc.c:151-183).
 *
 * Trigger attempt: create an RFCOMM socket, bind, and try to connect
 * to a (nonexistent) remote Bluetooth peer. If a session could be
 * established, the DLC timer (rd_timeout, 20s) would be armed, and a
 * DISC frame from the peer arriving at the timer-expiry window would
 * race rfcomm_dlc_close between the softclock handler
 * (rfcomm_dlc_timeout, rfcomm_dlc.c:195) and the network-input path
 * (rfcomm_session.c:784/819/876/911), causing a double-LIST_REMOVE,
 * double disconnected callback, and double session-expiry scheduling.
 *
 * RESULT on this guest: socket() and bind() succeed (after netbt.ko
 * is loaded by root), but connect() fails with EHOSTUNREACH ("No route
 * to host") because there is NO Bluetooth adapter / HCI unit on the
 * QEMU guest. Without an HCI unit, no L2CAP link, no RFCOMM session,
 * no DLC timer โ€” the race path is unreachable. This is a code-level
 * race confirmed by source tracing (see VERDICT.md) but not exercisable
 * on this guest.
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <netbt/bluetooth.h>
#include <netbt/rfcomm.h>

int
main(void)
{
	int s;
	struct sockaddr_bt laddr, raddr;

	s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
	if (s < 0) {
		printf("socket(RFCOMM) FAIL errno=%d (%s)\n",
		    errno, strerror(errno));
		printf("=> netbt.ko not loaded; AF_BLUETOOTH domain "
		       "unregistered\n");
		return 1;
	}
	printf("socket(RFCOMM) = %d OK\n", s);

	memset(&laddr, 0, sizeof(laddr));
	laddr.bt_len = sizeof(laddr);
	laddr.bt_family = AF_BLUETOOTH;
	/* bt_bdaddr = all-zeros = BDADDR_ANY */

	if (bind(s, (struct sockaddr *)&laddr, sizeof(laddr)) < 0) {
		printf("bind FAIL errno=%d (%s)\n", errno, strerror(errno));
	} else {
		printf("bind OK\n");
	}

	memset(&raddr, 0, sizeof(raddr));
	raddr.bt_len = sizeof(raddr);
	raddr.bt_family = AF_BLUETOOTH;
	raddr.bt_channel = 1;
	raddr.bt_bdaddr.b[0] = 0x01;	/* arbitrary non-zero peer */

	if (connect(s, (struct sockaddr *)&raddr, sizeof(raddr)) < 0) {
		printf("connect FAIL errno=%d (%s)\n", errno, strerror(errno));
		printf("=> no HCI unit / BT adapter; L2CAP link cannot be "
		       "established; RFCOMM session unreachable\n");
	} else {
		printf("connect OK โ€” session established (unexpected!)\n");
		/* If we got here, the DLC timer would be armed (20s).
		 * Closing the socket now would race against the timer.
		 * But this path is not reached on this guest. */
	}

	close(s);
	printf("done\n");
	return 0;
}