Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 30 Sep 2025 11:21:30 GMT
From:      Ahmad Khalifa <vexeduxr@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: d000adfe41e6 - main - gpioc: fix race in ioctl(GPIOCONFIGEVENTS)
Message-ID:  <202509301121.58UBLUV6087948@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by vexeduxr:

URL: https://cgit.FreeBSD.org/src/commit/?id=d000adfe41e6f2fe8f3dbe92d8fc2d34ae882086

commit d000adfe41e6f2fe8f3dbe92d8fc2d34ae882086
Author:     Ahmad Khalifa <vexeduxr@FreeBSD.org>
AuthorDate: 2025-09-30 11:09:50 +0000
Commit:     Ahmad Khalifa <vexeduxr@FreeBSD.org>
CommitDate: 2025-09-30 11:20:25 +0000

    gpioc: fix race in ioctl(GPIOCONFIGEVENTS)
    
    A race can occur in gpioc_ioctl when it is called with GPIOCONFIGEVENTS
    closely followed by GPIOSETCONFIG. GPIOSETCONFIG can alter the
    priv->pins list, making it no longer empty and opening the door for
    access to priv->events while we are reallocating it. Fix this by holding
    priv->mtx while handling GPIOCONFIGEVENTS.
    
    Reported by:    Qiu-ji Chen
    PR:             289120
    Reviewed by:    mmel
    MFC after:      1 day
    Differential Revision:  https://reviews.freebsd.org/D52783
---
 sys/dev/gpio/gpioc.c | 29 +++++++++++++++++++----------
 1 file changed, 19 insertions(+), 10 deletions(-)

diff --git a/sys/dev/gpio/gpioc.c b/sys/dev/gpio/gpioc.c
index b56fe6b4c37f..9b297bcb1a77 100644
--- a/sys/dev/gpio/gpioc.c
+++ b/sys/dev/gpio/gpioc.c
@@ -793,6 +793,7 @@ gpioc_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
 	struct gpio_access_32 *a32;
 	struct gpio_config_32 *c32;
 	struct gpio_event_config *evcfg;
+	struct gpioc_pin_event *tmp;
 	uint32_t caps, intrflags;
 
 	switch (cmd) {
@@ -908,27 +909,35 @@ gpioc_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
 		res = devfs_get_cdevpriv((void **)&priv);
 		if (res != 0)
 			break;
-		/* If any pins have been configured, changes aren't allowed. */
-		if (!SLIST_EMPTY(&priv->pins)) {
-			res = EINVAL;
-			break;
-		}
 		if (evcfg->gp_report_type != GPIO_EVENT_REPORT_DETAIL &&
 		    evcfg->gp_report_type != GPIO_EVENT_REPORT_SUMMARY) {
 			res = EINVAL;
 			break;
 		}
-		priv->report_option = evcfg->gp_report_type;
 		/* Reallocate the events buffer if the user wants it bigger. */
-		if (priv->report_option == GPIO_EVENT_REPORT_DETAIL &&
+		tmp = NULL;
+		if (evcfg->gp_report_type == GPIO_EVENT_REPORT_DETAIL &&
 		    priv->numevents < evcfg->gp_fifo_size) {
-			free(priv->events, M_GPIOC);
-			priv->numevents = evcfg->gp_fifo_size;
-			priv->events = malloc(priv->numevents *
+			tmp = malloc(priv->numevents *
 			    sizeof(struct gpioc_pin_event), M_GPIOC,
 			    M_WAITOK | M_ZERO);
+		}
+		mtx_lock(&priv->mtx);
+		/* If any pins have been configured, changes aren't allowed. */
+		if (!SLIST_EMPTY(&priv->pins)) {
+			mtx_unlock(&priv->mtx);
+			free(tmp, M_GPIOC);
+			res = EINVAL;
+			break;
+		}
+		if (tmp != NULL) {
+			free(priv->events, M_GPIOC);
+			priv->events = tmp;
+			priv->numevents = evcfg->gp_fifo_size;
 			priv->evidx_head = priv->evidx_tail = 0;
 		}
+		priv->report_option = evcfg->gp_report_type;
+		mtx_unlock(&priv->mtx);
 		break;
 	case FIONBIO:
 		/*



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202509301121.58UBLUV6087948>