From nobody Mon Jun 8 09:49:29 2026 Received: from mail-dy1-f178.google.com (mail-dy1-f178.google.com [74.125.82.178]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AB9AC20ED for ; Sat, 30 May 2026 02:46:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.178 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780109217; cv=none; b=cP+UOiqa0EFY3xsEVlfbZHGydYX7ej/QOfIpobl1mA6vfTVCWpkwONSpaL5JydHh7osJmaEE304MmoWuh/FVIhQ3/GOhzF+4BLUtXh2In4fB+MNEJh7iZq/L/ah9xHtbKEaPG8VOLOj7q3BNlc4m3V3DW8v9jkW1bRji8m7AEY8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780109217; c=relaxed/simple; bh=ab1XFI8ZhS9mQFGSCS6vPUaLitfosz7uOL8HHpbf3Ts=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=swRRMimS12ShxWaxrFpvvLml6zLuJ65M/3f2+oMCfU/UuqmuWFkrvZDfC9aXF0OPJJw4ndR2Bt9ywyHxRBXwPLbE8moq8g71zUssxTJlH/vZOCQnxMdNNNr6t6jphDD+u1p4CvquGsvThb3N2uPJuVnpkxDXtYtT1u3Bmede/CQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=wbinvd.org; spf=pass smtp.mailfrom=wbinvd.org; dkim=pass (2048-bit key) header.d=wbinvd.org header.i=@wbinvd.org header.b=MV+wqrz6; arc=none smtp.client-ip=74.125.82.178 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=wbinvd.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=wbinvd.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=wbinvd.org header.i=@wbinvd.org header.b="MV+wqrz6" Received: by mail-dy1-f178.google.com with SMTP id 5a478bee46e88-304e83724bfso2118025eec.0 for ; Fri, 29 May 2026 19:46:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=wbinvd.org; s=wbinvd; t=1780109215; x=1780714015; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=ZzH9ok0+H+Onagh80bIxPoJb8EFgdppi50Z1sdGayBU=; b=MV+wqrz67Bet5Jt1Amn6e16sD51TI0cZ0WUxhlqWvMDKKc3S4BZE3VO3WiLMYybs5O 6/qooxY6R+1oqR6/ZDS+4XaSAHutXFgbKeXAcmDhlnQwxjZyPoIPkxoJ5dAd351TMM2N C2yq1ySzh1K+pERTzG7VGYzx0MhOG6p73MmFSep2z8ieCbsTNLGL5rxGbPVrguyUX9WD PrLatvIYoHfrDIMFRMNlhXR/kwF1mrhseJHvWAdkxn1W7GxhxBpxTCuwKsg21BExIbPP /mx80Gfg5Et5XLFCoe7kA/HVdfXA7kq6qdD/i03lW6umzVB92H5TrfTURxVDFgijHgt8 N43g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780109215; x=1780714015; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=ZzH9ok0+H+Onagh80bIxPoJb8EFgdppi50Z1sdGayBU=; b=J+/g/Md+pVukWnS7nxyRPk7LEXg09HySYofKjCavwcMGfVcWbvBFmXVBQN3iG9NILb y8e9erQTiXJH9mdq7PUYimCPITGM3FYLxcsoDjF/IaIEfDqbMiCaP9tvniZphDloyODl 38sX7EVsG0JcBC6xtPOUPYDKX+Ia7fl/+fFMzRxqihc1KCDuVK0cNrgf3nPdnKG9Z3W/ hlptItDtcAeMia730X0ezJLy5z19+iHB3mSFyw3Aw/FO1VDccxGTXA9zDUUTxxYb+Heh ui+YNLP1QcjkN0aBGjbwiaOAx/s5DZ3qkSLPXsjUxRP4OXtEygE6tcd1X94UDvxsNAl/ axOQ== X-Gm-Message-State: AOJu0YxR9iNJGG1QIRuWgjg5XuRclWzovFaw0wqvyl5cCcBIiW+UolxU YXRBMHv5khXuwlrWkwJtyzTRwbv95/hJ85Am0CGJZAXinQo99M+nvGH0xh7X9DFDArGKqWh9Des mFrhN X-Gm-Gg: Acq92OEKdyGIbnd1keYrd0V28FtNczRSEqFZzHy68AgTuI/IM3yw8S4ur/G1Taol6ih YL9hnjdFVZiwlOPj8FiCP6MFMjxUYuuJ8Nv3wum3eqHxJ2vgAEibeLRuMp3wlKvP1p79/8bEQ16 MqfM5tPYk3rx7rLJkHPJWBxeLSz6ZZiPWyqQzVa1bsGMrJf4y5Ir2x9Wmk1uJ5gUnlrCF2U8MRp +W8CMqVNBw1jA6PsJE1Ot6E6AqBkiiu5IMQGiz+OA4rXC+Co3qYUCOnPFTQHCw9yOmt6hUXHnMS m3Sgdqiao+SRJCJsaLsTuwRycY+Cgi+p+tIXi/6tdvGMFbi8TzJi5wSsiXC1x/lIOm16g+ep7Bp YjQixUkc9YI8ttuIG4aM0kZ24CoiNEezX6EoQ5Lxgg3D1JpViXYdu1wme3mkWiV3muGoSIKob7j ZNW6mBI45EaExrJouaUPy1qW2plzDXX/Wfs79B X-Received: by 2002:a05:693c:3742:b0:304:cd1a:f066 with SMTP id 5a478bee46e88-304fa508b6emr1135652eec.13.1780109214644; Fri, 29 May 2026 19:46:54 -0700 (PDT) Received: from mozart.vkv.me ([2001:5a8:468b:d015:ed95:9469:51ff:4655]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-304ed53d14fsm2934732eec.17.2026.05.29.19.46.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 29 May 2026 19:46:54 -0700 (PDT) From: Calvin Owens To: linux-kernel@vger.kernel.org Cc: Rodolfo Giometti , Greg Kroah-Hartman Subject: [PATCH] pps: Don't allow PPS_KC_BIND on removed devices Date: Fri, 29 May 2026 19:46:08 -0700 Message-ID: X-Mailer: git-send-email 2.47.3 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" If userspace holds its file descriptor open, it can call PPS_KC_BIND on a device which has been unplugged, leaving pps_kc_hardpps_dev as a dangling pointer after close(). After that sequence, PPS_KC_BIND is broken until the system is rebooted, because the pointer comparison in pps_kc_bind() can never be true. calling pps_ktimer_init+0x0/0x1000 [pps_ktimer] @ 1081 initcall pps_ktimer_init+0x0/0x1000 [pps_ktimer] returned 0 after 811 u= secs pps pps0: bound kernel consumer: edge=3D0x1 pps pps0: unbound kernel consumer on device removal pps pps0: bound kernel consumer: edge=3D0x1 calling pps_ktimer_init+0x0/0x1000 [pps_ktimer] @ 1085 initcall pps_ktimer_init+0x0/0x1000 [pps_ktimer] returned 0 after 340 u= secs pps pps0: another kernel consumer is already bound Here is a short reproducer, which uses rmmod of the pps-ktimer testcase to simulate a device being unplugged: #include #include #include #include #include #include #include #include int main(void) { while (1) { int fd; if (system("insmod ./pps-ktimer.ko")) err(1, "insmod failed"); fd =3D open("/dev/pps0", O_RDWR); if (fd =3D=3D -1) err(1, "open failed"); struct pps_bind_args args =3D { .tsformat =3D PPS_TSFMT_TSPEC, .edge =3D PPS_CAPTUREASSERT, .consumer =3D PPS_KC_HARDPPS, }; if (ioctl(fd, PPS_KC_BIND, &args)) err(1, "first PPS_KC_BIND failed"); if (system("rmmod pps-ktimer")) err(1, "rmmod failed"); if (ioctl(fd, PPS_KC_BIND, &args)) { if (errno !=3D ENODEV) err(1, "second PPS_KC_BIND failed"); else puts("Got ENODEV, kernel is patched"); } close(fd); } } Fix this by setting a flag when the device is unplugged, returning -ENODEV from PPS_KC_BIND if the flag is set. For userspace to encounter this new behavior, it must do something which breaks the interface today, so this fix shouldn't cause any observable behavior change for working programs. Reported-by: Sashiko Closes: https://sashiko.dev/#/patchset/cover.1779733602.git.calvin%40wbinvd= .org?part=3D1 Signed-off-by: Calvin Owens --- I generally hate "just add a flag" as a way to fix this sort of thing, but I think this really is specific to KC_BIND and not a more general lifetime problem. drivers/pps/kc.c | 20 +++++++++++--------- include/linux/pps_kernel.h | 1 + 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/pps/kc.c b/drivers/pps/kc.c index fbd23295afd7..5f9058f663c8 100644 --- a/drivers/pps/kc.c +++ b/drivers/pps/kc.c @@ -36,17 +36,21 @@ static int pps_kc_hardpps_mode; /* mode bits for kerne= l consumer */ int pps_kc_bind(struct pps_device *pps, struct pps_bind_args *bind_args) { /* Check if another consumer is already bound */ - spin_lock_irq(&pps_kc_hardpps_lock); + guard(spinlock_irq)(&pps_kc_hardpps_lock); + + /* + * Don't allow PPS_KC_BIND on a removed device. + */ + if (pps->kc_removed) + return -ENODEV; =20 if (bind_args->edge =3D=3D 0) if (pps_kc_hardpps_dev =3D=3D pps) { pps_kc_hardpps_mode =3D 0; pps_kc_hardpps_dev =3D NULL; - spin_unlock_irq(&pps_kc_hardpps_lock); dev_info(&pps->dev, "unbound kernel" " consumer\n"); } else { - spin_unlock_irq(&pps_kc_hardpps_lock); dev_err(&pps->dev, "selected kernel consumer" " is not bound\n"); return -EINVAL; @@ -56,11 +60,9 @@ int pps_kc_bind(struct pps_device *pps, struct pps_bind_= args *bind_args) pps_kc_hardpps_dev =3D=3D pps) { pps_kc_hardpps_mode =3D bind_args->edge; pps_kc_hardpps_dev =3D pps; - spin_unlock_irq(&pps_kc_hardpps_lock); dev_info(&pps->dev, "bound kernel consumer: " "edge=3D0x%x\n", bind_args->edge); } else { - spin_unlock_irq(&pps_kc_hardpps_lock); dev_err(&pps->dev, "another kernel consumer" " is already bound\n"); return -EINVAL; @@ -78,15 +80,15 @@ int pps_kc_bind(struct pps_device *pps, struct pps_bind= _args *bind_args) */ void pps_kc_remove(struct pps_device *pps) { - spin_lock_irq(&pps_kc_hardpps_lock); + guard(spinlock_irq)(&pps_kc_hardpps_lock); + + pps->kc_removed =3D true; if (pps =3D=3D pps_kc_hardpps_dev) { pps_kc_hardpps_mode =3D 0; pps_kc_hardpps_dev =3D NULL; - spin_unlock_irq(&pps_kc_hardpps_lock); dev_info(&pps->dev, "unbound kernel consumer" " on device removal\n"); - } else - spin_unlock_irq(&pps_kc_hardpps_lock); + } } =20 /* pps_kc_event - call hardpps() on PPS event diff --git a/include/linux/pps_kernel.h b/include/linux/pps_kernel.h index aab0aebb529e..3c2979f8a5ac 100644 --- a/include/linux/pps_kernel.h +++ b/include/linux/pps_kernel.h @@ -60,6 +60,7 @@ struct pps_device { struct device dev; struct fasync_struct *async_queue; /* fasync method */ spinlock_t lock; + bool kc_removed; }; =20 /* --=20 2.47.3