[merged mm-nonmm-stable] pps-dont-allow-pps_kc_bind-on-removed-devices.patch removed from -mm tree

Andrew Morton <[email protected]> Mon, 03 Aug 2026 21:05:08 -0700
Newsgroups org.kernel.vger.mm-commits
Message-ID <[email protected]>
The quilt patch titled
     Subject: pps: don't allow PPS_KC_BIND on removed devices
has been removed from the -mm tree.  Its filename was
     pps-dont-allow-pps_kc_bind-on-removed-devices.patch

This patch was dropped because it was merged into the mm-nonmm-stable branch
of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm

------------------------------------------------------
From: Calvin Owens <[email protected]>
Subject: pps: don't allow PPS_KC_BIND on removed devices
Date: Wed, 3 Jun 2026 10:25:44 -0700

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 usecs
    pps pps0: bound kernel consumer: edge=0x1
    pps pps0: unbound kernel consumer on device removal
    pps pps0: bound kernel consumer: edge=0x1
    calling  pps_ktimer_init+0x0/0x1000 [pps_ktimer] @ 1085
    initcall pps_ktimer_init+0x0/0x1000 [pps_ktimer] returned 0 after 340 usecs
    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 <stdlib.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/ioctl.h>
    #include <linux/pps.h>
    #include <errno.h>
    #include <err.h>

    int main(void)
    {
        while (1) {
            int fd;

            if (system("insmod ./pps-ktimer.ko"))
                err(1, "insmod failed");

            fd = open("/dev/pps0", O_RDWR);
            if (fd == -1)
                err(1, "open failed");

            struct pps_bind_args args = {
                .tsformat = PPS_TSFMT_TSPEC,
                .edge = PPS_CAPTUREASSERT,
                .consumer = 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 != 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.

Link: https://lore.kernel.org/672778c177ac9b6fdcb445e35c97ac4ca7d1149f.1780506611.git.calvin@wbinvd.org
Signed-off-by: Calvin Owens <[email protected]>
Reported-by: Sashiko <[email protected]>
Closes: https://sashiko.dev/#/patchset/cover.1779733602.git.calvin%40wbinvd.org?part=1
Acked-by: Rodolfo Giometti <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
---

 drivers/pps/kc.c           |   10 ++++++++++
 include/linux/pps_kernel.h |    1 +
 2 files changed, 11 insertions(+)

--- a/drivers/pps/kc.c~pps-dont-allow-pps_kc_bind-on-removed-devices
+++ a/drivers/pps/kc.c
@@ -38,6 +38,14 @@ int pps_kc_bind(struct pps_device *pps,
 	/* Check if another consumer is already bound */
 	spin_lock_irq(&pps_kc_hardpps_lock);
 
+	/*
+	 * Don't allow PPS_KC_BIND on a removed device.
+	 */
+	if (pps->kc_removed) {
+		spin_unlock_irq(&pps_kc_hardpps_lock);
+		return -ENODEV;
+	}
+
 	if (bind_args->edge == 0)
 		if (pps_kc_hardpps_dev == pps) {
 			pps_kc_hardpps_mode = 0;
@@ -79,6 +87,8 @@ int pps_kc_bind(struct pps_device *pps,
 void pps_kc_remove(struct pps_device *pps)
 {
 	spin_lock_irq(&pps_kc_hardpps_lock);
+
+	pps->kc_removed = true;
 	if (pps == pps_kc_hardpps_dev) {
 		pps_kc_hardpps_mode = 0;
 		pps_kc_hardpps_dev = NULL;
--- a/include/linux/pps_kernel.h~pps-dont-allow-pps_kc_bind-on-removed-devices
+++ a/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;
 };
 
 /*
_

Patches currently in -mm which might be from [email protected] are