Searched +hist:0 +hist:c0382e3 (Results 1 - 13 of 13) sorted by relevance
/linux-master/drivers/usb/host/ | ||
H A D | ohci-sa1111.c | diff 074a6bda Thu Jan 14 09:31:09 MST 2021 Uwe Kleine-König <u.kleine-koenig@pengutronix.de> ARM: 9048/1: sa1111: make sa1111 bus's remove callback return void The driver core ignores the return value of struct device_driver::remove because there is only little that can be done. To simplify the quest to make this function return void, let struct sa1111_driver::remove return void, too. All users already unconditionally return 0, this commit makes it obvious that returning an error code is a bad idea and ensures future users behave accordingly. Link: https://lore.kernel.org/r/20201126114724.2028511-1-u.kleine-koenig@pengutronix.de Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> diff 0c0382e3 Thu Oct 13 15:08:02 MDT 2005 Alan Stern <stern@rowland.harvard.edu> [PATCH] USB: Rename hcd->hub_suspend to hcd->bus_suspend This patch (as580) is perhaps the only result from the long discussion I had with David about his changes to the root-hub suspend/resume code. It renames the hub_suspend and hub_resume methods in struct usb_hcd to bus_suspend and bus_resume. These are more descriptive names, since the methods really do suspend or resume an entire USB bus, and less likely to be confused with the hub_suspend and hub_resume routines in hub.c. It also takes David's advice about removing the layer of bus glue, where those methods are called. And it implements a related change that David made to the other HCDs but forgot to put into dummy_hcd. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> diff 0c0382e3 Thu Oct 13 15:08:02 MDT 2005 Alan Stern <stern@rowland.harvard.edu> [PATCH] USB: Rename hcd->hub_suspend to hcd->bus_suspend This patch (as580) is perhaps the only result from the long discussion I had with David about his changes to the root-hub suspend/resume code. It renames the hub_suspend and hub_resume methods in struct usb_hcd to bus_suspend and bus_resume. These are more descriptive names, since the methods really do suspend or resume an entire USB bus, and less likely to be confused with the hub_suspend and hub_resume routines in hub.c. It also takes David's advice about removing the layer of bus glue, where those methods are called. And it implements a related change that David made to the other HCDs but forgot to put into dummy_hcd. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
H A D | ohci-s3c2410.c | diff 0ded36d9 Wed Nov 13 05:10:18 MST 2013 Majunath Goudar <csmanjuvijay@gmail.com> USB: OHCI: Properly handle ohci-s3c2410 suspend Suspend scenario in case of ohci-s3c2410 glue was not properly handled as it was not suspending generic part of ohci controller. Alan Stern suggested, properly handle ohci-s3c2410 suspend scenario. Calling explicitly the ohci_suspend() routine in ohci_hcd_s3c2410_drv_suspend() will ensure proper handling of suspend scenario. Signed-off-by: Manjunath Goudar <csmanjuvijay@gmail.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Cc: Ben Dooks <ben-linux@fluff.org> Cc: Kukjin Kim <kgene.kim@samsung.com> Cc: linux-arm-kernel@lists.infradead.org Cc: linux-samsung-soc@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-usb@vger.kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff 0c0382e3 Thu Oct 13 15:08:02 MDT 2005 Alan Stern <stern@rowland.harvard.edu> [PATCH] USB: Rename hcd->hub_suspend to hcd->bus_suspend This patch (as580) is perhaps the only result from the long discussion I had with David about his changes to the root-hub suspend/resume code. It renames the hub_suspend and hub_resume methods in struct usb_hcd to bus_suspend and bus_resume. These are more descriptive names, since the methods really do suspend or resume an entire USB bus, and less likely to be confused with the hub_suspend and hub_resume routines in hub.c. It also takes David's advice about removing the layer of bus glue, where those methods are called. And it implements a related change that David made to the other HCDs but forgot to put into dummy_hcd. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> diff 0c0382e3 Thu Oct 13 15:08:02 MDT 2005 Alan Stern <stern@rowland.harvard.edu> [PATCH] USB: Rename hcd->hub_suspend to hcd->bus_suspend This patch (as580) is perhaps the only result from the long discussion I had with David about his changes to the root-hub suspend/resume code. It renames the hub_suspend and hub_resume methods in struct usb_hcd to bus_suspend and bus_resume. These are more descriptive names, since the methods really do suspend or resume an entire USB bus, and less likely to be confused with the hub_suspend and hub_resume routines in hub.c. It also takes David's advice about removing the layer of bus glue, where those methods are called. And it implements a related change that David made to the other HCDs but forgot to put into dummy_hcd. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> diff ba44e7c4 Tue Aug 09 08:04:00 MDT 2005 Ben Dooks <ben-linux@fluff.org> [PATCH] USB: S3C24XX port numbering fix Fix the port numbering confusion for the S3C24XX platform device information as reported by Rudy <rudyboy168@gmail.com> This patch ensurs that the the ports are numbered 0 and 1. Signed-off-by: Ben Dooks <ben-linux@fluff.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
H A D | ohci-pci.c | diff c1db30a2 Thu May 01 13:21:42 MDT 2014 Alan Stern <stern@rowland.harvard.edu> USB: OHCI: fix problem with global suspend on ATI controllers Some OHCI controllers from ATI/AMD seem to have difficulty with "global" USB suspend, that is, suspending an entire USB bus without setting the suspend feature for each port connected to a device. When we try to resume the child devices, the controller gives timeout errors on the unsuspended ports, requiring resets, and can even cause ohci-hcd to hang; see http://marc.info/?l=linux-usb&m=139514332820398&w=2 and the following messages. This patch fixes the problem by adding a new quirk flag to ohci-hcd. The flag causes the ohci_rh_suspend() routine to suspend each unsuspended, enabled port before suspending the root hub. This effectively converts the "global" suspend to an ordinary root-hub suspend. There is no need to unsuspend these ports when the root hub is resumed, because the child devices will be resumed anyway in the course of a normal system resume ("global" suspend is never used for runtime PM). This patch should be applied to all stable kernels which include commit 0aa2832dd0d9 (USB: use "global suspend" for system sleep on USB-2 buses) or a backported version thereof. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Reported-by: Peter Münster <pmlists@free.fr> Tested-by: Peter Münster <pmlists@free.fr> CC: <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff a0d4922d Wed Dec 17 13:06:03 MST 2008 Alan Stern <stern@rowland.harvard.edu> USB: fix up suspend and resume for PCI host controllers This patch (as1192) rearranges the USB PCI host controller suspend and resume and resume routines: Use pci_wake_from_d3() for enabling and disabling wakeup, instead of pci_enable_wake(). Carry out the actual state change while interrupts are disabled. Change the order of the preparations to agree with the general recommendation for PCI devices, instead of messing around with the wakeup settings while the device is in D3. In .suspend: Call the underlying driver to disable IRQ generation; pci_wake_from_d3(device_may_wakeup()); pci_disable_device(); In .suspend_late: pci_save_state(); pci_set_power_state(D3hot); (for PPC_PMAC) Disable ASIC clocks In .resume_early: (for PPC_PMAC) Enable ASIC clocks pci_set_power_state(D0); pci_restore_state(); In .resume: pci_enable_device(); pci_set_master(); pci_wake_from_d3(0); Call the underlying driver to reenable IRQ generation Add the necessary .suspend_late and .resume_early method pointers to the PCI host controller drivers. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> CC: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> diff 0d22f655 Thu Apr 03 09:35:26 MDT 2008 Alan Stern <stern@rowland.harvard.edu> USB: OHCI: fix bug in controller resume This patch (as1063) fixes a bug in the way ohci-hcd resumes its controllers. It leaves the Master Interrupt Enable bit turned off. If the root hub is resumed immediately this won't matter. But if the root hub is suspended (say because no devices are plugged in), it won't ever wake up by itself. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> CC: David Brownell <david-b@pacbell.net> Cc: stable <stable@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> diff 8ab5e8c0 Sat May 19 15:23:28 MDT 2007 Andrey Borzenkov <arvidjaar@mail.ru> USB: Fix USB OHCI Subvendor for Toshiba Portege 4000 This fixes a bug in an OHCI quirk handler for Portege 4000; the Subvendor is 0x1179 (PCI_VENDOR_ID_TOSHIBA) not 0x102f (PCI_VENDOR_ID_TOSHIBA_2) bugid 8510 00:02.0 USB Controller [0c03]: ALi Corporation USB 1.1 Controller [10b9:5237] (rev 03) (prog-if 10 [OHCI]) Subsystem: Toshiba America Info Systems Unknown device [1179:0004] Flags: bus master, medium devsel, latency 64, IRQ 11 Memory at f7eff000 (32-bit, non-prefetchable) [size=4K] Capabilities: <access denied> Signed-off-by: Andrey Borzenkov <arvidjaar@mail.ru> Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> diff 8ab5e8c0 Sat May 19 15:23:28 MDT 2007 Andrey Borzenkov <arvidjaar@mail.ru> USB: Fix USB OHCI Subvendor for Toshiba Portege 4000 This fixes a bug in an OHCI quirk handler for Portege 4000; the Subvendor is 0x1179 (PCI_VENDOR_ID_TOSHIBA) not 0x102f (PCI_VENDOR_ID_TOSHIBA_2) bugid 8510 00:02.0 USB Controller [0c03]: ALi Corporation USB 1.1 Controller [10b9:5237] (rev 03) (prog-if 10 [OHCI]) Subsystem: Toshiba America Info Systems Unknown device [1179:0004] Flags: bus master, medium devsel, latency 64, IRQ 11 Memory at f7eff000 (32-bit, non-prefetchable) [size=4K] Capabilities: <access denied> Signed-off-by: Andrey Borzenkov <arvidjaar@mail.ru> Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> diff 8ab5e8c0 Sat May 19 15:23:28 MDT 2007 Andrey Borzenkov <arvidjaar@mail.ru> USB: Fix USB OHCI Subvendor for Toshiba Portege 4000 This fixes a bug in an OHCI quirk handler for Portege 4000; the Subvendor is 0x1179 (PCI_VENDOR_ID_TOSHIBA) not 0x102f (PCI_VENDOR_ID_TOSHIBA_2) bugid 8510 00:02.0 USB Controller [0c03]: ALi Corporation USB 1.1 Controller [10b9:5237] (rev 03) (prog-if 10 [OHCI]) Subsystem: Toshiba America Info Systems Unknown device [1179:0004] Flags: bus master, medium devsel, latency 64, IRQ 11 Memory at f7eff000 (32-bit, non-prefetchable) [size=4K] Capabilities: <access denied> Signed-off-by: Andrey Borzenkov <arvidjaar@mail.ru> Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> diff 0c0382e3 Thu Oct 13 15:08:02 MDT 2005 Alan Stern <stern@rowland.harvard.edu> [PATCH] USB: Rename hcd->hub_suspend to hcd->bus_suspend This patch (as580) is perhaps the only result from the long discussion I had with David about his changes to the root-hub suspend/resume code. It renames the hub_suspend and hub_resume methods in struct usb_hcd to bus_suspend and bus_resume. These are more descriptive names, since the methods really do suspend or resume an entire USB bus, and less likely to be confused with the hub_suspend and hub_resume routines in hub.c. It also takes David's advice about removing the layer of bus glue, where those methods are called. And it implements a related change that David made to the other HCDs but forgot to put into dummy_hcd. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> diff 0c0382e3 Thu Oct 13 15:08:02 MDT 2005 Alan Stern <stern@rowland.harvard.edu> [PATCH] USB: Rename hcd->hub_suspend to hcd->bus_suspend This patch (as580) is perhaps the only result from the long discussion I had with David about his changes to the root-hub suspend/resume code. It renames the hub_suspend and hub_resume methods in struct usb_hcd to bus_suspend and bus_resume. These are more descriptive names, since the methods really do suspend or resume an entire USB bus, and less likely to be confused with the hub_suspend and hub_resume routines in hub.c. It also takes David's advice about removing the layer of bus glue, where those methods are called. And it implements a related change that David made to the other HCDs but forgot to put into dummy_hcd. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> diff 0e498763 Mon Apr 18 18:39:30 MDT 2005 David Brownell <david-b@pacbell.net> [PATCH] USB: OHCI on Compaq Aramada 7400 This adds a quirk to the OHCI driver that lets it work with an old Compaq implementation. It also removes some needless strings from the non-debug version of the driver. Signed-off-by: Chris Clayton <chris_clayton@f1internet.com> Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
H A D | isp116x-hcd.c | diff 0a9e8ade Wed Feb 14 09:08:26 MST 2018 Andy Shevchenko <andriy.shevchenko@linux.intel.com> USB: host: isp116x: Re-use DEFINE_SHOW_ATTRIBUTE() macro ...instead of open coding file operations followed by custom ->open() callbacks per each attribute. Cc: Olav Kongas <ok@artecdesign.ee> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff 0ed930bf Mon Mar 03 06:39:54 MST 2008 Anti Sullin <anti.sullin@artecdesign.ee> USB: isp116x: fix enumeration on boot This patch removes the buffering of the status register. USB core behavior has changed a bit and this buffering was not refreshed at the right time. The core got buffered old value of HCRHPORT and it did not detect any devices on boot. Signed-off-by: Anti Sullin <anti.sullin@artecdesign.ee> Acked by: Olav Kongas <ok@artecdesign.ee> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> diff 5bcd70eb Fri Feb 09 02:51:15 MST 2007 Prarit Bhargava <prarit@redhat.com> USB: change __init to __devinit for isp116x_probe Change __init to __devinit for isp116x_probe. Resolves MODPOST warning: WARNING: drivers/usb/host/isp116x-hcd.o - Section mismatch: reference to .init.text:isp116x_probe from .data.rel.local between 'isp116x_driver' (at offset 0x0) and 'isp116x_hc_driver' Signed-off-by: Prarit Bhargava <prarit@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> diff d5ce1379 Thu Jun 01 21:48:45 MDT 2006 Eric Sesterhenn <snakebyte@gmx.de> [PATCH] USB: negative index in drivers/usb/host/isp116x-hcd.c From: Eric Sesterhenn <snakebyte@gmx.de> This fixes coverity Bug #390. With the following code ret = ep->branch = balance(isp116x, ep->period, ep->load); if (ret < 0) goto fail; the problem is that ret and balance are of the type int, and ep->branch is u16. so the int balance() returns gets reduced to u16 and then converted to an int again, which removes the sign. Maybe the following little c program can explain it better: diff 0be930c5 Tue Dec 27 07:04:02 MST 2005 Olav Kongas <ok@artecdesign.ee> [PATCH] USB: isp116x-hcd: replace mdelay() by msleep() Replace mdelay() by msleep() in bus_suspend(); the rest of the system will gain 7ms. The related code is reorganized to minimize the number of locking/unlocking calls. The last hunk of the patch is the formatting change by Lindent. Signed-off-by: Olav Kongas <ok@artecdesign.ee> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> diff 0c0382e3 Thu Oct 13 15:08:02 MDT 2005 Alan Stern <stern@rowland.harvard.edu> [PATCH] USB: Rename hcd->hub_suspend to hcd->bus_suspend This patch (as580) is perhaps the only result from the long discussion I had with David about his changes to the root-hub suspend/resume code. It renames the hub_suspend and hub_resume methods in struct usb_hcd to bus_suspend and bus_resume. These are more descriptive names, since the methods really do suspend or resume an entire USB bus, and less likely to be confused with the hub_suspend and hub_resume routines in hub.c. It also takes David's advice about removing the layer of bus glue, where those methods are called. And it implements a related change that David made to the other HCDs but forgot to put into dummy_hcd. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> diff 0c0382e3 Thu Oct 13 15:08:02 MDT 2005 Alan Stern <stern@rowland.harvard.edu> [PATCH] USB: Rename hcd->hub_suspend to hcd->bus_suspend This patch (as580) is perhaps the only result from the long discussion I had with David about his changes to the root-hub suspend/resume code. It renames the hub_suspend and hub_resume methods in struct usb_hcd to bus_suspend and bus_resume. These are more descriptive names, since the methods really do suspend or resume an entire USB bus, and less likely to be confused with the hub_suspend and hub_resume routines in hub.c. It also takes David's advice about removing the layer of bus glue, where those methods are called. And it implements a related change that David made to the other HCDs but forgot to put into dummy_hcd. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
H A D | ohci-pxa27x.c | diff 0a980beb Thu Mar 07 04:24:06 MST 2024 Andy Shevchenko <andriy.shevchenko@linux.intel.com> usb: ohci-pxa27x: Remove unused of_gpio.h of_gpio.h is deprecated and subject to remove. The driver doesn't use it, simply remove the unused header. Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Link: https://lore.kernel.org/r/20240307112406.3625756-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff 0c392ed9 Fri Oct 03 10:57:21 MDT 2008 Eric Miao <eric.miao@marvell.com> [ARM] ohci-pxa27x: use ioremap() and offset for register access This avoid the pre-mapping of OHCI controller register space, and the mapping is made only when necessary (OHCI is probed). Signed-off-by: Eric Miao <eric.miao@marvell.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> diff 0cb0b0d3 Fri Oct 03 10:45:39 MDT 2008 Eric Miao <eric.miao@marvell.com> [ARM] ohci-pxa27x: introduce pxa27x_clear_otgph() Direct access to pxa27x specific register PSSR in a generic ohci driver is no good, introduce pxa27x_clear_otgph() and move the implementation into processor specific code. Signed-off-by: Eric Miao <eric.miao@marvell.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> diff 0f8469a5 Sun Aug 03 08:06:16 MDT 2008 Russell King <rmk@dyn-67.arm.linux.org.uk> [ARM] Eliminate useless includes of asm/mach-types.h There are 43 includes of asm/mach-types.h by files that don't reference anything from that file. Remove these unnecessary includes. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> diff 0c27c5d5 Thu Jun 08 15:44:07 MDT 2006 Richard Purdie <rpurdie@rpsys.net> [ARM] 3547/1: PXA-OHCI: Allow platforms to specify a power budget Patch from Richard Purdie Add a power budget variable to the PXA OHCI platform data and add a default value for the spitz platform(s) which prevents known failures with certain USB devices. Signed-off-by: Richard Purdie <rpurdie@rpsys.net> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> diff 0c0382e3 Thu Oct 13 15:08:02 MDT 2005 Alan Stern <stern@rowland.harvard.edu> [PATCH] USB: Rename hcd->hub_suspend to hcd->bus_suspend This patch (as580) is perhaps the only result from the long discussion I had with David about his changes to the root-hub suspend/resume code. It renames the hub_suspend and hub_resume methods in struct usb_hcd to bus_suspend and bus_resume. These are more descriptive names, since the methods really do suspend or resume an entire USB bus, and less likely to be confused with the hub_suspend and hub_resume routines in hub.c. It also takes David's advice about removing the layer of bus glue, where those methods are called. And it implements a related change that David made to the other HCDs but forgot to put into dummy_hcd. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> diff 0c0382e3 Thu Oct 13 15:08:02 MDT 2005 Alan Stern <stern@rowland.harvard.edu> [PATCH] USB: Rename hcd->hub_suspend to hcd->bus_suspend This patch (as580) is perhaps the only result from the long discussion I had with David about his changes to the root-hub suspend/resume code. It renames the hub_suspend and hub_resume methods in struct usb_hcd to bus_suspend and bus_resume. These are more descriptive names, since the methods really do suspend or resume an entire USB bus, and less likely to be confused with the hub_suspend and hub_resume routines in hub.c. It also takes David's advice about removing the layer of bus glue, where those methods are called. And it implements a related change that David made to the other HCDs but forgot to put into dummy_hcd. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
H A D | ohci-omap.c | diff 903b39e1 Wed Jan 18 01:27:34 MST 2023 Arnd Bergmann <arnd@arndb.de> usb: ohci-omap: avoid unused-variable warning The dead code removal has led to 'need_transceiver' not being used at all when OTG support is disabled: drivers/usb/host/ohci-omap.c: In function 'ohci_omap_reset': drivers/usb/host/ohci-omap.c:99:33: error: unused variable 'need_transceiver' [-Werror=unused-variable] 99 | int need_transceiver = (config->otg != 0); Change the #ifdef check into an IS_ENABLED() check to make the code more readable and let the compiler see where it is used. Fixes: 8825acd7cc8a ("ARM: omap1: remove dead code") Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Arnd Bergmann <arnd@arndb.de> diff 0a3aa0d3 Tue Dec 10 05:25:09 MST 2013 Jingoo Han <jg1.han@samsung.com> USB: ohci-omap: use dev_err() instead of printk() Use dev_err() instead of printk() to provide a better message to userspace. Signed-off-by: Jingoo Han <jg1.han@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff bb1a5805 Sat Aug 04 01:12:00 MDT 2012 Arnd Bergmann <arnd@arndb.de> usb/ohci-omap: remove unused variable Commit c2e935a7d "USB: move transceiver from ehci_hcd and ohci_hcd to hcd and rename it as phy" removed the last use of the "ohci" variable in the usb_hcd_omap_remove function, but left the variable in place unused. Without this patch, building omap1_defconfig results in: In file included from drivers/usb/host/ohci-hcd.c:1013:0: drivers/usb/host/ohci-omap.c: In function 'usb_hcd_omap_remove': drivers/usb/host/ohci-omap.c:406:19: warning: unused variable 'ohci' [-Wunused-variable] Signed-off-by: Arnd Bergmann <arnd@arndb.de> Acked-by: Alan Stern <stern@rowland.harvard.edu> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Richard Zhao <richard.zhao@freescale.com> diff 0c0382e3 Thu Oct 13 15:08:02 MDT 2005 Alan Stern <stern@rowland.harvard.edu> [PATCH] USB: Rename hcd->hub_suspend to hcd->bus_suspend This patch (as580) is perhaps the only result from the long discussion I had with David about his changes to the root-hub suspend/resume code. It renames the hub_suspend and hub_resume methods in struct usb_hcd to bus_suspend and bus_resume. These are more descriptive names, since the methods really do suspend or resume an entire USB bus, and less likely to be confused with the hub_suspend and hub_resume routines in hub.c. It also takes David's advice about removing the layer of bus glue, where those methods are called. And it implements a related change that David made to the other HCDs but forgot to put into dummy_hcd. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> diff 0c0382e3 Thu Oct 13 15:08:02 MDT 2005 Alan Stern <stern@rowland.harvard.edu> [PATCH] USB: Rename hcd->hub_suspend to hcd->bus_suspend This patch (as580) is perhaps the only result from the long discussion I had with David about his changes to the root-hub suspend/resume code. It renames the hub_suspend and hub_resume methods in struct usb_hcd to bus_suspend and bus_resume. These are more descriptive names, since the methods really do suspend or resume an entire USB bus, and less likely to be confused with the hub_suspend and hub_resume routines in hub.c. It also takes David's advice about removing the layer of bus glue, where those methods are called. And it implements a related change that David made to the other HCDs but forgot to put into dummy_hcd. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
H A D | ehci-pci.c | diff 26b75952 Fri Apr 09 02:48:01 MDT 2021 Longfang Liu <liulongfang@huawei.com> USB:ehci:fix Kunpeng920 ehci hardware problem Kunpeng920's EHCI controller does not have SBRN register. Reading the SBRN register when the controller driver is initialized will get 0. When rebooting the EHCI driver, ehci_shutdown() will be called. if the sbrn flag is 0, ehci_shutdown() will return directly. The sbrn flag being 0 will cause the EHCI interrupt signal to not be turned off after reboot. this interrupt that is not closed will cause an exception to the device sharing the interrupt. Therefore, the EHCI controller of Kunpeng920 needs to skip the read operation of the SBRN register. Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Longfang Liu <liulongfang@huawei.com> Link: https://lore.kernel.org/r/1617958081-17999-1-git-send-email-liulongfang@huawei.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff 26b75952 Fri Apr 09 02:48:01 MDT 2021 Longfang Liu <liulongfang@huawei.com> USB:ehci:fix Kunpeng920 ehci hardware problem Kunpeng920's EHCI controller does not have SBRN register. Reading the SBRN register when the controller driver is initialized will get 0. When rebooting the EHCI driver, ehci_shutdown() will be called. if the sbrn flag is 0, ehci_shutdown() will return directly. The sbrn flag being 0 will cause the EHCI interrupt signal to not be turned off after reboot. this interrupt that is not closed will cause an exception to the device sharing the interrupt. Therefore, the EHCI controller of Kunpeng920 needs to skip the read operation of the SBRN register. Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Longfang Liu <liulongfang@huawei.com> Link: https://lore.kernel.org/r/1617958081-17999-1-git-send-email-liulongfang@huawei.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff 26b75952 Fri Apr 09 02:48:01 MDT 2021 Longfang Liu <liulongfang@huawei.com> USB:ehci:fix Kunpeng920 ehci hardware problem Kunpeng920's EHCI controller does not have SBRN register. Reading the SBRN register when the controller driver is initialized will get 0. When rebooting the EHCI driver, ehci_shutdown() will be called. if the sbrn flag is 0, ehci_shutdown() will return directly. The sbrn flag being 0 will cause the EHCI interrupt signal to not be turned off after reboot. this interrupt that is not closed will cause an exception to the device sharing the interrupt. Therefore, the EHCI controller of Kunpeng920 needs to skip the read operation of the SBRN register. Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Longfang Liu <liulongfang@huawei.com> Link: https://lore.kernel.org/r/1617958081-17999-1-git-send-email-liulongfang@huawei.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff 1ddcb71a Sun Jun 07 21:46:59 MDT 2020 Longfang Liu <liulongfang@huawei.com> USB: ehci: reopen solution for Synopsys HC bug A Synopsys USB2.0 core used in Huawei Kunpeng920 SoC has a bug which might cause the host controller not issuing ping. Bug description: After indicating an Interrupt on Async Advance, the software uses the doorbell mechanism to delete the Next Link queue head of the last executed queue head. At this time, the host controller still references the removed queue head(the queue head is NULL). NULL reference causes the host controller to lose the USB device. Solution: After deleting the Next Link queue head, when has_synopsys_hc_bug set to 1,the software can write one of the valid queue head addresses to the ASYNCLISTADDR register to allow the host controller to get the valid queue head. in order to solve that problem, this patch set the flag for Huawei Kunpeng920 There are detailed instructions and solutions in this patch: commit 2f7ac6c19997 ("USB: ehci: add workaround for Synopsys HC bug") Signed-off-by: Longfang Liu <liulongfang@huawei.com> Cc: stable <stable@vger.kernel.org> Acked-by: Alan Stern <stern@rowland.harvard.edu> Link: https://lore.kernel.org/r/1591588019-44284-1-git-send-email-liulongfang@huawei.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff 6e693739 Wed Jul 02 02:58:18 MDT 2014 Bryan O'Donoghue <bryan.odonoghue@intel.com> USB: ehci-pci: USB host controller support for Intel Quark X1000 The EHCI packet buffer in/out threshold is programmable for Intel Quark X1000 USB host controller, and the default value is 0x20 dwords. The in/out threshold can be programmed to 0x80 dwords (512 Bytes) to maximize the perfomrance, but only when isochronous/interrupt transactions are not initiated by the USB host controller. This patch is to reconfigure the packet buffer in/out threshold as maximal as possible to maximize the performance, and 0x7F dwords (508 Bytes) should be used because the USB host controller initiates isochronous/interrupt transactions. Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@intel.com> Signed-off-by: Alvin (Weike) Chen <alvin.chen@intel.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Reviewed-by: Jingoo Han <jg1.han@samsung.com> Cc: stable <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff 6e693739 Wed Jul 02 02:58:18 MDT 2014 Bryan O'Donoghue <bryan.odonoghue@intel.com> USB: ehci-pci: USB host controller support for Intel Quark X1000 The EHCI packet buffer in/out threshold is programmable for Intel Quark X1000 USB host controller, and the default value is 0x20 dwords. The in/out threshold can be programmed to 0x80 dwords (512 Bytes) to maximize the perfomrance, but only when isochronous/interrupt transactions are not initiated by the USB host controller. This patch is to reconfigure the packet buffer in/out threshold as maximal as possible to maximize the performance, and 0x7F dwords (508 Bytes) should be used because the USB host controller initiates isochronous/interrupt transactions. Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@intel.com> Signed-off-by: Alvin (Weike) Chen <alvin.chen@intel.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Reviewed-by: Jingoo Han <jg1.han@samsung.com> Cc: stable <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff 6e693739 Wed Jul 02 02:58:18 MDT 2014 Bryan O'Donoghue <bryan.odonoghue@intel.com> USB: ehci-pci: USB host controller support for Intel Quark X1000 The EHCI packet buffer in/out threshold is programmable for Intel Quark X1000 USB host controller, and the default value is 0x20 dwords. The in/out threshold can be programmed to 0x80 dwords (512 Bytes) to maximize the perfomrance, but only when isochronous/interrupt transactions are not initiated by the USB host controller. This patch is to reconfigure the packet buffer in/out threshold as maximal as possible to maximize the performance, and 0x7F dwords (508 Bytes) should be used because the USB host controller initiates isochronous/interrupt transactions. Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@intel.com> Signed-off-by: Alvin (Weike) Chen <alvin.chen@intel.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Reviewed-by: Jingoo Han <jg1.han@samsung.com> Cc: stable <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff 3ad145b6 Thu Oct 03 09:37:12 MDT 2013 Huang Rui <ray.huang@amd.com> usb: ehci: use amd_chipset_type to filter for usb subsystem hang bug Commit "usb: pci-quirks: refactor AMD quirk to abstract AMD chipset types" introduced a new AMD chipset type to filter AMD platforms with different chipsets. According to a recent thread [1], this patch updates USB subsystem hang symptom quirk which is observed on AMD all SB600 and SB700 revision 0x3a/0x3b. And make it use the new chipset type to represent. [1] http://marc.info/?l=linux-usb&m=138012321616452&w=2 Signed-off-by: Huang Rui <ray.huang@amd.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff 3ad145b6 Thu Oct 03 09:37:12 MDT 2013 Huang Rui <ray.huang@amd.com> usb: ehci: use amd_chipset_type to filter for usb subsystem hang bug Commit "usb: pci-quirks: refactor AMD quirk to abstract AMD chipset types" introduced a new AMD chipset type to filter AMD platforms with different chipsets. According to a recent thread [1], this patch updates USB subsystem hang symptom quirk which is observed on AMD all SB600 and SB700 revision 0x3a/0x3b. And make it use the new chipset type to represent. [1] http://marc.info/?l=linux-usb&m=138012321616452&w=2 Signed-off-by: Huang Rui <ray.huang@amd.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff 75e1a2ae Wed Dec 19 09:15:56 MST 2012 Jan Beulich <JBeulich@suse.com> USB: ehci: make debug port in-use detection functional again Debug port in-use determination must be done before the controller gets reset the first time, i.e. before the call to ehci_setup() as of commit 1a49e2ac9651df7349867a5cf44e2c83de1046af. That commit effectively rendered commit 9fa5780beea1274d498a224822397100022da7d4 useless. While moving that code around, also fix the BAR determination - the respective capability field is a 3- rather than a 2-bit one -, and use PCI_CAP_ID_DBG instead of the literal 0x0a. It's unclear to me whether the debug port functionality is important enough to warrant fixing this in stable kernels too. Signed-off-by: Jan Beulich <jbeulich@suse.com> Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Cc: stable <stable@vger.kernel.org> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
H A D | ohci-hub.c | diff c1db30a2 Thu May 01 13:21:42 MDT 2014 Alan Stern <stern@rowland.harvard.edu> USB: OHCI: fix problem with global suspend on ATI controllers Some OHCI controllers from ATI/AMD seem to have difficulty with "global" USB suspend, that is, suspending an entire USB bus without setting the suspend feature for each port connected to a device. When we try to resume the child devices, the controller gives timeout errors on the unsuspended ports, requiring resets, and can even cause ohci-hcd to hang; see http://marc.info/?l=linux-usb&m=139514332820398&w=2 and the following messages. This patch fixes the problem by adding a new quirk flag to ohci-hcd. The flag causes the ohci_rh_suspend() routine to suspend each unsuspended, enabled port before suspending the root hub. This effectively converts the "global" suspend to an ordinary root-hub suspend. There is no need to unsuspend these ports when the root hub is resumed, because the child devices will be resumed anyway in the course of a normal system resume ("global" suspend is never used for runtime PM). This patch should be applied to all stable kernels which include commit 0aa2832dd0d9 (USB: use "global suspend" for system sleep on USB-2 buses) or a backported version thereof. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Reported-by: Peter Münster <pmlists@free.fr> Tested-by: Peter Münster <pmlists@free.fr> CC: <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff 0c0382e3 Thu Oct 13 15:08:02 MDT 2005 Alan Stern <stern@rowland.harvard.edu> [PATCH] USB: Rename hcd->hub_suspend to hcd->bus_suspend This patch (as580) is perhaps the only result from the long discussion I had with David about his changes to the root-hub suspend/resume code. It renames the hub_suspend and hub_resume methods in struct usb_hcd to bus_suspend and bus_resume. These are more descriptive names, since the methods really do suspend or resume an entire USB bus, and less likely to be confused with the hub_suspend and hub_resume routines in hub.c. It also takes David's advice about removing the layer of bus glue, where those methods are called. And it implements a related change that David made to the other HCDs but forgot to put into dummy_hcd. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> diff 0c0382e3 Thu Oct 13 15:08:02 MDT 2005 Alan Stern <stern@rowland.harvard.edu> [PATCH] USB: Rename hcd->hub_suspend to hcd->bus_suspend This patch (as580) is perhaps the only result from the long discussion I had with David about his changes to the root-hub suspend/resume code. It renames the hub_suspend and hub_resume methods in struct usb_hcd to bus_suspend and bus_resume. These are more descriptive names, since the methods really do suspend or resume an entire USB bus, and less likely to be confused with the hub_suspend and hub_resume routines in hub.c. It also takes David's advice about removing the layer of bus glue, where those methods are called. And it implements a related change that David made to the other HCDs but forgot to put into dummy_hcd. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
H A D | uhci-hcd.c | diff dc54ce3e Sun May 21 16:50:42 MDT 2023 Niklas Schnelle <schnelle@linux.ibm.com> usb: uhci: handle HAS_IOPORT dependencies In a future patch HAS_IOPORT=n will result in inb()/outb() and friends not being declared. We thus need to guard sections of code calling them as alternative access methods with CONFIG_HAS_IOPORT checks. For uhci-hcd there are a lot of I/O port uses that do have MMIO alternatives all selected by uhci_has_pci_registers() so this can be handled by UHCI_IN/OUT macros and making uhci_has_pci_registers() constant 0 if CONFIG_HAS_IOPORT is unset. Co-developed-by: Arnd Bergmann <arnd@kernel.org> Signed-off-by: Arnd Bergmann <arnd@kernel.org> Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com> Reviewed-by: Alan Stern <stern@rowland.harvard.edu> Link: https://lore.kernel.org/r/20230522105049.1467313-38-schnelle@linux.ibm.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff 0a3f82c7 Thu Feb 02 08:32:25 MST 2023 Greg Kroah-Hartman <gregkh@linuxfoundation.org> USB: uhci: fix memory leak with using debugfs_lookup() When calling debugfs_lookup() the result must have dput() called on it, otherwise the memory will leak over time. To make things simpler, just call debugfs_lookup_and_remove() instead which handles all of the logic at once. Cc: Alan Stern <stern@rowland.harvard.edu> Link: https://lore.kernel.org/r/20230202153235.2412790-3-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff 2b80a29b Sat Dec 30 13:03:52 MST 2017 Himanshu Jha <himanshujha199640@gmail.com> USB: host: Use zeroing memory allocator rather than allocator/memset Use dma_zalloc_coherent for allocating zeroed memory and remove unnecessary memset function. Done using Coccinelle. Generated-by: scripts/coccinelle/api/alloc/kzalloc-simple.cocci 0-day tested with no failures. Suggested-by: Luis R. Rodriguez <mcgrof@kernel.org> Signed-off-by: Himanshu Jha <himanshujha199640@gmail.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Acked-by: Mathias Nyman <mathias.nyman@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> |
H A D | sl811-hcd.c | diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> diff e99e88a9 Mon Oct 16 15:43:17 MDT 2017 Kees Cook <keescook@chromium.org> treewide: setup_timer() -> timer_setup() This converts all remaining cases of the old setup_timer() API into using timer_setup(), where the callback argument is the structure already holding the struct timer_list. These should have no behavioral changes, since they just change which pointer is passed into the callback with the same available pointers after conversion. It handles the following examples, in addition to some other variations. Casting from unsigned long: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... setup_timer(&ptr->my_timer, my_callback, ptr); and forced object casts: void my_callback(struct something *ptr) { ... } ... setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr); become: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... timer_setup(&ptr->my_timer, my_callback, 0); Direct function assignments: void my_callback(unsigned long data) { struct something *ptr = (struct something *)data; ... } ... ptr->my_timer.function = my_callback; have a temporary cast added, along with converting the args: void my_callback(struct timer_list *t) { struct something *ptr = from_timer(ptr, t, my_timer); ... } ... ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback; And finally, callbacks without a data assignment: void my_callback(unsigned long data) { ... } ... setup_timer(&ptr->my_timer, my_callback, 0); have their argument renamed to verify they're unused during conversion: void my_callback(struct timer_list *unused) { ... } ... timer_setup(&ptr->my_timer, my_callback, 0); The conversion is done with the following Coccinelle script: spatch --very-quiet --all-includes --include-headers \ -I ./arch/x86/include -I ./arch/x86/include/generated \ -I ./include -I ./arch/x86/include/uapi \ -I ./arch/x86/include/generated/uapi -I ./include/uapi \ -I ./include/generated/uapi --include ./include/linux/kconfig.h \ --dir . \ --cocci-file ~/src/data/timer_setup.cocci @fix_address_of@ expression e; @@ setup_timer( -&(e) +&e , ...) // Update any raw setup_timer() usages that have a NULL callback, but // would otherwise match change_timer_function_usage, since the latter // will update all function assignments done in the face of a NULL // function initialization in setup_timer(). @change_timer_function_usage_NULL@ expression _E; identifier _timer; type _cast_data; @@ ( -setup_timer(&_E->_timer, NULL, _E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E->_timer, NULL, (_cast_data)_E); +timer_setup(&_E->_timer, NULL, 0); | -setup_timer(&_E._timer, NULL, &_E); +timer_setup(&_E._timer, NULL, 0); | -setup_timer(&_E._timer, NULL, (_cast_data)&_E); +timer_setup(&_E._timer, NULL, 0); ) @change_timer_function_usage@ expression _E; identifier _timer; struct timer_list _stl; identifier _callback; type _cast_func, _cast_data; @@ ( -setup_timer(&_E->_timer, _callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, &_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, _E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, &_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E); +timer_setup(&_E._timer, _callback, 0); | _E->_timer@_stl.function = _callback; | _E->_timer@_stl.function = &_callback; | _E->_timer@_stl.function = (_cast_func)_callback; | _E->_timer@_stl.function = (_cast_func)&_callback; | _E._timer@_stl.function = _callback; | _E._timer@_stl.function = &_callback; | _E._timer@_stl.function = (_cast_func)_callback; | _E._timer@_stl.function = (_cast_func)&_callback; ) // callback(unsigned long arg) @change_callback_handle_cast depends on change_timer_function_usage@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; identifier _handle; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { ( ... when != _origarg _handletype *_handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(_handletype *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg | ... when != _origarg _handletype *_handle; ... when != _handle _handle = -(void *)_origarg; +from_timer(_handle, t, _timer); ... when != _origarg ) } // callback(unsigned long arg) without existing variable @change_callback_handle_cast_no_arg depends on change_timer_function_usage && !change_callback_handle_cast@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _origtype; identifier _origarg; type _handletype; @@ void _callback( -_origtype _origarg +struct timer_list *t ) { + _handletype *_origarg = from_timer(_origarg, t, _timer); + ... when != _origarg - (_handletype *)_origarg + _origarg ... when != _origarg } // Avoid already converted callbacks. @match_callback_converted depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier t; @@ void _callback(struct timer_list *t) { ... } // callback(struct something *handle) @change_callback_handle_arg depends on change_timer_function_usage && !match_callback_converted && !change_callback_handle_cast && !change_callback_handle_cast_no_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; @@ void _callback( -_handletype *_handle +struct timer_list *t ) { + _handletype *_handle = from_timer(_handle, t, _timer); ... } // If change_callback_handle_arg ran on an empty function, remove // the added handler. @unchange_callback_handle_arg depends on change_timer_function_usage && change_callback_handle_arg@ identifier change_timer_function_usage._callback; identifier change_timer_function_usage._timer; type _handletype; identifier _handle; identifier t; @@ void _callback(struct timer_list *t) { - _handletype *_handle = from_timer(_handle, t, _timer); } // We only want to refactor the setup_timer() data argument if we've found // the matching callback. This undoes changes in change_timer_function_usage. @unchange_timer_function_usage depends on change_timer_function_usage && !change_callback_handle_cast && !change_callback_handle_cast_no_arg && !change_callback_handle_arg@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type change_timer_function_usage._cast_data; @@ ( -timer_setup(&_E->_timer, _callback, 0); +setup_timer(&_E->_timer, _callback, (_cast_data)_E); | -timer_setup(&_E._timer, _callback, 0); +setup_timer(&_E._timer, _callback, (_cast_data)&_E); ) // If we fixed a callback from a .function assignment, fix the // assignment cast now. @change_timer_function_assignment depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression change_timer_function_usage._E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_func; typedef TIMER_FUNC_TYPE; @@ ( _E->_timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -&_callback +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)_callback; +(TIMER_FUNC_TYPE)_callback ; | _E->_timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -&_callback; +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)_callback +(TIMER_FUNC_TYPE)_callback ; | _E._timer.function = -(_cast_func)&_callback +(TIMER_FUNC_TYPE)_callback ; ) // Sometimes timer functions are called directly. Replace matched args. @change_timer_function_calls depends on change_timer_function_usage && (change_callback_handle_cast || change_callback_handle_cast_no_arg || change_callback_handle_arg)@ expression _E; identifier change_timer_function_usage._timer; identifier change_timer_function_usage._callback; type _cast_data; @@ _callback( ( -(_cast_data)_E +&_E->_timer | -(_cast_data)&_E +&_E._timer | -_E +&_E->_timer ) ) // If a timer has been configured without a data argument, it can be // converted without regard to the callback argument, since it is unused. @match_timer_function_unused_data@ expression _E; identifier _timer; identifier _callback; @@ ( -setup_timer(&_E->_timer, _callback, 0); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0L); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E->_timer, _callback, 0UL); +timer_setup(&_E->_timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0L); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_E._timer, _callback, 0UL); +timer_setup(&_E._timer, _callback, 0); | -setup_timer(&_timer, _callback, 0); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0L); +timer_setup(&_timer, _callback, 0); | -setup_timer(&_timer, _callback, 0UL); +timer_setup(&_timer, _callback, 0); | -setup_timer(_timer, _callback, 0); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0L); +timer_setup(_timer, _callback, 0); | -setup_timer(_timer, _callback, 0UL); +timer_setup(_timer, _callback, 0); ) @change_callback_unused_data depends on match_timer_function_unused_data@ identifier match_timer_function_unused_data._callback; type _origtype; identifier _origarg; @@ void _callback( -_origtype _origarg +struct timer_list *unused ) { ... when != _origarg } Signed-off-by: Kees Cook <keescook@chromium.org> |
H A D | ehci-hub.c | diff 85e3990b Thu May 19 14:29:50 MDT 2016 Alan Stern <stern@rowland.harvard.edu> USB: EHCI: avoid undefined pointer arithmetic and placate UBSAN Several people have reported that UBSAN doesn't like the pointer arithmetic in ehci_hub_control(): u32 __iomem *status_reg = &ehci->regs->port_status[ (wIndex & 0xff) - 1]; u32 __iomem *hostpc_reg = &ehci->regs->hostpc[(wIndex & 0xff) - 1]; If wIndex is 0 (and it often is), these calculations underflow and UBSAN complains. According to the C standard, pointer computations leading to locations outside the bounds of an array object (other than 1 position past the end) are undefined. In this case, the compiler would be justified in concluding the wIndex can never be 0 and then optimizing away the tests for !wIndex that occur later in the subroutine. (Although, since ehci->regs->port_status and ehci->regs->hostpc are both 0-length arrays and are thus GCC extensions to the C standard, it's not clear what the compiler is really allowed to do.) At any rate, we can avoid all these difficulties, at the cost of making the code slightly longer, by not decrementing the index when it is equal to 0. The runtime effect is minimal, and anyway ehci_hub_control() is not on a hot path. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Reported-by: Valdis Kletnieks <Valdis.Kletnieks@vt.edu> Reported-by: Meelis Roos <mroos@linux.ee> Reported-by: Martin_MOKREJÅ <mmokrejs@gmail.com> Reported-by: "Navin P.S" <navinp1912@gmail.com> CC: Andrey Ryabinin <ryabinin.a.a@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff 85e3990b Thu May 19 14:29:50 MDT 2016 Alan Stern <stern@rowland.harvard.edu> USB: EHCI: avoid undefined pointer arithmetic and placate UBSAN Several people have reported that UBSAN doesn't like the pointer arithmetic in ehci_hub_control(): u32 __iomem *status_reg = &ehci->regs->port_status[ (wIndex & 0xff) - 1]; u32 __iomem *hostpc_reg = &ehci->regs->hostpc[(wIndex & 0xff) - 1]; If wIndex is 0 (and it often is), these calculations underflow and UBSAN complains. According to the C standard, pointer computations leading to locations outside the bounds of an array object (other than 1 position past the end) are undefined. In this case, the compiler would be justified in concluding the wIndex can never be 0 and then optimizing away the tests for !wIndex that occur later in the subroutine. (Although, since ehci->regs->port_status and ehci->regs->hostpc are both 0-length arrays and are thus GCC extensions to the C standard, it's not clear what the compiler is really allowed to do.) At any rate, we can avoid all these difficulties, at the cost of making the code slightly longer, by not decrementing the index when it is equal to 0. The runtime effect is minimal, and anyway ehci_hub_control() is not on a hot path. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Reported-by: Valdis Kletnieks <Valdis.Kletnieks@vt.edu> Reported-by: Meelis Roos <mroos@linux.ee> Reported-by: Martin_MOKREJÅ <mmokrejs@gmail.com> Reported-by: "Navin P.S" <navinp1912@gmail.com> CC: Andrey Ryabinin <ryabinin.a.a@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff 85e3990b Thu May 19 14:29:50 MDT 2016 Alan Stern <stern@rowland.harvard.edu> USB: EHCI: avoid undefined pointer arithmetic and placate UBSAN Several people have reported that UBSAN doesn't like the pointer arithmetic in ehci_hub_control(): u32 __iomem *status_reg = &ehci->regs->port_status[ (wIndex & 0xff) - 1]; u32 __iomem *hostpc_reg = &ehci->regs->hostpc[(wIndex & 0xff) - 1]; If wIndex is 0 (and it often is), these calculations underflow and UBSAN complains. According to the C standard, pointer computations leading to locations outside the bounds of an array object (other than 1 position past the end) are undefined. In this case, the compiler would be justified in concluding the wIndex can never be 0 and then optimizing away the tests for !wIndex that occur later in the subroutine. (Although, since ehci->regs->port_status and ehci->regs->hostpc are both 0-length arrays and are thus GCC extensions to the C standard, it's not clear what the compiler is really allowed to do.) At any rate, we can avoid all these difficulties, at the cost of making the code slightly longer, by not decrementing the index when it is equal to 0. The runtime effect is minimal, and anyway ehci_hub_control() is not on a hot path. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Reported-by: Valdis Kletnieks <Valdis.Kletnieks@vt.edu> Reported-by: Meelis Roos <mroos@linux.ee> Reported-by: Martin_MOKREJÅ <mmokrejs@gmail.com> Reported-by: "Navin P.S" <navinp1912@gmail.com> CC: Andrey Ryabinin <ryabinin.a.a@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff 85e3990b Thu May 19 14:29:50 MDT 2016 Alan Stern <stern@rowland.harvard.edu> USB: EHCI: avoid undefined pointer arithmetic and placate UBSAN Several people have reported that UBSAN doesn't like the pointer arithmetic in ehci_hub_control(): u32 __iomem *status_reg = &ehci->regs->port_status[ (wIndex & 0xff) - 1]; u32 __iomem *hostpc_reg = &ehci->regs->hostpc[(wIndex & 0xff) - 1]; If wIndex is 0 (and it often is), these calculations underflow and UBSAN complains. According to the C standard, pointer computations leading to locations outside the bounds of an array object (other than 1 position past the end) are undefined. In this case, the compiler would be justified in concluding the wIndex can never be 0 and then optimizing away the tests for !wIndex that occur later in the subroutine. (Although, since ehci->regs->port_status and ehci->regs->hostpc are both 0-length arrays and are thus GCC extensions to the C standard, it's not clear what the compiler is really allowed to do.) At any rate, we can avoid all these difficulties, at the cost of making the code slightly longer, by not decrementing the index when it is equal to 0. The runtime effect is minimal, and anyway ehci_hub_control() is not on a hot path. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Reported-by: Valdis Kletnieks <Valdis.Kletnieks@vt.edu> Reported-by: Meelis Roos <mroos@linux.ee> Reported-by: Martin_MOKREJÅ <mmokrejs@gmail.com> Reported-by: "Navin P.S" <navinp1912@gmail.com> CC: Andrey Ryabinin <ryabinin.a.a@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff 85e3990b Thu May 19 14:29:50 MDT 2016 Alan Stern <stern@rowland.harvard.edu> USB: EHCI: avoid undefined pointer arithmetic and placate UBSAN Several people have reported that UBSAN doesn't like the pointer arithmetic in ehci_hub_control(): u32 __iomem *status_reg = &ehci->regs->port_status[ (wIndex & 0xff) - 1]; u32 __iomem *hostpc_reg = &ehci->regs->hostpc[(wIndex & 0xff) - 1]; If wIndex is 0 (and it often is), these calculations underflow and UBSAN complains. According to the C standard, pointer computations leading to locations outside the bounds of an array object (other than 1 position past the end) are undefined. In this case, the compiler would be justified in concluding the wIndex can never be 0 and then optimizing away the tests for !wIndex that occur later in the subroutine. (Although, since ehci->regs->port_status and ehci->regs->hostpc are both 0-length arrays and are thus GCC extensions to the C standard, it's not clear what the compiler is really allowed to do.) At any rate, we can avoid all these difficulties, at the cost of making the code slightly longer, by not decrementing the index when it is equal to 0. The runtime effect is minimal, and anyway ehci_hub_control() is not on a hot path. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Reported-by: Valdis Kletnieks <Valdis.Kletnieks@vt.edu> Reported-by: Meelis Roos <mroos@linux.ee> Reported-by: Martin_MOKREJÅ <mmokrejs@gmail.com> Reported-by: "Navin P.S" <navinp1912@gmail.com> CC: Andrey Ryabinin <ryabinin.a.a@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff 85e3990b Thu May 19 14:29:50 MDT 2016 Alan Stern <stern@rowland.harvard.edu> USB: EHCI: avoid undefined pointer arithmetic and placate UBSAN Several people have reported that UBSAN doesn't like the pointer arithmetic in ehci_hub_control(): u32 __iomem *status_reg = &ehci->regs->port_status[ (wIndex & 0xff) - 1]; u32 __iomem *hostpc_reg = &ehci->regs->hostpc[(wIndex & 0xff) - 1]; If wIndex is 0 (and it often is), these calculations underflow and UBSAN complains. According to the C standard, pointer computations leading to locations outside the bounds of an array object (other than 1 position past the end) are undefined. In this case, the compiler would be justified in concluding the wIndex can never be 0 and then optimizing away the tests for !wIndex that occur later in the subroutine. (Although, since ehci->regs->port_status and ehci->regs->hostpc are both 0-length arrays and are thus GCC extensions to the C standard, it's not clear what the compiler is really allowed to do.) At any rate, we can avoid all these difficulties, at the cost of making the code slightly longer, by not decrementing the index when it is equal to 0. The runtime effect is minimal, and anyway ehci_hub_control() is not on a hot path. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Reported-by: Valdis Kletnieks <Valdis.Kletnieks@vt.edu> Reported-by: Meelis Roos <mroos@linux.ee> Reported-by: Martin_MOKREJÅ <mmokrejs@gmail.com> Reported-by: "Navin P.S" <navinp1912@gmail.com> CC: Andrey Ryabinin <ryabinin.a.a@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff 5cbcc35e Mon Aug 04 18:28:19 MDT 2014 Peter Chen <peter.chen@freescale.com> usb: ehci: using wIndex + 1 for hub port The roothub's index per controller is from 0, but the hub port index per hub is from 1, this patch fixes "can't find device at roohub" problem for connecting test fixture at roohub when do USB-IF Embedded Host High-Speed Electrical Test. This patch is for v3.12+. Cc: stable@vger.kernel.org Signed-off-by: Peter Chen <peter.chen@freescale.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff 9841f37a Thu Aug 08 17:49:24 MDT 2013 Manu Gautam <mgautam@codeaurora.org> usb: ehci: Add support for SINGLE_STEP_SET_FEATURE test of EHSET The USB Embedded High-speed Host Electrical Test (EHSET) defines the SINGLE_STEP_SET_FEATURE test as follows: 1) The host enumerates the test device with VID:0x1A0A, PID:0x0108 2) The host sends the SETUP stage of a GetDescriptor(Device) 3) The device ACKs the request 4) The host issues SOFs for 15 seconds allowing the test operator to raise the scope trigger just above the SOF voltage level 5) The host sends the IN packet 6) The device sends data in response, triggering the scope 7) The host sends an ACK in response to the data This patch adds additional handling to the EHCI hub driver and allows the EHSET driver to initiate this test mode by issuing a a SetFeature request to the root hub with a Test Selector value of 0x06. From there it mimics ehci_urb_enqueue() but separately submits QTDs for the SETUP and DATA/STATUS stages in order to insert a delay in between. Signed-off-by: Manu Gautam <mgautam@codeaurora.org> Acked-by: Alan Stern <stern@rowland.harvard.edu> [jackp@codeaurora.org: imported from commit c2084930 on codeaurora.org; minor cleanup and updated author email] Signed-off-by: Jack Pham <jackp@codeaurora.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff 9841f37a Thu Aug 08 17:49:24 MDT 2013 Manu Gautam <mgautam@codeaurora.org> usb: ehci: Add support for SINGLE_STEP_SET_FEATURE test of EHSET The USB Embedded High-speed Host Electrical Test (EHSET) defines the SINGLE_STEP_SET_FEATURE test as follows: 1) The host enumerates the test device with VID:0x1A0A, PID:0x0108 2) The host sends the SETUP stage of a GetDescriptor(Device) 3) The device ACKs the request 4) The host issues SOFs for 15 seconds allowing the test operator to raise the scope trigger just above the SOF voltage level 5) The host sends the IN packet 6) The device sends data in response, triggering the scope 7) The host sends an ACK in response to the data This patch adds additional handling to the EHCI hub driver and allows the EHSET driver to initiate this test mode by issuing a a SetFeature request to the root hub with a Test Selector value of 0x06. From there it mimics ehci_urb_enqueue() but separately submits QTDs for the SETUP and DATA/STATUS stages in order to insert a delay in between. Signed-off-by: Manu Gautam <mgautam@codeaurora.org> Acked-by: Alan Stern <stern@rowland.harvard.edu> [jackp@codeaurora.org: imported from commit c2084930 on codeaurora.org; minor cleanup and updated author email] Signed-off-by: Jack Pham <jackp@codeaurora.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff 9841f37a Thu Aug 08 17:49:24 MDT 2013 Manu Gautam <mgautam@codeaurora.org> usb: ehci: Add support for SINGLE_STEP_SET_FEATURE test of EHSET The USB Embedded High-speed Host Electrical Test (EHSET) defines the SINGLE_STEP_SET_FEATURE test as follows: 1) The host enumerates the test device with VID:0x1A0A, PID:0x0108 2) The host sends the SETUP stage of a GetDescriptor(Device) 3) The device ACKs the request 4) The host issues SOFs for 15 seconds allowing the test operator to raise the scope trigger just above the SOF voltage level 5) The host sends the IN packet 6) The device sends data in response, triggering the scope 7) The host sends an ACK in response to the data This patch adds additional handling to the EHCI hub driver and allows the EHSET driver to initiate this test mode by issuing a a SetFeature request to the root hub with a Test Selector value of 0x06. From there it mimics ehci_urb_enqueue() but separately submits QTDs for the SETUP and DATA/STATUS stages in order to insert a delay in between. Signed-off-by: Manu Gautam <mgautam@codeaurora.org> Acked-by: Alan Stern <stern@rowland.harvard.edu> [jackp@codeaurora.org: imported from commit c2084930 on codeaurora.org; minor cleanup and updated author email] Signed-off-by: Jack Pham <jackp@codeaurora.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
/linux-master/drivers/usb/core/ | ||
H A D | hcd.c | diff 9013d8fc Wed Aug 24 14:31:07 MDT 2022 Khalid Masum <khalid.masum.92@gmail.com> usb: host: Initiate urb ep with udev ep0 Currently we look up for endpoint in a table and initate urb endpoint with it. This is unnecessary because the lookup will always result in endpoint 0. Suggested-by: Alan Stern <stern@rowland.harvard.edu> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Khalid Masum <khalid.masum.92@gmail.com> Link: https://lore.kernel.org/r/20220824203107.14908-1-khalid.masum.92@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff 4dce3b37 Fri Aug 19 00:07:48 MDT 2022 Jack Wang <jinpu.wang@ionos.com> usb/hcd: Fix dma_map_sg error check dma_map_sg return 0 on error. Cc: Alan Stern <stern@rowland.harvard.edu> Cc: Kishon Vijay Abraham I <kishon@ti.com> Cc: Alexey Sheplyakov <asheplyakov@basealt.ru> Cc: Stephen Boyd <swboyd@chromium.org> Cc: Weitao Wang <WeitaoWang-oc@zhaoxin.com> Cc: Matthias Kaehlcke <mka@chromium.org> Cc: Arnd Bergmann <arnd@arndb.de> Cc: linux-usb@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Jack Wang <jinpu.wang@ionos.com> Link: https://lore.kernel.org/r/20220819060801.10443-7-jinpu.wang@ionos.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff d7de14d7 Fri Jul 22 08:17:00 MDT 2022 Alexey Sheplyakov <asheplyakov@basealt.ru> usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov <asheplyakov@basealt.ru> Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
H A D | hub.c | diff 12783c0b Wed Jan 10 02:58:14 MST 2024 Udipto Goswami <quic_ugoswami@quicinc.com> usb: core: Prevent null pointer dereference in update_port_device_state Currently, the function update_port_device_state gets the usb_hub from udev->parent by calling usb_hub_to_struct_hub. However, in case the actconfig or the maxchild is 0, the usb_hub would be NULL and upon further accessing to get port_dev would result in null pointer dereference. Fix this by introducing an if check after the usb_hub is populated. Fixes: 83cb2604f641 ("usb: core: add sysfs entry for usb device state") Cc: stable@vger.kernel.org Signed-off-by: Udipto Goswami <quic_ugoswami@quicinc.com> Reviewed-by: Alan Stern <stern@rowland.harvard.edu> Link: https://lore.kernel.org/r/20240110095814.7626-1-quic_ugoswami@quicinc.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff 5a1ccf0c Fri Oct 27 09:20:29 MDT 2023 Hardik Gajjar <hgajjar@de.adit-jv.com> usb: new quirk to reduce the SET_ADDRESS request timeout This patch introduces a new USB quirk, USB_QUIRK_SHORT_SET_ADDRESS_REQ_TIMEOUT, which modifies the timeout value for the SET_ADDRESS request. The standard timeout for USB request/command is 5000 ms, as recommended in the USB 3.2 specification (section 9.2.6.1). However, certain scenarios, such as connecting devices through an APTIV hub, can lead to timeout errors when the device enumerates as full speed initially and later switches to high speed during chirp negotiation. In such cases, USB analyzer logs reveal that the bus suspends for 5 seconds due to incorrect chirp parsing and resumes only after two consecutive timeout errors trigger a hub driver reset. Packet(54) Dir(?) Full Speed J(997.100 us) Idle( 2.850 us) _______| Time Stamp(28 . 105 910 682) _______|_____________________________________________________________Ch0 Packet(55) Dir(?) Full Speed J(997.118 us) Idle( 2.850 us) _______| Time Stamp(28 . 106 910 632) _______|_____________________________________________________________Ch0 Packet(56) Dir(?) Full Speed J(399.650 us) Idle(222.582 us) _______| Time Stamp(28 . 107 910 600) _______|_____________________________________________________________Ch0 Packet(57) Dir Chirp J( 23.955 ms) Idle(115.169 ms) _______| Time Stamp(28 . 108 532 832) _______|_____________________________________________________________Ch0 Packet(58) Dir(?) Full Speed J (Suspend)( 5.347 sec) Idle( 5.366 us) _______| Time Stamp(28 . 247 657 600) _______|_____________________________________________________________Ch0 This 5-second delay in device enumeration is undesirable, particularly in automotive applications where quick enumeration is crucial (ideally within 3 seconds). The newly introduced quirks provide the flexibility to align with a 3-second time limit, as required in specific contexts like automotive applications. By reducing the SET_ADDRESS request timeout to 500 ms, the system can respond more swiftly to errors, initiate rapid recovery, and ensure efficient device enumeration. This change is vital for scenarios where rapid smartphone enumeration and screen projection are essential. To use the quirk, please write "vendor_id:product_id:p" to /sys/bus/usb/drivers/hub/module/parameter/quirks For example, echo "0x2c48:0x0132:p" > /sys/bus/usb/drivers/hub/module/parameters/quirks" Signed-off-by: Hardik Gajjar <hgajjar@de.adit-jv.com> Reviewed-by: Alan Stern <stern@rowland.harvard.edu> Link: https://lore.kernel.org/r/20231027152029.104363-2-hgajjar@de.adit-jv.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff 5a1ccf0c Fri Oct 27 09:20:29 MDT 2023 Hardik Gajjar <hgajjar@de.adit-jv.com> usb: new quirk to reduce the SET_ADDRESS request timeout This patch introduces a new USB quirk, USB_QUIRK_SHORT_SET_ADDRESS_REQ_TIMEOUT, which modifies the timeout value for the SET_ADDRESS request. The standard timeout for USB request/command is 5000 ms, as recommended in the USB 3.2 specification (section 9.2.6.1). However, certain scenarios, such as connecting devices through an APTIV hub, can lead to timeout errors when the device enumerates as full speed initially and later switches to high speed during chirp negotiation. In such cases, USB analyzer logs reveal that the bus suspends for 5 seconds due to incorrect chirp parsing and resumes only after two consecutive timeout errors trigger a hub driver reset. Packet(54) Dir(?) Full Speed J(997.100 us) Idle( 2.850 us) _______| Time Stamp(28 . 105 910 682) _______|_____________________________________________________________Ch0 Packet(55) Dir(?) Full Speed J(997.118 us) Idle( 2.850 us) _______| Time Stamp(28 . 106 910 632) _______|_____________________________________________________________Ch0 Packet(56) Dir(?) Full Speed J(399.650 us) Idle(222.582 us) _______| Time Stamp(28 . 107 910 600) _______|_____________________________________________________________Ch0 Packet(57) Dir Chirp J( 23.955 ms) Idle(115.169 ms) _______| Time Stamp(28 . 108 532 832) _______|_____________________________________________________________Ch0 Packet(58) Dir(?) Full Speed J (Suspend)( 5.347 sec) Idle( 5.366 us) _______| Time Stamp(28 . 247 657 600) _______|_____________________________________________________________Ch0 This 5-second delay in device enumeration is undesirable, particularly in automotive applications where quick enumeration is crucial (ideally within 3 seconds). The newly introduced quirks provide the flexibility to align with a 3-second time limit, as required in specific contexts like automotive applications. By reducing the SET_ADDRESS request timeout to 500 ms, the system can respond more swiftly to errors, initiate rapid recovery, and ensure efficient device enumeration. This change is vital for scenarios where rapid smartphone enumeration and screen projection are essential. To use the quirk, please write "vendor_id:product_id:p" to /sys/bus/usb/drivers/hub/module/parameter/quirks For example, echo "0x2c48:0x0132:p" > /sys/bus/usb/drivers/hub/module/parameters/quirks" Signed-off-by: Hardik Gajjar <hgajjar@de.adit-jv.com> Reviewed-by: Alan Stern <stern@rowland.harvard.edu> Link: https://lore.kernel.org/r/20231027152029.104363-2-hgajjar@de.adit-jv.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff f74a7afc Tue Aug 29 16:04:18 MDT 2023 Ricardo Cañuelo <ricardo.canuelo@collabora.com> usb: hub: Guard against accesses to uninitialized BOS descriptors Many functions in drivers/usb/core/hub.c and drivers/usb/core/hub.h access fields inside udev->bos without checking if it was allocated and initialized. If usb_get_bos_descriptor() fails for whatever reason, udev->bos will be NULL and those accesses will result in a crash: BUG: kernel NULL pointer dereference, address: 0000000000000018 PGD 0 P4D 0 Oops: 0000 [#1] PREEMPT SMP NOPTI CPU: 5 PID: 17818 Comm: kworker/5:1 Tainted: G W 5.15.108-18910-gab0e1cb584e1 #1 <HASH:1f9e 1> Hardware name: Google Kindred/Kindred, BIOS Google_Kindred.12672.413.0 02/03/2021 Workqueue: usb_hub_wq hub_event RIP: 0010:hub_port_reset+0x193/0x788 Code: 89 f7 e8 20 f7 15 00 48 8b 43 08 80 b8 96 03 00 00 03 75 36 0f b7 88 92 03 00 00 81 f9 10 03 00 00 72 27 48 8b 80 a8 03 00 00 <48> 83 78 18 00 74 19 48 89 df 48 8b 75 b0 ba 02 00 00 00 4c 89 e9 RSP: 0018:ffffab740c53fcf8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffffa1bc5f678000 RCX: 0000000000000310 RDX: fffffffffffffdff RSI: 0000000000000286 RDI: ffffa1be9655b840 RBP: ffffab740c53fd70 R08: 00001b7d5edaa20c R09: ffffffffb005e060 R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000000 R13: ffffab740c53fd3e R14: 0000000000000032 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffffa1be96540000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000018 CR3: 000000022e80c005 CR4: 00000000003706e0 Call Trace: hub_event+0x73f/0x156e ? hub_activate+0x5b7/0x68f process_one_work+0x1a2/0x487 worker_thread+0x11a/0x288 kthread+0x13a/0x152 ? process_one_work+0x487/0x487 ? kthread_associate_blkcg+0x70/0x70 ret_from_fork+0x1f/0x30 Fall back to a default behavior if the BOS descriptor isn't accessible and skip all the functionalities that depend on it: LPM support checks, Super Speed capabilitiy checks, U1/U2 states setup. Signed-off-by: Ricardo Cañuelo <ricardo.canuelo@collabora.com> Cc: stable <stable@vger.kernel.org> Link: https://lore.kernel.org/r/20230830100418.1952143-1-ricardo.canuelo@collabora.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff f74a7afc Tue Aug 29 16:04:18 MDT 2023 Ricardo Cañuelo <ricardo.canuelo@collabora.com> usb: hub: Guard against accesses to uninitialized BOS descriptors Many functions in drivers/usb/core/hub.c and drivers/usb/core/hub.h access fields inside udev->bos without checking if it was allocated and initialized. If usb_get_bos_descriptor() fails for whatever reason, udev->bos will be NULL and those accesses will result in a crash: BUG: kernel NULL pointer dereference, address: 0000000000000018 PGD 0 P4D 0 Oops: 0000 [#1] PREEMPT SMP NOPTI CPU: 5 PID: 17818 Comm: kworker/5:1 Tainted: G W 5.15.108-18910-gab0e1cb584e1 #1 <HASH:1f9e 1> Hardware name: Google Kindred/Kindred, BIOS Google_Kindred.12672.413.0 02/03/2021 Workqueue: usb_hub_wq hub_event RIP: 0010:hub_port_reset+0x193/0x788 Code: 89 f7 e8 20 f7 15 00 48 8b 43 08 80 b8 96 03 00 00 03 75 36 0f b7 88 92 03 00 00 81 f9 10 03 00 00 72 27 48 8b 80 a8 03 00 00 <48> 83 78 18 00 74 19 48 89 df 48 8b 75 b0 ba 02 00 00 00 4c 89 e9 RSP: 0018:ffffab740c53fcf8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffffa1bc5f678000 RCX: 0000000000000310 RDX: fffffffffffffdff RSI: 0000000000000286 RDI: ffffa1be9655b840 RBP: ffffab740c53fd70 R08: 00001b7d5edaa20c R09: ffffffffb005e060 R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000000 R13: ffffab740c53fd3e R14: 0000000000000032 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffffa1be96540000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000018 CR3: 000000022e80c005 CR4: 00000000003706e0 Call Trace: hub_event+0x73f/0x156e ? hub_activate+0x5b7/0x68f process_one_work+0x1a2/0x487 worker_thread+0x11a/0x288 kthread+0x13a/0x152 ? process_one_work+0x487/0x487 ? kthread_associate_blkcg+0x70/0x70 ret_from_fork+0x1f/0x30 Fall back to a default behavior if the BOS descriptor isn't accessible and skip all the functionalities that depend on it: LPM support checks, Super Speed capabilitiy checks, U1/U2 states setup. Signed-off-by: Ricardo Cañuelo <ricardo.canuelo@collabora.com> Cc: stable <stable@vger.kernel.org> Link: https://lore.kernel.org/r/20230830100418.1952143-1-ricardo.canuelo@collabora.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff f74a7afc Tue Aug 29 16:04:18 MDT 2023 Ricardo Cañuelo <ricardo.canuelo@collabora.com> usb: hub: Guard against accesses to uninitialized BOS descriptors Many functions in drivers/usb/core/hub.c and drivers/usb/core/hub.h access fields inside udev->bos without checking if it was allocated and initialized. If usb_get_bos_descriptor() fails for whatever reason, udev->bos will be NULL and those accesses will result in a crash: BUG: kernel NULL pointer dereference, address: 0000000000000018 PGD 0 P4D 0 Oops: 0000 [#1] PREEMPT SMP NOPTI CPU: 5 PID: 17818 Comm: kworker/5:1 Tainted: G W 5.15.108-18910-gab0e1cb584e1 #1 <HASH:1f9e 1> Hardware name: Google Kindred/Kindred, BIOS Google_Kindred.12672.413.0 02/03/2021 Workqueue: usb_hub_wq hub_event RIP: 0010:hub_port_reset+0x193/0x788 Code: 89 f7 e8 20 f7 15 00 48 8b 43 08 80 b8 96 03 00 00 03 75 36 0f b7 88 92 03 00 00 81 f9 10 03 00 00 72 27 48 8b 80 a8 03 00 00 <48> 83 78 18 00 74 19 48 89 df 48 8b 75 b0 ba 02 00 00 00 4c 89 e9 RSP: 0018:ffffab740c53fcf8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffffa1bc5f678000 RCX: 0000000000000310 RDX: fffffffffffffdff RSI: 0000000000000286 RDI: ffffa1be9655b840 RBP: ffffab740c53fd70 R08: 00001b7d5edaa20c R09: ffffffffb005e060 R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000000 R13: ffffab740c53fd3e R14: 0000000000000032 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffffa1be96540000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000018 CR3: 000000022e80c005 CR4: 00000000003706e0 Call Trace: hub_event+0x73f/0x156e ? hub_activate+0x5b7/0x68f process_one_work+0x1a2/0x487 worker_thread+0x11a/0x288 kthread+0x13a/0x152 ? process_one_work+0x487/0x487 ? kthread_associate_blkcg+0x70/0x70 ret_from_fork+0x1f/0x30 Fall back to a default behavior if the BOS descriptor isn't accessible and skip all the functionalities that depend on it: LPM support checks, Super Speed capabilitiy checks, U1/U2 states setup. Signed-off-by: Ricardo Cañuelo <ricardo.canuelo@collabora.com> Cc: stable <stable@vger.kernel.org> Link: https://lore.kernel.org/r/20230830100418.1952143-1-ricardo.canuelo@collabora.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff f74a7afc Tue Aug 29 16:04:18 MDT 2023 Ricardo Cañuelo <ricardo.canuelo@collabora.com> usb: hub: Guard against accesses to uninitialized BOS descriptors Many functions in drivers/usb/core/hub.c and drivers/usb/core/hub.h access fields inside udev->bos without checking if it was allocated and initialized. If usb_get_bos_descriptor() fails for whatever reason, udev->bos will be NULL and those accesses will result in a crash: BUG: kernel NULL pointer dereference, address: 0000000000000018 PGD 0 P4D 0 Oops: 0000 [#1] PREEMPT SMP NOPTI CPU: 5 PID: 17818 Comm: kworker/5:1 Tainted: G W 5.15.108-18910-gab0e1cb584e1 #1 <HASH:1f9e 1> Hardware name: Google Kindred/Kindred, BIOS Google_Kindred.12672.413.0 02/03/2021 Workqueue: usb_hub_wq hub_event RIP: 0010:hub_port_reset+0x193/0x788 Code: 89 f7 e8 20 f7 15 00 48 8b 43 08 80 b8 96 03 00 00 03 75 36 0f b7 88 92 03 00 00 81 f9 10 03 00 00 72 27 48 8b 80 a8 03 00 00 <48> 83 78 18 00 74 19 48 89 df 48 8b 75 b0 ba 02 00 00 00 4c 89 e9 RSP: 0018:ffffab740c53fcf8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffffa1bc5f678000 RCX: 0000000000000310 RDX: fffffffffffffdff RSI: 0000000000000286 RDI: ffffa1be9655b840 RBP: ffffab740c53fd70 R08: 00001b7d5edaa20c R09: ffffffffb005e060 R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000000 R13: ffffab740c53fd3e R14: 0000000000000032 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffffa1be96540000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000018 CR3: 000000022e80c005 CR4: 00000000003706e0 Call Trace: hub_event+0x73f/0x156e ? hub_activate+0x5b7/0x68f process_one_work+0x1a2/0x487 worker_thread+0x11a/0x288 kthread+0x13a/0x152 ? process_one_work+0x487/0x487 ? kthread_associate_blkcg+0x70/0x70 ret_from_fork+0x1f/0x30 Fall back to a default behavior if the BOS descriptor isn't accessible and skip all the functionalities that depend on it: LPM support checks, Super Speed capabilitiy checks, U1/U2 states setup. Signed-off-by: Ricardo Cañuelo <ricardo.canuelo@collabora.com> Cc: stable <stable@vger.kernel.org> Link: https://lore.kernel.org/r/20230830100418.1952143-1-ricardo.canuelo@collabora.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff f74a7afc Tue Aug 29 16:04:18 MDT 2023 Ricardo Cañuelo <ricardo.canuelo@collabora.com> usb: hub: Guard against accesses to uninitialized BOS descriptors Many functions in drivers/usb/core/hub.c and drivers/usb/core/hub.h access fields inside udev->bos without checking if it was allocated and initialized. If usb_get_bos_descriptor() fails for whatever reason, udev->bos will be NULL and those accesses will result in a crash: BUG: kernel NULL pointer dereference, address: 0000000000000018 PGD 0 P4D 0 Oops: 0000 [#1] PREEMPT SMP NOPTI CPU: 5 PID: 17818 Comm: kworker/5:1 Tainted: G W 5.15.108-18910-gab0e1cb584e1 #1 <HASH:1f9e 1> Hardware name: Google Kindred/Kindred, BIOS Google_Kindred.12672.413.0 02/03/2021 Workqueue: usb_hub_wq hub_event RIP: 0010:hub_port_reset+0x193/0x788 Code: 89 f7 e8 20 f7 15 00 48 8b 43 08 80 b8 96 03 00 00 03 75 36 0f b7 88 92 03 00 00 81 f9 10 03 00 00 72 27 48 8b 80 a8 03 00 00 <48> 83 78 18 00 74 19 48 89 df 48 8b 75 b0 ba 02 00 00 00 4c 89 e9 RSP: 0018:ffffab740c53fcf8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffffa1bc5f678000 RCX: 0000000000000310 RDX: fffffffffffffdff RSI: 0000000000000286 RDI: ffffa1be9655b840 RBP: ffffab740c53fd70 R08: 00001b7d5edaa20c R09: ffffffffb005e060 R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000000 R13: ffffab740c53fd3e R14: 0000000000000032 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffffa1be96540000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000018 CR3: 000000022e80c005 CR4: 00000000003706e0 Call Trace: hub_event+0x73f/0x156e ? hub_activate+0x5b7/0x68f process_one_work+0x1a2/0x487 worker_thread+0x11a/0x288 kthread+0x13a/0x152 ? process_one_work+0x487/0x487 ? kthread_associate_blkcg+0x70/0x70 ret_from_fork+0x1f/0x30 Fall back to a default behavior if the BOS descriptor isn't accessible and skip all the functionalities that depend on it: LPM support checks, Super Speed capabilitiy checks, U1/U2 states setup. Signed-off-by: Ricardo Cañuelo <ricardo.canuelo@collabora.com> Cc: stable <stable@vger.kernel.org> Link: https://lore.kernel.org/r/20230830100418.1952143-1-ricardo.canuelo@collabora.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff f74a7afc Tue Aug 29 16:04:18 MDT 2023 Ricardo Cañuelo <ricardo.canuelo@collabora.com> usb: hub: Guard against accesses to uninitialized BOS descriptors Many functions in drivers/usb/core/hub.c and drivers/usb/core/hub.h access fields inside udev->bos without checking if it was allocated and initialized. If usb_get_bos_descriptor() fails for whatever reason, udev->bos will be NULL and those accesses will result in a crash: BUG: kernel NULL pointer dereference, address: 0000000000000018 PGD 0 P4D 0 Oops: 0000 [#1] PREEMPT SMP NOPTI CPU: 5 PID: 17818 Comm: kworker/5:1 Tainted: G W 5.15.108-18910-gab0e1cb584e1 #1 <HASH:1f9e 1> Hardware name: Google Kindred/Kindred, BIOS Google_Kindred.12672.413.0 02/03/2021 Workqueue: usb_hub_wq hub_event RIP: 0010:hub_port_reset+0x193/0x788 Code: 89 f7 e8 20 f7 15 00 48 8b 43 08 80 b8 96 03 00 00 03 75 36 0f b7 88 92 03 00 00 81 f9 10 03 00 00 72 27 48 8b 80 a8 03 00 00 <48> 83 78 18 00 74 19 48 89 df 48 8b 75 b0 ba 02 00 00 00 4c 89 e9 RSP: 0018:ffffab740c53fcf8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffffa1bc5f678000 RCX: 0000000000000310 RDX: fffffffffffffdff RSI: 0000000000000286 RDI: ffffa1be9655b840 RBP: ffffab740c53fd70 R08: 00001b7d5edaa20c R09: ffffffffb005e060 R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000000 R13: ffffab740c53fd3e R14: 0000000000000032 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffffa1be96540000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000018 CR3: 000000022e80c005 CR4: 00000000003706e0 Call Trace: hub_event+0x73f/0x156e ? hub_activate+0x5b7/0x68f process_one_work+0x1a2/0x487 worker_thread+0x11a/0x288 kthread+0x13a/0x152 ? process_one_work+0x487/0x487 ? kthread_associate_blkcg+0x70/0x70 ret_from_fork+0x1f/0x30 Fall back to a default behavior if the BOS descriptor isn't accessible and skip all the functionalities that depend on it: LPM support checks, Super Speed capabilitiy checks, U1/U2 states setup. Signed-off-by: Ricardo Cañuelo <ricardo.canuelo@collabora.com> Cc: stable <stable@vger.kernel.org> Link: https://lore.kernel.org/r/20230830100418.1952143-1-ricardo.canuelo@collabora.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff f74a7afc Tue Aug 29 16:04:18 MDT 2023 Ricardo Cañuelo <ricardo.canuelo@collabora.com> usb: hub: Guard against accesses to uninitialized BOS descriptors Many functions in drivers/usb/core/hub.c and drivers/usb/core/hub.h access fields inside udev->bos without checking if it was allocated and initialized. If usb_get_bos_descriptor() fails for whatever reason, udev->bos will be NULL and those accesses will result in a crash: BUG: kernel NULL pointer dereference, address: 0000000000000018 PGD 0 P4D 0 Oops: 0000 [#1] PREEMPT SMP NOPTI CPU: 5 PID: 17818 Comm: kworker/5:1 Tainted: G W 5.15.108-18910-gab0e1cb584e1 #1 <HASH:1f9e 1> Hardware name: Google Kindred/Kindred, BIOS Google_Kindred.12672.413.0 02/03/2021 Workqueue: usb_hub_wq hub_event RIP: 0010:hub_port_reset+0x193/0x788 Code: 89 f7 e8 20 f7 15 00 48 8b 43 08 80 b8 96 03 00 00 03 75 36 0f b7 88 92 03 00 00 81 f9 10 03 00 00 72 27 48 8b 80 a8 03 00 00 <48> 83 78 18 00 74 19 48 89 df 48 8b 75 b0 ba 02 00 00 00 4c 89 e9 RSP: 0018:ffffab740c53fcf8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffffa1bc5f678000 RCX: 0000000000000310 RDX: fffffffffffffdff RSI: 0000000000000286 RDI: ffffa1be9655b840 RBP: ffffab740c53fd70 R08: 00001b7d5edaa20c R09: ffffffffb005e060 R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000000 R13: ffffab740c53fd3e R14: 0000000000000032 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffffa1be96540000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000018 CR3: 000000022e80c005 CR4: 00000000003706e0 Call Trace: hub_event+0x73f/0x156e ? hub_activate+0x5b7/0x68f process_one_work+0x1a2/0x487 worker_thread+0x11a/0x288 kthread+0x13a/0x152 ? process_one_work+0x487/0x487 ? kthread_associate_blkcg+0x70/0x70 ret_from_fork+0x1f/0x30 Fall back to a default behavior if the BOS descriptor isn't accessible and skip all the functionalities that depend on it: LPM support checks, Super Speed capabilitiy checks, U1/U2 states setup. Signed-off-by: Ricardo Cañuelo <ricardo.canuelo@collabora.com> Cc: stable <stable@vger.kernel.org> Link: https://lore.kernel.org/r/20230830100418.1952143-1-ricardo.canuelo@collabora.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff f74a7afc Tue Aug 29 16:04:18 MDT 2023 Ricardo Cañuelo <ricardo.canuelo@collabora.com> usb: hub: Guard against accesses to uninitialized BOS descriptors Many functions in drivers/usb/core/hub.c and drivers/usb/core/hub.h access fields inside udev->bos without checking if it was allocated and initialized. If usb_get_bos_descriptor() fails for whatever reason, udev->bos will be NULL and those accesses will result in a crash: BUG: kernel NULL pointer dereference, address: 0000000000000018 PGD 0 P4D 0 Oops: 0000 [#1] PREEMPT SMP NOPTI CPU: 5 PID: 17818 Comm: kworker/5:1 Tainted: G W 5.15.108-18910-gab0e1cb584e1 #1 <HASH:1f9e 1> Hardware name: Google Kindred/Kindred, BIOS Google_Kindred.12672.413.0 02/03/2021 Workqueue: usb_hub_wq hub_event RIP: 0010:hub_port_reset+0x193/0x788 Code: 89 f7 e8 20 f7 15 00 48 8b 43 08 80 b8 96 03 00 00 03 75 36 0f b7 88 92 03 00 00 81 f9 10 03 00 00 72 27 48 8b 80 a8 03 00 00 <48> 83 78 18 00 74 19 48 89 df 48 8b 75 b0 ba 02 00 00 00 4c 89 e9 RSP: 0018:ffffab740c53fcf8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffffa1bc5f678000 RCX: 0000000000000310 RDX: fffffffffffffdff RSI: 0000000000000286 RDI: ffffa1be9655b840 RBP: ffffab740c53fd70 R08: 00001b7d5edaa20c R09: ffffffffb005e060 R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000000 R13: ffffab740c53fd3e R14: 0000000000000032 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffffa1be96540000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000018 CR3: 000000022e80c005 CR4: 00000000003706e0 Call Trace: hub_event+0x73f/0x156e ? hub_activate+0x5b7/0x68f process_one_work+0x1a2/0x487 worker_thread+0x11a/0x288 kthread+0x13a/0x152 ? process_one_work+0x487/0x487 ? kthread_associate_blkcg+0x70/0x70 ret_from_fork+0x1f/0x30 Fall back to a default behavior if the BOS descriptor isn't accessible and skip all the functionalities that depend on it: LPM support checks, Super Speed capabilitiy checks, U1/U2 states setup. Signed-off-by: Ricardo Cañuelo <ricardo.canuelo@collabora.com> Cc: stable <stable@vger.kernel.org> Link: https://lore.kernel.org/r/20230830100418.1952143-1-ricardo.canuelo@collabora.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff f74a7afc Tue Aug 29 16:04:18 MDT 2023 Ricardo Cañuelo <ricardo.canuelo@collabora.com> usb: hub: Guard against accesses to uninitialized BOS descriptors Many functions in drivers/usb/core/hub.c and drivers/usb/core/hub.h access fields inside udev->bos without checking if it was allocated and initialized. If usb_get_bos_descriptor() fails for whatever reason, udev->bos will be NULL and those accesses will result in a crash: BUG: kernel NULL pointer dereference, address: 0000000000000018 PGD 0 P4D 0 Oops: 0000 [#1] PREEMPT SMP NOPTI CPU: 5 PID: 17818 Comm: kworker/5:1 Tainted: G W 5.15.108-18910-gab0e1cb584e1 #1 <HASH:1f9e 1> Hardware name: Google Kindred/Kindred, BIOS Google_Kindred.12672.413.0 02/03/2021 Workqueue: usb_hub_wq hub_event RIP: 0010:hub_port_reset+0x193/0x788 Code: 89 f7 e8 20 f7 15 00 48 8b 43 08 80 b8 96 03 00 00 03 75 36 0f b7 88 92 03 00 00 81 f9 10 03 00 00 72 27 48 8b 80 a8 03 00 00 <48> 83 78 18 00 74 19 48 89 df 48 8b 75 b0 ba 02 00 00 00 4c 89 e9 RSP: 0018:ffffab740c53fcf8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffffa1bc5f678000 RCX: 0000000000000310 RDX: fffffffffffffdff RSI: 0000000000000286 RDI: ffffa1be9655b840 RBP: ffffab740c53fd70 R08: 00001b7d5edaa20c R09: ffffffffb005e060 R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000000 R13: ffffab740c53fd3e R14: 0000000000000032 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffffa1be96540000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000018 CR3: 000000022e80c005 CR4: 00000000003706e0 Call Trace: hub_event+0x73f/0x156e ? hub_activate+0x5b7/0x68f process_one_work+0x1a2/0x487 worker_thread+0x11a/0x288 kthread+0x13a/0x152 ? process_one_work+0x487/0x487 ? kthread_associate_blkcg+0x70/0x70 ret_from_fork+0x1f/0x30 Fall back to a default behavior if the BOS descriptor isn't accessible and skip all the functionalities that depend on it: LPM support checks, Super Speed capabilitiy checks, U1/U2 states setup. Signed-off-by: Ricardo Cañuelo <ricardo.canuelo@collabora.com> Cc: stable <stable@vger.kernel.org> Link: https://lore.kernel.org/r/20230830100418.1952143-1-ricardo.canuelo@collabora.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff f74a7afc Tue Aug 29 16:04:18 MDT 2023 Ricardo Cañuelo <ricardo.canuelo@collabora.com> usb: hub: Guard against accesses to uninitialized BOS descriptors Many functions in drivers/usb/core/hub.c and drivers/usb/core/hub.h access fields inside udev->bos without checking if it was allocated and initialized. If usb_get_bos_descriptor() fails for whatever reason, udev->bos will be NULL and those accesses will result in a crash: BUG: kernel NULL pointer dereference, address: 0000000000000018 PGD 0 P4D 0 Oops: 0000 [#1] PREEMPT SMP NOPTI CPU: 5 PID: 17818 Comm: kworker/5:1 Tainted: G W 5.15.108-18910-gab0e1cb584e1 #1 <HASH:1f9e 1> Hardware name: Google Kindred/Kindred, BIOS Google_Kindred.12672.413.0 02/03/2021 Workqueue: usb_hub_wq hub_event RIP: 0010:hub_port_reset+0x193/0x788 Code: 89 f7 e8 20 f7 15 00 48 8b 43 08 80 b8 96 03 00 00 03 75 36 0f b7 88 92 03 00 00 81 f9 10 03 00 00 72 27 48 8b 80 a8 03 00 00 <48> 83 78 18 00 74 19 48 89 df 48 8b 75 b0 ba 02 00 00 00 4c 89 e9 RSP: 0018:ffffab740c53fcf8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffffa1bc5f678000 RCX: 0000000000000310 RDX: fffffffffffffdff RSI: 0000000000000286 RDI: ffffa1be9655b840 RBP: ffffab740c53fd70 R08: 00001b7d5edaa20c R09: ffffffffb005e060 R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000000 R13: ffffab740c53fd3e R14: 0000000000000032 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffffa1be96540000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000018 CR3: 000000022e80c005 CR4: 00000000003706e0 Call Trace: hub_event+0x73f/0x156e ? hub_activate+0x5b7/0x68f process_one_work+0x1a2/0x487 worker_thread+0x11a/0x288 kthread+0x13a/0x152 ? process_one_work+0x487/0x487 ? kthread_associate_blkcg+0x70/0x70 ret_from_fork+0x1f/0x30 Fall back to a default behavior if the BOS descriptor isn't accessible and skip all the functionalities that depend on it: LPM support checks, Super Speed capabilitiy checks, U1/U2 states setup. Signed-off-by: Ricardo Cañuelo <ricardo.canuelo@collabora.com> Cc: stable <stable@vger.kernel.org> Link: https://lore.kernel.org/r/20230830100418.1952143-1-ricardo.canuelo@collabora.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff f74a7afc Tue Aug 29 16:04:18 MDT 2023 Ricardo Cañuelo <ricardo.canuelo@collabora.com> usb: hub: Guard against accesses to uninitialized BOS descriptors Many functions in drivers/usb/core/hub.c and drivers/usb/core/hub.h access fields inside udev->bos without checking if it was allocated and initialized. If usb_get_bos_descriptor() fails for whatever reason, udev->bos will be NULL and those accesses will result in a crash: BUG: kernel NULL pointer dereference, address: 0000000000000018 PGD 0 P4D 0 Oops: 0000 [#1] PREEMPT SMP NOPTI CPU: 5 PID: 17818 Comm: kworker/5:1 Tainted: G W 5.15.108-18910-gab0e1cb584e1 #1 <HASH:1f9e 1> Hardware name: Google Kindred/Kindred, BIOS Google_Kindred.12672.413.0 02/03/2021 Workqueue: usb_hub_wq hub_event RIP: 0010:hub_port_reset+0x193/0x788 Code: 89 f7 e8 20 f7 15 00 48 8b 43 08 80 b8 96 03 00 00 03 75 36 0f b7 88 92 03 00 00 81 f9 10 03 00 00 72 27 48 8b 80 a8 03 00 00 <48> 83 78 18 00 74 19 48 89 df 48 8b 75 b0 ba 02 00 00 00 4c 89 e9 RSP: 0018:ffffab740c53fcf8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffffa1bc5f678000 RCX: 0000000000000310 RDX: fffffffffffffdff RSI: 0000000000000286 RDI: ffffa1be9655b840 RBP: ffffab740c53fd70 R08: 00001b7d5edaa20c R09: ffffffffb005e060 R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000000 R13: ffffab740c53fd3e R14: 0000000000000032 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffffa1be96540000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000018 CR3: 000000022e80c005 CR4: 00000000003706e0 Call Trace: hub_event+0x73f/0x156e ? hub_activate+0x5b7/0x68f process_one_work+0x1a2/0x487 worker_thread+0x11a/0x288 kthread+0x13a/0x152 ? process_one_work+0x487/0x487 ? kthread_associate_blkcg+0x70/0x70 ret_from_fork+0x1f/0x30 Fall back to a default behavior if the BOS descriptor isn't accessible and skip all the functionalities that depend on it: LPM support checks, Super Speed capabilitiy checks, U1/U2 states setup. Signed-off-by: Ricardo Cañuelo <ricardo.canuelo@collabora.com> Cc: stable <stable@vger.kernel.org> Link: https://lore.kernel.org/r/20230830100418.1952143-1-ricardo.canuelo@collabora.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff f74a7afc Tue Aug 29 16:04:18 MDT 2023 Ricardo Cañuelo <ricardo.canuelo@collabora.com> usb: hub: Guard against accesses to uninitialized BOS descriptors Many functions in drivers/usb/core/hub.c and drivers/usb/core/hub.h access fields inside udev->bos without checking if it was allocated and initialized. If usb_get_bos_descriptor() fails for whatever reason, udev->bos will be NULL and those accesses will result in a crash: BUG: kernel NULL pointer dereference, address: 0000000000000018 PGD 0 P4D 0 Oops: 0000 [#1] PREEMPT SMP NOPTI CPU: 5 PID: 17818 Comm: kworker/5:1 Tainted: G W 5.15.108-18910-gab0e1cb584e1 #1 <HASH:1f9e 1> Hardware name: Google Kindred/Kindred, BIOS Google_Kindred.12672.413.0 02/03/2021 Workqueue: usb_hub_wq hub_event RIP: 0010:hub_port_reset+0x193/0x788 Code: 89 f7 e8 20 f7 15 00 48 8b 43 08 80 b8 96 03 00 00 03 75 36 0f b7 88 92 03 00 00 81 f9 10 03 00 00 72 27 48 8b 80 a8 03 00 00 <48> 83 78 18 00 74 19 48 89 df 48 8b 75 b0 ba 02 00 00 00 4c 89 e9 RSP: 0018:ffffab740c53fcf8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffffa1bc5f678000 RCX: 0000000000000310 RDX: fffffffffffffdff RSI: 0000000000000286 RDI: ffffa1be9655b840 RBP: ffffab740c53fd70 R08: 00001b7d5edaa20c R09: ffffffffb005e060 R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000000 R13: ffffab740c53fd3e R14: 0000000000000032 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffffa1be96540000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000018 CR3: 000000022e80c005 CR4: 00000000003706e0 Call Trace: hub_event+0x73f/0x156e ? hub_activate+0x5b7/0x68f process_one_work+0x1a2/0x487 worker_thread+0x11a/0x288 kthread+0x13a/0x152 ? process_one_work+0x487/0x487 ? kthread_associate_blkcg+0x70/0x70 ret_from_fork+0x1f/0x30 Fall back to a default behavior if the BOS descriptor isn't accessible and skip all the functionalities that depend on it: LPM support checks, Super Speed capabilitiy checks, U1/U2 states setup. Signed-off-by: Ricardo Cañuelo <ricardo.canuelo@collabora.com> Cc: stable <stable@vger.kernel.org> Link: https://lore.kernel.org/r/20230830100418.1952143-1-ricardo.canuelo@collabora.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff f74a7afc Tue Aug 29 16:04:18 MDT 2023 Ricardo Cañuelo <ricardo.canuelo@collabora.com> usb: hub: Guard against accesses to uninitialized BOS descriptors Many functions in drivers/usb/core/hub.c and drivers/usb/core/hub.h access fields inside udev->bos without checking if it was allocated and initialized. If usb_get_bos_descriptor() fails for whatever reason, udev->bos will be NULL and those accesses will result in a crash: BUG: kernel NULL pointer dereference, address: 0000000000000018 PGD 0 P4D 0 Oops: 0000 [#1] PREEMPT SMP NOPTI CPU: 5 PID: 17818 Comm: kworker/5:1 Tainted: G W 5.15.108-18910-gab0e1cb584e1 #1 <HASH:1f9e 1> Hardware name: Google Kindred/Kindred, BIOS Google_Kindred.12672.413.0 02/03/2021 Workqueue: usb_hub_wq hub_event RIP: 0010:hub_port_reset+0x193/0x788 Code: 89 f7 e8 20 f7 15 00 48 8b 43 08 80 b8 96 03 00 00 03 75 36 0f b7 88 92 03 00 00 81 f9 10 03 00 00 72 27 48 8b 80 a8 03 00 00 <48> 83 78 18 00 74 19 48 89 df 48 8b 75 b0 ba 02 00 00 00 4c 89 e9 RSP: 0018:ffffab740c53fcf8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffffa1bc5f678000 RCX: 0000000000000310 RDX: fffffffffffffdff RSI: 0000000000000286 RDI: ffffa1be9655b840 RBP: ffffab740c53fd70 R08: 00001b7d5edaa20c R09: ffffffffb005e060 R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000000 R13: ffffab740c53fd3e R14: 0000000000000032 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffffa1be96540000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000018 CR3: 000000022e80c005 CR4: 00000000003706e0 Call Trace: hub_event+0x73f/0x156e ? hub_activate+0x5b7/0x68f process_one_work+0x1a2/0x487 worker_thread+0x11a/0x288 kthread+0x13a/0x152 ? process_one_work+0x487/0x487 ? kthread_associate_blkcg+0x70/0x70 ret_from_fork+0x1f/0x30 Fall back to a default behavior if the BOS descriptor isn't accessible and skip all the functionalities that depend on it: LPM support checks, Super Speed capabilitiy checks, U1/U2 states setup. Signed-off-by: Ricardo Cañuelo <ricardo.canuelo@collabora.com> Cc: stable <stable@vger.kernel.org> Link: https://lore.kernel.org/r/20230830100418.1952143-1-ricardo.canuelo@collabora.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff f74a7afc Tue Aug 29 16:04:18 MDT 2023 Ricardo Cañuelo <ricardo.canuelo@collabora.com> usb: hub: Guard against accesses to uninitialized BOS descriptors Many functions in drivers/usb/core/hub.c and drivers/usb/core/hub.h access fields inside udev->bos without checking if it was allocated and initialized. If usb_get_bos_descriptor() fails for whatever reason, udev->bos will be NULL and those accesses will result in a crash: BUG: kernel NULL pointer dereference, address: 0000000000000018 PGD 0 P4D 0 Oops: 0000 [#1] PREEMPT SMP NOPTI CPU: 5 PID: 17818 Comm: kworker/5:1 Tainted: G W 5.15.108-18910-gab0e1cb584e1 #1 <HASH:1f9e 1> Hardware name: Google Kindred/Kindred, BIOS Google_Kindred.12672.413.0 02/03/2021 Workqueue: usb_hub_wq hub_event RIP: 0010:hub_port_reset+0x193/0x788 Code: 89 f7 e8 20 f7 15 00 48 8b 43 08 80 b8 96 03 00 00 03 75 36 0f b7 88 92 03 00 00 81 f9 10 03 00 00 72 27 48 8b 80 a8 03 00 00 <48> 83 78 18 00 74 19 48 89 df 48 8b 75 b0 ba 02 00 00 00 4c 89 e9 RSP: 0018:ffffab740c53fcf8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffffa1bc5f678000 RCX: 0000000000000310 RDX: fffffffffffffdff RSI: 0000000000000286 RDI: ffffa1be9655b840 RBP: ffffab740c53fd70 R08: 00001b7d5edaa20c R09: ffffffffb005e060 R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000000 R13: ffffab740c53fd3e R14: 0000000000000032 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffffa1be96540000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000018 CR3: 000000022e80c005 CR4: 00000000003706e0 Call Trace: hub_event+0x73f/0x156e ? hub_activate+0x5b7/0x68f process_one_work+0x1a2/0x487 worker_thread+0x11a/0x288 kthread+0x13a/0x152 ? process_one_work+0x487/0x487 ? kthread_associate_blkcg+0x70/0x70 ret_from_fork+0x1f/0x30 Fall back to a default behavior if the BOS descriptor isn't accessible and skip all the functionalities that depend on it: LPM support checks, Super Speed capabilitiy checks, U1/U2 states setup. Signed-off-by: Ricardo Cañuelo <ricardo.canuelo@collabora.com> Cc: stable <stable@vger.kernel.org> Link: https://lore.kernel.org/r/20230830100418.1952143-1-ricardo.canuelo@collabora.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff f74a7afc Tue Aug 29 16:04:18 MDT 2023 Ricardo Cañuelo <ricardo.canuelo@collabora.com> usb: hub: Guard against accesses to uninitialized BOS descriptors Many functions in drivers/usb/core/hub.c and drivers/usb/core/hub.h access fields inside udev->bos without checking if it was allocated and initialized. If usb_get_bos_descriptor() fails for whatever reason, udev->bos will be NULL and those accesses will result in a crash: BUG: kernel NULL pointer dereference, address: 0000000000000018 PGD 0 P4D 0 Oops: 0000 [#1] PREEMPT SMP NOPTI CPU: 5 PID: 17818 Comm: kworker/5:1 Tainted: G W 5.15.108-18910-gab0e1cb584e1 #1 <HASH:1f9e 1> Hardware name: Google Kindred/Kindred, BIOS Google_Kindred.12672.413.0 02/03/2021 Workqueue: usb_hub_wq hub_event RIP: 0010:hub_port_reset+0x193/0x788 Code: 89 f7 e8 20 f7 15 00 48 8b 43 08 80 b8 96 03 00 00 03 75 36 0f b7 88 92 03 00 00 81 f9 10 03 00 00 72 27 48 8b 80 a8 03 00 00 <48> 83 78 18 00 74 19 48 89 df 48 8b 75 b0 ba 02 00 00 00 4c 89 e9 RSP: 0018:ffffab740c53fcf8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffffa1bc5f678000 RCX: 0000000000000310 RDX: fffffffffffffdff RSI: 0000000000000286 RDI: ffffa1be9655b840 RBP: ffffab740c53fd70 R08: 00001b7d5edaa20c R09: ffffffffb005e060 R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000000 R13: ffffab740c53fd3e R14: 0000000000000032 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffffa1be96540000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000018 CR3: 000000022e80c005 CR4: 00000000003706e0 Call Trace: hub_event+0x73f/0x156e ? hub_activate+0x5b7/0x68f process_one_work+0x1a2/0x487 worker_thread+0x11a/0x288 kthread+0x13a/0x152 ? process_one_work+0x487/0x487 ? kthread_associate_blkcg+0x70/0x70 ret_from_fork+0x1f/0x30 Fall back to a default behavior if the BOS descriptor isn't accessible and skip all the functionalities that depend on it: LPM support checks, Super Speed capabilitiy checks, U1/U2 states setup. Signed-off-by: Ricardo Cañuelo <ricardo.canuelo@collabora.com> Cc: stable <stable@vger.kernel.org> Link: https://lore.kernel.org/r/20230830100418.1952143-1-ricardo.canuelo@collabora.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff f74a7afc Tue Aug 29 16:04:18 MDT 2023 Ricardo Cañuelo <ricardo.canuelo@collabora.com> usb: hub: Guard against accesses to uninitialized BOS descriptors Many functions in drivers/usb/core/hub.c and drivers/usb/core/hub.h access fields inside udev->bos without checking if it was allocated and initialized. If usb_get_bos_descriptor() fails for whatever reason, udev->bos will be NULL and those accesses will result in a crash: BUG: kernel NULL pointer dereference, address: 0000000000000018 PGD 0 P4D 0 Oops: 0000 [#1] PREEMPT SMP NOPTI CPU: 5 PID: 17818 Comm: kworker/5:1 Tainted: G W 5.15.108-18910-gab0e1cb584e1 #1 <HASH:1f9e 1> Hardware name: Google Kindred/Kindred, BIOS Google_Kindred.12672.413.0 02/03/2021 Workqueue: usb_hub_wq hub_event RIP: 0010:hub_port_reset+0x193/0x788 Code: 89 f7 e8 20 f7 15 00 48 8b 43 08 80 b8 96 03 00 00 03 75 36 0f b7 88 92 03 00 00 81 f9 10 03 00 00 72 27 48 8b 80 a8 03 00 00 <48> 83 78 18 00 74 19 48 89 df 48 8b 75 b0 ba 02 00 00 00 4c 89 e9 RSP: 0018:ffffab740c53fcf8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffffa1bc5f678000 RCX: 0000000000000310 RDX: fffffffffffffdff RSI: 0000000000000286 RDI: ffffa1be9655b840 RBP: ffffab740c53fd70 R08: 00001b7d5edaa20c R09: ffffffffb005e060 R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000000 R13: ffffab740c53fd3e R14: 0000000000000032 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffffa1be96540000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000018 CR3: 000000022e80c005 CR4: 00000000003706e0 Call Trace: hub_event+0x73f/0x156e ? hub_activate+0x5b7/0x68f process_one_work+0x1a2/0x487 worker_thread+0x11a/0x288 kthread+0x13a/0x152 ? process_one_work+0x487/0x487 ? kthread_associate_blkcg+0x70/0x70 ret_from_fork+0x1f/0x30 Fall back to a default behavior if the BOS descriptor isn't accessible and skip all the functionalities that depend on it: LPM support checks, Super Speed capabilitiy checks, U1/U2 states setup. Signed-off-by: Ricardo Cañuelo <ricardo.canuelo@collabora.com> Cc: stable <stable@vger.kernel.org> Link: https://lore.kernel.org/r/20230830100418.1952143-1-ricardo.canuelo@collabora.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff f74a7afc Tue Aug 29 16:04:18 MDT 2023 Ricardo Cañuelo <ricardo.canuelo@collabora.com> usb: hub: Guard against accesses to uninitialized BOS descriptors Many functions in drivers/usb/core/hub.c and drivers/usb/core/hub.h access fields inside udev->bos without checking if it was allocated and initialized. If usb_get_bos_descriptor() fails for whatever reason, udev->bos will be NULL and those accesses will result in a crash: BUG: kernel NULL pointer dereference, address: 0000000000000018 PGD 0 P4D 0 Oops: 0000 [#1] PREEMPT SMP NOPTI CPU: 5 PID: 17818 Comm: kworker/5:1 Tainted: G W 5.15.108-18910-gab0e1cb584e1 #1 <HASH:1f9e 1> Hardware name: Google Kindred/Kindred, BIOS Google_Kindred.12672.413.0 02/03/2021 Workqueue: usb_hub_wq hub_event RIP: 0010:hub_port_reset+0x193/0x788 Code: 89 f7 e8 20 f7 15 00 48 8b 43 08 80 b8 96 03 00 00 03 75 36 0f b7 88 92 03 00 00 81 f9 10 03 00 00 72 27 48 8b 80 a8 03 00 00 <48> 83 78 18 00 74 19 48 89 df 48 8b 75 b0 ba 02 00 00 00 4c 89 e9 RSP: 0018:ffffab740c53fcf8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffffa1bc5f678000 RCX: 0000000000000310 RDX: fffffffffffffdff RSI: 0000000000000286 RDI: ffffa1be9655b840 RBP: ffffab740c53fd70 R08: 00001b7d5edaa20c R09: ffffffffb005e060 R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000000 R13: ffffab740c53fd3e R14: 0000000000000032 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffffa1be96540000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000018 CR3: 000000022e80c005 CR4: 00000000003706e0 Call Trace: hub_event+0x73f/0x156e ? hub_activate+0x5b7/0x68f process_one_work+0x1a2/0x487 worker_thread+0x11a/0x288 kthread+0x13a/0x152 ? process_one_work+0x487/0x487 ? kthread_associate_blkcg+0x70/0x70 ret_from_fork+0x1f/0x30 Fall back to a default behavior if the BOS descriptor isn't accessible and skip all the functionalities that depend on it: LPM support checks, Super Speed capabilitiy checks, U1/U2 states setup. Signed-off-by: Ricardo Cañuelo <ricardo.canuelo@collabora.com> Cc: stable <stable@vger.kernel.org> Link: https://lore.kernel.org/r/20230830100418.1952143-1-ricardo.canuelo@collabora.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff f74a7afc Tue Aug 29 16:04:18 MDT 2023 Ricardo Cañuelo <ricardo.canuelo@collabora.com> usb: hub: Guard against accesses to uninitialized BOS descriptors Many functions in drivers/usb/core/hub.c and drivers/usb/core/hub.h access fields inside udev->bos without checking if it was allocated and initialized. If usb_get_bos_descriptor() fails for whatever reason, udev->bos will be NULL and those accesses will result in a crash: BUG: kernel NULL pointer dereference, address: 0000000000000018 PGD 0 P4D 0 Oops: 0000 [#1] PREEMPT SMP NOPTI CPU: 5 PID: 17818 Comm: kworker/5:1 Tainted: G W 5.15.108-18910-gab0e1cb584e1 #1 <HASH:1f9e 1> Hardware name: Google Kindred/Kindred, BIOS Google_Kindred.12672.413.0 02/03/2021 Workqueue: usb_hub_wq hub_event RIP: 0010:hub_port_reset+0x193/0x788 Code: 89 f7 e8 20 f7 15 00 48 8b 43 08 80 b8 96 03 00 00 03 75 36 0f b7 88 92 03 00 00 81 f9 10 03 00 00 72 27 48 8b 80 a8 03 00 00 <48> 83 78 18 00 74 19 48 89 df 48 8b 75 b0 ba 02 00 00 00 4c 89 e9 RSP: 0018:ffffab740c53fcf8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffffa1bc5f678000 RCX: 0000000000000310 RDX: fffffffffffffdff RSI: 0000000000000286 RDI: ffffa1be9655b840 RBP: ffffab740c53fd70 R08: 00001b7d5edaa20c R09: ffffffffb005e060 R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000000 R13: ffffab740c53fd3e R14: 0000000000000032 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffffa1be96540000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000018 CR3: 000000022e80c005 CR4: 00000000003706e0 Call Trace: hub_event+0x73f/0x156e ? hub_activate+0x5b7/0x68f process_one_work+0x1a2/0x487 worker_thread+0x11a/0x288 kthread+0x13a/0x152 ? process_one_work+0x487/0x487 ? kthread_associate_blkcg+0x70/0x70 ret_from_fork+0x1f/0x30 Fall back to a default behavior if the BOS descriptor isn't accessible and skip all the functionalities that depend on it: LPM support checks, Super Speed capabilitiy checks, U1/U2 states setup. Signed-off-by: Ricardo Cañuelo <ricardo.canuelo@collabora.com> Cc: stable <stable@vger.kernel.org> Link: https://lore.kernel.org/r/20230830100418.1952143-1-ricardo.canuelo@collabora.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff f74a7afc Tue Aug 29 16:04:18 MDT 2023 Ricardo Cañuelo <ricardo.canuelo@collabora.com> usb: hub: Guard against accesses to uninitialized BOS descriptors Many functions in drivers/usb/core/hub.c and drivers/usb/core/hub.h access fields inside udev->bos without checking if it was allocated and initialized. If usb_get_bos_descriptor() fails for whatever reason, udev->bos will be NULL and those accesses will result in a crash: BUG: kernel NULL pointer dereference, address: 0000000000000018 PGD 0 P4D 0 Oops: 0000 [#1] PREEMPT SMP NOPTI CPU: 5 PID: 17818 Comm: kworker/5:1 Tainted: G W 5.15.108-18910-gab0e1cb584e1 #1 <HASH:1f9e 1> Hardware name: Google Kindred/Kindred, BIOS Google_Kindred.12672.413.0 02/03/2021 Workqueue: usb_hub_wq hub_event RIP: 0010:hub_port_reset+0x193/0x788 Code: 89 f7 e8 20 f7 15 00 48 8b 43 08 80 b8 96 03 00 00 03 75 36 0f b7 88 92 03 00 00 81 f9 10 03 00 00 72 27 48 8b 80 a8 03 00 00 <48> 83 78 18 00 74 19 48 89 df 48 8b 75 b0 ba 02 00 00 00 4c 89 e9 RSP: 0018:ffffab740c53fcf8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffffa1bc5f678000 RCX: 0000000000000310 RDX: fffffffffffffdff RSI: 0000000000000286 RDI: ffffa1be9655b840 RBP: ffffab740c53fd70 R08: 00001b7d5edaa20c R09: ffffffffb005e060 R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000000 R13: ffffab740c53fd3e R14: 0000000000000032 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffffa1be96540000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000018 CR3: 000000022e80c005 CR4: 00000000003706e0 Call Trace: hub_event+0x73f/0x156e ? hub_activate+0x5b7/0x68f process_one_work+0x1a2/0x487 worker_thread+0x11a/0x288 kthread+0x13a/0x152 ? process_one_work+0x487/0x487 ? kthread_associate_blkcg+0x70/0x70 ret_from_fork+0x1f/0x30 Fall back to a default behavior if the BOS descriptor isn't accessible and skip all the functionalities that depend on it: LPM support checks, Super Speed capabilitiy checks, U1/U2 states setup. Signed-off-by: Ricardo Cañuelo <ricardo.canuelo@collabora.com> Cc: stable <stable@vger.kernel.org> Link: https://lore.kernel.org/r/20230830100418.1952143-1-ricardo.canuelo@collabora.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff f74a7afc Tue Aug 29 16:04:18 MDT 2023 Ricardo Cañuelo <ricardo.canuelo@collabora.com> usb: hub: Guard against accesses to uninitialized BOS descriptors Many functions in drivers/usb/core/hub.c and drivers/usb/core/hub.h access fields inside udev->bos without checking if it was allocated and initialized. If usb_get_bos_descriptor() fails for whatever reason, udev->bos will be NULL and those accesses will result in a crash: BUG: kernel NULL pointer dereference, address: 0000000000000018 PGD 0 P4D 0 Oops: 0000 [#1] PREEMPT SMP NOPTI CPU: 5 PID: 17818 Comm: kworker/5:1 Tainted: G W 5.15.108-18910-gab0e1cb584e1 #1 <HASH:1f9e 1> Hardware name: Google Kindred/Kindred, BIOS Google_Kindred.12672.413.0 02/03/2021 Workqueue: usb_hub_wq hub_event RIP: 0010:hub_port_reset+0x193/0x788 Code: 89 f7 e8 20 f7 15 00 48 8b 43 08 80 b8 96 03 00 00 03 75 36 0f b7 88 92 03 00 00 81 f9 10 03 00 00 72 27 48 8b 80 a8 03 00 00 <48> 83 78 18 00 74 19 48 89 df 48 8b 75 b0 ba 02 00 00 00 4c 89 e9 RSP: 0018:ffffab740c53fcf8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffffa1bc5f678000 RCX: 0000000000000310 RDX: fffffffffffffdff RSI: 0000000000000286 RDI: ffffa1be9655b840 RBP: ffffab740c53fd70 R08: 00001b7d5edaa20c R09: ffffffffb005e060 R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000000 R13: ffffab740c53fd3e R14: 0000000000000032 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffffa1be96540000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000018 CR3: 000000022e80c005 CR4: 00000000003706e0 Call Trace: hub_event+0x73f/0x156e ? hub_activate+0x5b7/0x68f process_one_work+0x1a2/0x487 worker_thread+0x11a/0x288 kthread+0x13a/0x152 ? process_one_work+0x487/0x487 ? kthread_associate_blkcg+0x70/0x70 ret_from_fork+0x1f/0x30 Fall back to a default behavior if the BOS descriptor isn't accessible and skip all the functionalities that depend on it: LPM support checks, Super Speed capabilitiy checks, U1/U2 states setup. Signed-off-by: Ricardo Cañuelo <ricardo.canuelo@collabora.com> Cc: stable <stable@vger.kernel.org> Link: https://lore.kernel.org/r/20230830100418.1952143-1-ricardo.canuelo@collabora.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff f74a7afc Tue Aug 29 16:04:18 MDT 2023 Ricardo Cañuelo <ricardo.canuelo@collabora.com> usb: hub: Guard against accesses to uninitialized BOS descriptors Many functions in drivers/usb/core/hub.c and drivers/usb/core/hub.h access fields inside udev->bos without checking if it was allocated and initialized. If usb_get_bos_descriptor() fails for whatever reason, udev->bos will be NULL and those accesses will result in a crash: BUG: kernel NULL pointer dereference, address: 0000000000000018 PGD 0 P4D 0 Oops: 0000 [#1] PREEMPT SMP NOPTI CPU: 5 PID: 17818 Comm: kworker/5:1 Tainted: G W 5.15.108-18910-gab0e1cb584e1 #1 <HASH:1f9e 1> Hardware name: Google Kindred/Kindred, BIOS Google_Kindred.12672.413.0 02/03/2021 Workqueue: usb_hub_wq hub_event RIP: 0010:hub_port_reset+0x193/0x788 Code: 89 f7 e8 20 f7 15 00 48 8b 43 08 80 b8 96 03 00 00 03 75 36 0f b7 88 92 03 00 00 81 f9 10 03 00 00 72 27 48 8b 80 a8 03 00 00 <48> 83 78 18 00 74 19 48 89 df 48 8b 75 b0 ba 02 00 00 00 4c 89 e9 RSP: 0018:ffffab740c53fcf8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffffa1bc5f678000 RCX: 0000000000000310 RDX: fffffffffffffdff RSI: 0000000000000286 RDI: ffffa1be9655b840 RBP: ffffab740c53fd70 R08: 00001b7d5edaa20c R09: ffffffffb005e060 R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000000 R13: ffffab740c53fd3e R14: 0000000000000032 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffffa1be96540000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000018 CR3: 000000022e80c005 CR4: 00000000003706e0 Call Trace: hub_event+0x73f/0x156e ? hub_activate+0x5b7/0x68f process_one_work+0x1a2/0x487 worker_thread+0x11a/0x288 kthread+0x13a/0x152 ? process_one_work+0x487/0x487 ? kthread_associate_blkcg+0x70/0x70 ret_from_fork+0x1f/0x30 Fall back to a default behavior if the BOS descriptor isn't accessible and skip all the functionalities that depend on it: LPM support checks, Super Speed capabilitiy checks, U1/U2 states setup. Signed-off-by: Ricardo Cañuelo <ricardo.canuelo@collabora.com> Cc: stable <stable@vger.kernel.org> Link: https://lore.kernel.org/r/20230830100418.1952143-1-ricardo.canuelo@collabora.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> diff f74a7afc Tue Aug 29 16:04:18 MDT 2023 Ricardo Cañuelo <ricardo.canuelo@collabora.com> usb: hub: Guard against accesses to uninitialized BOS descriptors Many functions in drivers/usb/core/hub.c and drivers/usb/core/hub.h access fields inside udev->bos without checking if it was allocated and initialized. If usb_get_bos_descriptor() fails for whatever reason, udev->bos will be NULL and those accesses will result in a crash: BUG: kernel NULL pointer dereference, address: 0000000000000018 PGD 0 P4D 0 Oops: 0000 [#1] PREEMPT SMP NOPTI CPU: 5 PID: 17818 Comm: kworker/5:1 Tainted: G W 5.15.108-18910-gab0e1cb584e1 #1 <HASH:1f9e 1> Hardware name: Google Kindred/Kindred, BIOS Google_Kindred.12672.413.0 02/03/2021 Workqueue: usb_hub_wq hub_event RIP: 0010:hub_port_reset+0x193/0x788 Code: 89 f7 e8 20 f7 15 00 48 8b 43 08 80 b8 96 03 00 00 03 75 36 0f b7 88 92 03 00 00 81 f9 10 03 00 00 72 27 48 8b 80 a8 03 00 00 <48> 83 78 18 00 74 19 48 89 df 48 8b 75 b0 ba 02 00 00 00 4c 89 e9 RSP: 0018:ffffab740c53fcf8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffffa1bc5f678000 RCX: 0000000000000310 RDX: fffffffffffffdff RSI: 0000000000000286 RDI: ffffa1be9655b840 RBP: ffffab740c53fd70 R08: 00001b7d5edaa20c R09: ffffffffb005e060 R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000000 R13: ffffab740c53fd3e R14: 0000000000000032 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffffa1be96540000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000018 CR3: 000000022e80c005 CR4: 00000000003706e0 Call Trace: hub_event+0x73f/0x156e ? hub_activate+0x5b7/0x68f process_one_work+0x1a2/0x487 worker_thread+0x11a/0x288 kthread+0x13a/0x152 ? process_one_work+0x487/0x487 ? kthread_associate_blkcg+0x70/0x70 ret_from_fork+0x1f/0x30 Fall back to a default behavior if the BOS descriptor isn't accessible and skip all the functionalities that depend on it: LPM support checks, Super Speed capabilitiy checks, U1/U2 states setup. Signed-off-by: Ricardo Cañuelo <ricardo.canuelo@collabora.com> Cc: stable <stable@vger.kernel.org> Link: https://lore.kernel.org/r/20230830100418.1952143-1-ricardo.canuelo@collabora.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
Completed in 1083 milliseconds