[PATCH 0/3] Modernize tasklet callback API
Hi,
This is the infrastructure changes to prepare the tasklet API for conversion to passing the tasklet struct as the callback argument instead of an arbitrary unsigned long. The first patch details why this is useful (it's the same rationale as the timer_struct changes from a bit ago: less abuse during memory corruption attacks, more in line with existing ways of doing things in the kernel, save a little space in struct, etc). Notably, the existing tasklet API use is much less messy, so there is less to clean up.
It's not clear to me which tree this should go through... Greg since it starts with a USB clean-up, -tip for timer or interrupt, or if I should just carry it. I'm open to suggestions, but if I don't hear otherwise, I'll just carry it.
My goal is to have this merged for v5.9-rc1 so that during the v5.10 development cycle the new API will be available. The entire tree of changes is here[1] currently, but to split it up by maintainer the infrastructure changes need to be landed first.
Review and Acks appreciated! :)
Thanks,
-Kees
[1] https://github.com/allenpais/tasklets/commits/tasklets_V2
Kees Cook (2): usb: gadget: udc: Avoid tasklet passing a global treewide: Replace DECLARE_TASKLET() with DECLARE_TASKLET_OLD()
Romain Perier (1): tasklet: Introduce new initialization API
drivers/input/keyboard/omap-keypad.c | 2 +- drivers/input/serio/hil_mlc.c | 2 +- drivers/net/wan/farsync.c | 4 +-- drivers/s390/crypto/ap_bus.c | 2 +- drivers/staging/most/dim2/dim2.c | 2 +- drivers/staging/octeon/ethernet-tx.c | 2 +- drivers/tty/vt/keyboard.c | 2 +- drivers/usb/gadget/udc/snps_udc_core.c | 6 ++--- drivers/usb/host/fhci-sched.c | 2 +- include/linux/interrupt.h | 37 ++++++++++++++++++++++---- kernel/backtracetest.c | 2 +- kernel/debug/debug_core.c | 2 +- kernel/irq/resend.c | 2 +- kernel/softirq.c | 18 ++++++++++++- net/atm/pppoatm.c | 2 +- net/iucv/iucv.c | 2 +- sound/drivers/pcsp/pcsp_lib.c | 2 +- 17 files changed, 66 insertions(+), 25 deletions(-)
There's no reason for the tasklet callback to set an argument since it always uses a global. Instead, use the global directly, in preparation for converting the tasklet subsystem to modern callback conventions.
Signed-off-by: Kees Cook keescook@chromium.org --- drivers/usb/gadget/udc/snps_udc_core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/usb/gadget/udc/snps_udc_core.c b/drivers/usb/gadget/udc/snps_udc_core.c index 3fcded31405a..afdd28f332ce 100644 --- a/drivers/usb/gadget/udc/snps_udc_core.c +++ b/drivers/usb/gadget/udc/snps_udc_core.c @@ -96,9 +96,7 @@ static int stop_pollstall_timer; static DECLARE_COMPLETION(on_pollstall_exit);
/* tasklet for usb disconnect */ -static DECLARE_TASKLET(disconnect_tasklet, udc_tasklet_disconnect, - (unsigned long) &udc); - +static DECLARE_TASKLET(disconnect_tasklet, udc_tasklet_disconnect, 0);
/* endpoint names used for print */ static const char ep0_string[] = "ep0in"; @@ -1661,7 +1659,7 @@ static void usb_disconnect(struct udc *dev) /* Tasklet for disconnect to be outside of interrupt context */ static void udc_tasklet_disconnect(unsigned long par) { - struct udc *dev = (struct udc *)(*((struct udc **) par)); + struct udc *dev = udc; u32 tmp;
DBG(dev, "Tasklet disconnect\n");
On Wed, Jul 15, 2020 at 08:08:45PM -0700, Kees Cook wrote:
There's no reason for the tasklet callback to set an argument since it always uses a global. Instead, use the global directly, in preparation for converting the tasklet subsystem to modern callback conventions.
Signed-off-by: Kees Cook keescook@chromium.org
drivers/usb/gadget/udc/snps_udc_core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/usb/gadget/udc/snps_udc_core.c b/drivers/usb/gadget/udc/snps_udc_core.c index 3fcded31405a..afdd28f332ce 100644 --- a/drivers/usb/gadget/udc/snps_udc_core.c +++ b/drivers/usb/gadget/udc/snps_udc_core.c @@ -96,9 +96,7 @@ static int stop_pollstall_timer; static DECLARE_COMPLETION(on_pollstall_exit);
/* tasklet for usb disconnect */ -static DECLARE_TASKLET(disconnect_tasklet, udc_tasklet_disconnect,
(unsigned long) &udc);
+static DECLARE_TASKLET(disconnect_tasklet, udc_tasklet_disconnect, 0);
/* endpoint names used for print */ static const char ep0_string[] = "ep0in"; @@ -1661,7 +1659,7 @@ static void usb_disconnect(struct udc *dev) /* Tasklet for disconnect to be outside of interrupt context */ static void udc_tasklet_disconnect(unsigned long par) {
- struct udc *dev = (struct udc *)(*((struct udc **) par));
struct udc *dev = udc; u32 tmp;
DBG(dev, "Tasklet disconnect\n");
Feel free to just take this in your tree, no need to wait for the USB stuff to land.
Reviewed-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
On Thu, Jul 16, 2020 at 09:28:23AM +0200, Greg Kroah-Hartman wrote:
On Wed, Jul 15, 2020 at 08:08:45PM -0700, Kees Cook wrote:
There's no reason for the tasklet callback to set an argument since it always uses a global. Instead, use the global directly, in preparation for converting the tasklet subsystem to modern callback conventions.
Signed-off-by: Kees Cook keescook@chromium.org
drivers/usb/gadget/udc/snps_udc_core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/usb/gadget/udc/snps_udc_core.c b/drivers/usb/gadget/udc/snps_udc_core.c index 3fcded31405a..afdd28f332ce 100644 --- a/drivers/usb/gadget/udc/snps_udc_core.c +++ b/drivers/usb/gadget/udc/snps_udc_core.c @@ -96,9 +96,7 @@ static int stop_pollstall_timer; static DECLARE_COMPLETION(on_pollstall_exit);
/* tasklet for usb disconnect */ -static DECLARE_TASKLET(disconnect_tasklet, udc_tasklet_disconnect,
(unsigned long) &udc);
+static DECLARE_TASKLET(disconnect_tasklet, udc_tasklet_disconnect, 0);
/* endpoint names used for print */ static const char ep0_string[] = "ep0in"; @@ -1661,7 +1659,7 @@ static void usb_disconnect(struct udc *dev) /* Tasklet for disconnect to be outside of interrupt context */ static void udc_tasklet_disconnect(unsigned long par) {
- struct udc *dev = (struct udc *)(*((struct udc **) par));
struct udc *dev = udc; u32 tmp;
DBG(dev, "Tasklet disconnect\n");
Feel free to just take this in your tree, no need to wait for the USB stuff to land.
Reviewed-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
Okay, thanks! I'll carry this series for v5.9, unless I hear otherwise from Thomas. :)
Hi,
Kees Cook keescook@chromium.org writes:
There's no reason for the tasklet callback to set an argument since it always uses a global. Instead, use the global directly, in preparation for converting the tasklet subsystem to modern callback conventions.
Signed-off-by: Kees Cook keescook@chromium.org
looks okay to me.
Acked-by: Felipe Balbi balbi@kernel.org
This converts all the existing DECLARE_TASKLET() (and ...DISABLED) macros with DECLARE_TASKLET_OLD() in preparation for refactoring the tasklet callback type. All existing DECLARE_TASKLET() users had a "0" data argument, it has been removed here as well.
Signed-off-by: Kees Cook keescook@chromium.org --- drivers/input/keyboard/omap-keypad.c | 2 +- drivers/input/serio/hil_mlc.c | 2 +- drivers/net/wan/farsync.c | 4 ++-- drivers/s390/crypto/ap_bus.c | 2 +- drivers/staging/most/dim2/dim2.c | 2 +- drivers/staging/octeon/ethernet-tx.c | 2 +- drivers/tty/vt/keyboard.c | 2 +- drivers/usb/gadget/udc/snps_udc_core.c | 2 +- drivers/usb/host/fhci-sched.c | 2 +- include/linux/interrupt.h | 15 ++++++++++----- kernel/backtracetest.c | 2 +- kernel/debug/debug_core.c | 2 +- kernel/irq/resend.c | 2 +- net/atm/pppoatm.c | 2 +- net/iucv/iucv.c | 2 +- sound/drivers/pcsp/pcsp_lib.c | 2 +- 16 files changed, 26 insertions(+), 21 deletions(-)
diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c index 5fe7a5633e33..dbe836c7ff47 100644 --- a/drivers/input/keyboard/omap-keypad.c +++ b/drivers/input/keyboard/omap-keypad.c @@ -46,7 +46,7 @@ struct omap_kp { unsigned short keymap[]; };
-static DECLARE_TASKLET_DISABLED(kp_tasklet, omap_kp_tasklet, 0); +static DECLARE_TASKLET_DISABLED_OLD(kp_tasklet, omap_kp_tasklet);
static unsigned int *row_gpios; static unsigned int *col_gpios; diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c index e1423f7648d6..65f4e9d62a67 100644 --- a/drivers/input/serio/hil_mlc.c +++ b/drivers/input/serio/hil_mlc.c @@ -77,7 +77,7 @@ static struct timer_list hil_mlcs_kicker; static int hil_mlcs_probe;
static void hil_mlcs_process(unsigned long unused); -static DECLARE_TASKLET_DISABLED(hil_mlcs_tasklet, hil_mlcs_process, 0); +static DECLARE_TASKLET_DISABLED_OLD(hil_mlcs_tasklet, hil_mlcs_process);
/* #define HIL_MLC_DEBUG */ diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index 7916efce7188..f5198a391417 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -569,8 +569,8 @@ static void do_bottom_half_rx(struct fst_card_info *card); static void fst_process_tx_work_q(unsigned long work_q); static void fst_process_int_work_q(unsigned long work_q);
-static DECLARE_TASKLET(fst_tx_task, fst_process_tx_work_q, 0); -static DECLARE_TASKLET(fst_int_task, fst_process_int_work_q, 0); +static DECLARE_TASKLET_OLD(fst_tx_task, fst_process_tx_work_q); +static DECLARE_TASKLET_OLD(fst_int_task, fst_process_int_work_q);
static struct fst_card_info *fst_card_array[FST_MAX_CARDS]; static spinlock_t fst_work_q_lock; diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index e71ca4a719a5..2589ccd257e3 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -93,7 +93,7 @@ static DECLARE_WORK(ap_scan_work, ap_scan_bus); * Tasklet & timer for AP request polling and interrupts */ static void ap_tasklet_fn(unsigned long); -static DECLARE_TASKLET(ap_tasklet, ap_tasklet_fn, 0); +static DECLARE_TASKLET_OLD(ap_tasklet, ap_tasklet_fn); static DECLARE_WAIT_QUEUE_HEAD(ap_poll_wait); static struct task_struct *ap_poll_kthread; static DEFINE_MUTEX(ap_poll_thread_mutex); diff --git a/drivers/staging/most/dim2/dim2.c b/drivers/staging/most/dim2/dim2.c index 8e0f27e61652..509c8012d20b 100644 --- a/drivers/staging/most/dim2/dim2.c +++ b/drivers/staging/most/dim2/dim2.c @@ -46,7 +46,7 @@ MODULE_PARM_DESC(fcnt, "Num of frames per sub-buffer for sync channels as a powe static DEFINE_SPINLOCK(dim_lock);
static void dim2_tasklet_fn(unsigned long data); -static DECLARE_TASKLET(dim2_tasklet, dim2_tasklet_fn, 0); +static DECLARE_TASKLET_OLD(dim2_tasklet, dim2_tasklet_fn);
/** * struct hdm_channel - private structure to keep channel specific data diff --git a/drivers/staging/octeon/ethernet-tx.c b/drivers/staging/octeon/ethernet-tx.c index ab7dd8216006..9c71ad5af7b9 100644 --- a/drivers/staging/octeon/ethernet-tx.c +++ b/drivers/staging/octeon/ethernet-tx.c @@ -41,7 +41,7 @@ #endif
static void cvm_oct_tx_do_cleanup(unsigned long arg); -static DECLARE_TASKLET(cvm_oct_tx_cleanup_tasklet, cvm_oct_tx_do_cleanup, 0); +static DECLARE_TASKLET_OLD(cvm_oct_tx_cleanup_tasklet, cvm_oct_tx_do_cleanup);
/* Maximum number of SKBs to try to free per xmit packet. */ #define MAX_SKB_TO_FREE (MAX_OUT_QUEUE_DEPTH * 2) diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 568b2171f335..f80199984ee0 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -1236,7 +1236,7 @@ static void kbd_bh(unsigned long dummy) } }
-DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0); +DECLARE_TASKLET_DISABLED_OLD(keyboard_tasklet, kbd_bh);
#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\ defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\ diff --git a/drivers/usb/gadget/udc/snps_udc_core.c b/drivers/usb/gadget/udc/snps_udc_core.c index afdd28f332ce..e76f1a50b0fc 100644 --- a/drivers/usb/gadget/udc/snps_udc_core.c +++ b/drivers/usb/gadget/udc/snps_udc_core.c @@ -96,7 +96,7 @@ static int stop_pollstall_timer; static DECLARE_COMPLETION(on_pollstall_exit);
/* tasklet for usb disconnect */ -static DECLARE_TASKLET(disconnect_tasklet, udc_tasklet_disconnect, 0); +static DECLARE_TASKLET_OLD(disconnect_tasklet, udc_tasklet_disconnect);
/* endpoint names used for print */ static const char ep0_string[] = "ep0in"; diff --git a/drivers/usb/host/fhci-sched.c b/drivers/usb/host/fhci-sched.c index 3235d5307403..5c423f240a1f 100644 --- a/drivers/usb/host/fhci-sched.c +++ b/drivers/usb/host/fhci-sched.c @@ -677,7 +677,7 @@ static void process_done_list(unsigned long data) enable_irq(fhci_to_hcd(fhci)->irq); }
-DECLARE_TASKLET(fhci_tasklet, process_done_list, 0); +DECLARE_TASKLET_OLD(fhci_tasklet, process_done_list);
/* transfer complted callback */ u32 fhci_transfer_confirm_callback(struct fhci_hcd *fhci) diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 5db970b6615a..b911196f03eb 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -612,12 +612,17 @@ struct tasklet_struct unsigned long data; };
-#define DECLARE_TASKLET(name, func, data) \ -struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data } - -#define DECLARE_TASKLET_DISABLED(name, func, data) \ -struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(1), func, data } +#define DECLARE_TASKLET_OLD(name, _func) \ +struct tasklet_struct name = { \ + .count = ATOMIC_INIT(0), \ + .func = _func, \ +}
+#define DECLARE_TASKLET_DISABLED_OLD(name, _func) \ +struct tasklet_struct name = { \ + .count = ATOMIC_INIT(1), \ + .func = _func, \ +}
enum { diff --git a/kernel/backtracetest.c b/kernel/backtracetest.c index a2a97fa3071b..370217dd7e39 100644 --- a/kernel/backtracetest.c +++ b/kernel/backtracetest.c @@ -29,7 +29,7 @@ static void backtrace_test_irq_callback(unsigned long data) complete(&backtrace_work); }
-static DECLARE_TASKLET(backtrace_tasklet, &backtrace_test_irq_callback, 0); +static DECLARE_TASKLET_OLD(backtrace_tasklet, &backtrace_test_irq_callback);
static void backtrace_test_irq(void) { diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c index 9e5934780f41..b16dbc1bf056 100644 --- a/kernel/debug/debug_core.c +++ b/kernel/debug/debug_core.c @@ -1068,7 +1068,7 @@ static void kgdb_tasklet_bpt(unsigned long ing) atomic_set(&kgdb_break_tasklet_var, 0); }
-static DECLARE_TASKLET(kgdb_tasklet_breakpoint, kgdb_tasklet_bpt, 0); +static DECLARE_TASKLET_OLD(kgdb_tasklet_breakpoint, kgdb_tasklet_bpt);
void kgdb_schedule_breakpoint(void) { diff --git a/kernel/irq/resend.c b/kernel/irq/resend.c index 27634f4022d0..c48ce19a257f 100644 --- a/kernel/irq/resend.c +++ b/kernel/irq/resend.c @@ -45,7 +45,7 @@ static void resend_irqs(unsigned long arg) }
/* Tasklet to handle resend: */ -static DECLARE_TASKLET(resend_tasklet, resend_irqs, 0); +static DECLARE_TASKLET_OLD(resend_tasklet, resend_irqs);
static int irq_sw_resend(struct irq_desc *desc) { diff --git a/net/atm/pppoatm.c b/net/atm/pppoatm.c index 45d8e1d5d033..579b66da1d95 100644 --- a/net/atm/pppoatm.c +++ b/net/atm/pppoatm.c @@ -393,7 +393,7 @@ static int pppoatm_assign_vcc(struct atm_vcc *atmvcc, void __user *arg) * Each PPPoATM instance has its own tasklet - this is just a * prototypical one used to initialize them */ - static const DECLARE_TASKLET(tasklet_proto, pppoatm_wakeup_sender, 0); + static const DECLARE_TASKLET_OLD(tasklet_proto, pppoatm_wakeup_sender); if (copy_from_user(&be, arg, sizeof be)) return -EFAULT; if (be.encaps != PPPOATM_ENCAPS_AUTODETECT && diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c index 19250a0c85d3..cd2e468852e7 100644 --- a/net/iucv/iucv.c +++ b/net/iucv/iucv.c @@ -105,7 +105,7 @@ static LIST_HEAD(iucv_task_queue); * The tasklet for fast delivery of iucv interrupts. */ static void iucv_tasklet_fn(unsigned long); -static DECLARE_TASKLET(iucv_tasklet, iucv_tasklet_fn,0); +static DECLARE_TASKLET_OLD(iucv_tasklet, iucv_tasklet_fn);
/* * Queue of interrupt buffers for delivery via a work queue diff --git a/sound/drivers/pcsp/pcsp_lib.c b/sound/drivers/pcsp/pcsp_lib.c index 05244b11ed5e..4e79293d7f11 100644 --- a/sound/drivers/pcsp/pcsp_lib.c +++ b/sound/drivers/pcsp/pcsp_lib.c @@ -36,7 +36,7 @@ static void pcsp_call_pcm_elapsed(unsigned long priv) } }
-static DECLARE_TASKLET(pcsp_pcm_tasklet, pcsp_call_pcm_elapsed, 0); +static DECLARE_TASKLET_OLD(pcsp_pcm_tasklet, pcsp_call_pcm_elapsed);
/* write the port and returns the next expire time in ns; * called at the trigger-start and in hrtimer callback
On Wed, Jul 15, 2020 at 08:08:46PM -0700, Kees Cook wrote:
This converts all the existing DECLARE_TASKLET() (and ...DISABLED) macros with DECLARE_TASKLET_OLD() in preparation for refactoring the tasklet callback type. All existing DECLARE_TASKLET() users had a "0" data argument, it has been removed here as well.
Signed-off-by: Kees Cook keescook@chromium.org
drivers/input/keyboard/omap-keypad.c | 2 +- drivers/input/serio/hil_mlc.c | 2 +- drivers/net/wan/farsync.c | 4 ++-- drivers/s390/crypto/ap_bus.c | 2 +- drivers/staging/most/dim2/dim2.c | 2 +- drivers/staging/octeon/ethernet-tx.c | 2 +- drivers/tty/vt/keyboard.c | 2 +- drivers/usb/gadget/udc/snps_udc_core.c | 2 +- drivers/usb/host/fhci-sched.c | 2 +- include/linux/interrupt.h | 15 ++++++++++----- kernel/backtracetest.c | 2 +- kernel/debug/debug_core.c | 2 +- kernel/irq/resend.c | 2 +- net/atm/pppoatm.c | 2 +- net/iucv/iucv.c | 2 +- sound/drivers/pcsp/pcsp_lib.c | 2 +- 16 files changed, 26 insertions(+), 21 deletions(-)
Reviewed-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
On Wed, Jul 15, 2020 at 08:08:46PM -0700, Kees Cook wrote:
This converts all the existing DECLARE_TASKLET() (and ...DISABLED) macros with DECLARE_TASKLET_OLD() in preparation for refactoring the tasklet callback type. All existing DECLARE_TASKLET() users had a "0" data argument, it has been removed here as well.
Signed-off-by: Kees Cook keescook@chromium.org
[...]
16 files changed, 26 insertions(+), 21 deletions(-)
This is about 5% of what needs to change. There are 350 callers of tasklet_init(), and that still takes a 'data' argument.
On Thu, Jul 16, 2020 at 12:29:14PM +0100, Matthew Wilcox wrote:
On Wed, Jul 15, 2020 at 08:08:46PM -0700, Kees Cook wrote:
This converts all the existing DECLARE_TASKLET() (and ...DISABLED) macros with DECLARE_TASKLET_OLD() in preparation for refactoring the tasklet callback type. All existing DECLARE_TASKLET() users had a "0" data argument, it has been removed here as well.
Signed-off-by: Kees Cook keescook@chromium.org
[...]
16 files changed, 26 insertions(+), 21 deletions(-)
This is about 5% of what needs to change. There are 350 callers of tasklet_init(), and that still takes a 'data' argument.
Yup, please see the referenced tree. This "series" is just the ground-work for allowing the rest of the 350 patches to land with calls to the new tasklet_setup() API, and associated prototype and container_of() changes.
From: Romain Perier romain.perier@gmail.com
Nowadays, modern kernel subsystems that use callbacks pass the data structure associated with a given callback as argument to the callback. The tasklet subsystem remains one which passes an arbitrary unsigned long to the callback function. This has several problems:
- This keeps an extra field for storing the argument in each tasklet data structure, it bloats the tasklet_struct structure with a redundant .data field
- No type checking can be performed on this argument. Instead of using container_of() like other callback subsystems, it forces callbacks to do explicit type cast of the unsigned long argument into the required object type.
- Buffer overflows can overwrite the .func and the .data field, so an attacker can easily overwrite the function and its first argument to whatever it wants.
Add a new tasklet initialization API, via DECLARE_TASKLET() and tasklet_setup(), which will replace the existing ones.
This work is greatly inspired by the timer_struct conversion series, see commit e99e88a9d2b0 ("treewide: setup_timer() -> timer_setup()")
To avoid problems with both -Wcast-function-type (which is enabled in the kernel via -Wextra is several subsystems), and with mismatched function prototypes when build with Control Flow Integrity enabled, this adds the "use_callback" member to let the tasklet caller choose which union member to call through. Once all old API uses are removed, this and the .data member will be removed as well. (On 64-bit this does not grow the struct size as the new member fills the hole after atomic_t, which is also "int" sized.)
Signed-off-by: Romain Perier romain.perier@gmail.com Co-developed-by: Allen Pais allen.lkml@gmail.com Signed-off-by: Allen Pais allen.lkml@gmail.com Co-developed-by: Kees Cook keescook@chromium.org Signed-off-by: Kees Cook keescook@chromium.org --- include/linux/interrupt.h | 24 +++++++++++++++++++++++- kernel/softirq.c | 18 +++++++++++++++++- 2 files changed, 40 insertions(+), 2 deletions(-)
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index b911196f03eb..15570b237e53 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -608,10 +608,30 @@ struct tasklet_struct struct tasklet_struct *next; unsigned long state; atomic_t count; - void (*func)(unsigned long); + bool use_callback; + union { + void (*func)(unsigned long data); + void (*callback)(struct tasklet_struct *t); + }; unsigned long data; };
+#define DECLARE_TASKLET(name, _callback) \ +struct tasklet_struct name = { \ + .count = ATOMIC_INIT(0), \ + .callback = _callback, \ + .use_callback = true, \ +} + +#define DECLARE_TASKLET_DISABLED(name, _callback) \ +struct tasklet_struct name = { \ + .count = ATOMIC_INIT(1), \ + .callback = _callback, \ +} + +#define from_tasklet(var, callback_tasklet, tasklet_fieldname) \ + container_of(callback_tasklet, typeof(*var), tasklet_fieldname) + #define DECLARE_TASKLET_OLD(name, _func) \ struct tasklet_struct name = { \ .count = ATOMIC_INIT(0), \ @@ -691,6 +711,8 @@ extern void tasklet_kill(struct tasklet_struct *t); extern void tasklet_kill_immediate(struct tasklet_struct *t, unsigned int cpu); extern void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data); +extern void tasklet_setup(struct tasklet_struct *t, + void (*callback)(struct tasklet_struct *));
/* * Autoprobing for irqs: diff --git a/kernel/softirq.c b/kernel/softirq.c index c4201b7f42b1..292e7c2d2333 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -547,7 +547,10 @@ static void tasklet_action_common(struct softirq_action *a, if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)) BUG(); - t->func(t->data); + if (t->use_callback) + t->callback(t); + else + t->func(t->data); tasklet_unlock(t); continue; } @@ -573,6 +576,18 @@ static __latent_entropy void tasklet_hi_action(struct softirq_action *a) tasklet_action_common(a, this_cpu_ptr(&tasklet_hi_vec), HI_SOFTIRQ); }
+void tasklet_setup(struct tasklet_struct *t, + void (*callback)(struct tasklet_struct *)) +{ + t->next = NULL; + t->state = 0; + atomic_set(&t->count, 0); + t->callback = callback; + t->use_callback = true; + t->data = 0; +} +EXPORT_SYMBOL(tasklet_setup); + void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data) { @@ -580,6 +595,7 @@ void tasklet_init(struct tasklet_struct *t, t->state = 0; atomic_set(&t->count, 0); t->func = func; + t->use_callback = false; t->data = data; } EXPORT_SYMBOL(tasklet_init);
On Wed, Jul 15, 2020 at 08:08:47PM -0700, Kees Cook wrote:
From: Romain Perier romain.perier@gmail.com
Nowadays, modern kernel subsystems that use callbacks pass the data structure associated with a given callback as argument to the callback. The tasklet subsystem remains one which passes an arbitrary unsigned long to the callback function. This has several problems:
This keeps an extra field for storing the argument in each tasklet data structure, it bloats the tasklet_struct structure with a redundant .data field
No type checking can be performed on this argument. Instead of using container_of() like other callback subsystems, it forces callbacks to do explicit type cast of the unsigned long argument into the required object type.
Buffer overflows can overwrite the .func and the .data field, so an attacker can easily overwrite the function and its first argument to whatever it wants.
Add a new tasklet initialization API, via DECLARE_TASKLET() and tasklet_setup(), which will replace the existing ones.
This work is greatly inspired by the timer_struct conversion series, see commit e99e88a9d2b0 ("treewide: setup_timer() -> timer_setup()")
To avoid problems with both -Wcast-function-type (which is enabled in the kernel via -Wextra is several subsystems), and with mismatched function prototypes when build with Control Flow Integrity enabled, this adds the "use_callback" member to let the tasklet caller choose which union member to call through. Once all old API uses are removed, this and the .data member will be removed as well. (On 64-bit this does not grow the struct size as the new member fills the hole after atomic_t, which is also "int" sized.)
Signed-off-by: Romain Perier romain.perier@gmail.com Co-developed-by: Allen Pais allen.lkml@gmail.com Signed-off-by: Allen Pais allen.lkml@gmail.com Co-developed-by: Kees Cook keescook@chromium.org Signed-off-by: Kees Cook keescook@chromium.org
include/linux/interrupt.h | 24 +++++++++++++++++++++++- kernel/softirq.c | 18 +++++++++++++++++- 2 files changed, 40 insertions(+), 2 deletions(-)
Reviewed-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
On Wed, Jul 15, 2020 at 08:08:47PM -0700, Kees Cook wrote:
+#define DECLARE_TASKLET(name, _callback) \ +struct tasklet_struct name = { \
- .count = ATOMIC_INIT(0), \
- .callback = _callback, \
- .use_callback = true, \
+}
+#define DECLARE_TASKLET_DISABLED(name, _callback) \ +struct tasklet_struct name = { \
- .count = ATOMIC_INIT(1), \
- .callback = _callback, \
+}
You forgot to set use_callback here.
@@ -547,7 +547,10 @@ static void tasklet_action_common(struct softirq_action *a, if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)) BUG();
t->func(t->data);
if (t->use_callback)
t->callback(t);
else
t->func(t->data);
I think this is the wrong way to do the conversion. Start out by setting t->data to (unsigned long)t in the new initialisers. Then convert the drivers (all 350 of them) to the new API. Then you can get rid of 'data' from the tasklet_struct.
On Thu, Jul 16, 2020 at 04:37:04PM +0100, Matthew Wilcox wrote:
On Wed, Jul 15, 2020 at 08:08:47PM -0700, Kees Cook wrote:
+#define DECLARE_TASKLET(name, _callback) \ +struct tasklet_struct name = { \
- .count = ATOMIC_INIT(0), \
- .callback = _callback, \
- .use_callback = true, \
+}
+#define DECLARE_TASKLET_DISABLED(name, _callback) \ +struct tasklet_struct name = { \
- .count = ATOMIC_INIT(1), \
- .callback = _callback, \
+}
You forgot to set use_callback here.
Eek; thank you.
@@ -547,7 +547,10 @@ static void tasklet_action_common(struct softirq_action *a, if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)) BUG();
t->func(t->data);
if (t->use_callback)
t->callback(t);
else
t->func(t->data);
I think this is the wrong way to do the conversion. Start out by setting t->data to (unsigned long)t in the new initialisers. Then convert the drivers (all 350 of them) to the new API. Then you can get rid of 'data' from the tasklet_struct.
That's what I did when I converted timer_struct, and it ended up creating a mess for Control Flow Integrity checking. (The problem isn't actually casting .data, but rather in how the callsite calls the callback -- casting the callback assignments doesn't fix the mismatch between the caller and the callback's expectation about the function prototype under CFI.) I got lucky with timer_struct (in v4.14) in that not much had been converted, and I was able to do the entire conversion in the next kernel release.
So, this time, I'm trying to avoid the prototype mismatch mess by providing a selector to determine which prototype the callback should be called through, and I was happy to discover I could do it without growing the tasklet structure. Obviously the memory corruption safety improvement won't be realized until both .data, .use_callback, and .func are removed, but that was true even with the earlier style of conversion.
On Wed, Jul 15, 2020 at 08:08:44PM -0700, Kees Cook wrote:
Hi,
This is the infrastructure changes to prepare the tasklet API for conversion to passing the tasklet struct as the callback argument instead of an arbitrary unsigned long. The first patch details why this is useful (it's the same rationale as the timer_struct changes from a bit ago: less abuse during memory corruption attacks, more in line with existing ways of doing things in the kernel, save a little space in struct, etc). Notably, the existing tasklet API use is much less messy, so there is less to clean up.
I would _MUCH_ rather see tasklets go the way of the dodo, esp. given that:
drivers/input/keyboard/omap-keypad.c | 2 +- drivers/input/serio/hil_mlc.c | 2 +- drivers/net/wan/farsync.c | 4 +-- drivers/s390/crypto/ap_bus.c | 2 +- drivers/staging/most/dim2/dim2.c | 2 +- drivers/staging/octeon/ethernet-tx.c | 2 +- drivers/tty/vt/keyboard.c | 2 +- drivers/usb/gadget/udc/snps_udc_core.c | 6 ++--- drivers/usb/host/fhci-sched.c | 2 +- include/linux/interrupt.h | 37 ++++++++++++++++++++++---- kernel/backtracetest.c | 2 +- kernel/debug/debug_core.c | 2 +- kernel/irq/resend.c | 2 +- kernel/softirq.c | 18 ++++++++++++- net/atm/pppoatm.c | 2 +- net/iucv/iucv.c | 2 +- sound/drivers/pcsp/pcsp_lib.c | 2 +- 17 files changed, 66 insertions(+), 25 deletions(-)
there appear to be hardly any users left.. Can't we stage an extinction event here instead?
On 2020-07-16 09:57:18 [+0200], Peter Zijlstra wrote:
there appear to be hardly any users left.. Can't we stage an extinction event here instead?
Most of the time the tasklet is scheduled from an interrupt handler. So we could get rid of these tasklets by using threaded IRQs.
Sebastian
On Thu, Jul 16, 2020 at 10:15:38AM +0200, Sebastian Andrzej Siewior wrote:
On 2020-07-16 09:57:18 [+0200], Peter Zijlstra wrote:
there appear to be hardly any users left.. Can't we stage an extinction event here instead?
Most of the time the tasklet is scheduled from an interrupt handler. So we could get rid of these tasklets by using threaded IRQs.
Perhaps I can add a comment above the tasklet API area in interrupt.h?
On Thu, Jul 16, 2020 at 09:57:18AM +0200, Peter Zijlstra wrote:
On Wed, Jul 15, 2020 at 08:08:44PM -0700, Kees Cook wrote:
Hi,
This is the infrastructure changes to prepare the tasklet API for conversion to passing the tasklet struct as the callback argument instead of an arbitrary unsigned long. The first patch details why this is useful (it's the same rationale as the timer_struct changes from a bit ago: less abuse during memory corruption attacks, more in line with existing ways of doing things in the kernel, save a little space in struct, etc). Notably, the existing tasklet API use is much less messy, so there is less to clean up.
I would _MUCH_ rather see tasklets go the way of the dodo, esp. given that:
drivers/input/keyboard/omap-keypad.c | 2 +- drivers/input/serio/hil_mlc.c | 2 +- drivers/net/wan/farsync.c | 4 +-- drivers/s390/crypto/ap_bus.c | 2 +- drivers/staging/most/dim2/dim2.c | 2 +- drivers/staging/octeon/ethernet-tx.c | 2 +- drivers/tty/vt/keyboard.c | 2 +- drivers/usb/gadget/udc/snps_udc_core.c | 6 ++--- drivers/usb/host/fhci-sched.c | 2 +- include/linux/interrupt.h | 37 ++++++++++++++++++++++---- kernel/backtracetest.c | 2 +- kernel/debug/debug_core.c | 2 +- kernel/irq/resend.c | 2 +- kernel/softirq.c | 18 ++++++++++++- net/atm/pppoatm.c | 2 +- net/iucv/iucv.c | 2 +- sound/drivers/pcsp/pcsp_lib.c | 2 +- 17 files changed, 66 insertions(+), 25 deletions(-)
there appear to be hardly any users left.. Can't we stage an extinction event here instead?
Oh, I wish, but no. That's just the ones using DECLARE_TASKLET. There are hundred(s?) more (see the referenced tree).
On Thu, Jul 16, 2020 at 12:14 PM Kees Cook keescook@chromium.org wrote:
On Thu, Jul 16, 2020 at 09:57:18AM +0200, Peter Zijlstra wrote:
On Wed, Jul 15, 2020 at 08:08:44PM -0700, Kees Cook wrote:
Hi,
This is the infrastructure changes to prepare the tasklet API for conversion to passing the tasklet struct as the callback argument instead of an arbitrary unsigned long. The first patch details why this is useful (it's the same rationale as the timer_struct changes from a bit ago: less abuse during memory corruption attacks, more in line with existing ways of doing things in the kernel, save a little space in struct, etc). Notably, the existing tasklet API use is much less messy, so there is less to clean up.
I would _MUCH_ rather see tasklets go the way of the dodo, esp. given that:
drivers/input/keyboard/omap-keypad.c | 2 +- drivers/input/serio/hil_mlc.c | 2 +- drivers/net/wan/farsync.c | 4 +-- drivers/s390/crypto/ap_bus.c | 2 +- drivers/staging/most/dim2/dim2.c | 2 +- drivers/staging/octeon/ethernet-tx.c | 2 +- drivers/tty/vt/keyboard.c | 2 +- drivers/usb/gadget/udc/snps_udc_core.c | 6 ++--- drivers/usb/host/fhci-sched.c | 2 +- include/linux/interrupt.h | 37 ++++++++++++++++++++++---- kernel/backtracetest.c | 2 +- kernel/debug/debug_core.c | 2 +- kernel/irq/resend.c | 2 +- kernel/softirq.c | 18 ++++++++++++- net/atm/pppoatm.c | 2 +- net/iucv/iucv.c | 2 +- sound/drivers/pcsp/pcsp_lib.c | 2 +- 17 files changed, 66 insertions(+), 25 deletions(-)
there appear to be hardly any users left.. Can't we stage an extinction event here instead?
Oh, I wish, but no. That's just the ones using DECLARE_TASKLET. There are hundred(s?) more (see the referenced tree).
Still, do we really need tasklets? Can we substitute timers executing immediately in their place?
Thanks.
On Thu, Jul 16, 2020 at 01:48:20PM -0700, Dmitry Torokhov wrote:
On Thu, Jul 16, 2020 at 12:14 PM Kees Cook keescook@chromium.org wrote:
On Thu, Jul 16, 2020 at 09:57:18AM +0200, Peter Zijlstra wrote:
On Wed, Jul 15, 2020 at 08:08:44PM -0700, Kees Cook wrote:
Hi,
This is the infrastructure changes to prepare the tasklet API for conversion to passing the tasklet struct as the callback argument instead of an arbitrary unsigned long. The first patch details why this is useful (it's the same rationale as the timer_struct changes from a bit ago: less abuse during memory corruption attacks, more in line with existing ways of doing things in the kernel, save a little space in struct, etc). Notably, the existing tasklet API use is much less messy, so there is less to clean up.
I would _MUCH_ rather see tasklets go the way of the dodo, esp. given that:
drivers/input/keyboard/omap-keypad.c | 2 +- drivers/input/serio/hil_mlc.c | 2 +- drivers/net/wan/farsync.c | 4 +-- drivers/s390/crypto/ap_bus.c | 2 +- drivers/staging/most/dim2/dim2.c | 2 +- drivers/staging/octeon/ethernet-tx.c | 2 +- drivers/tty/vt/keyboard.c | 2 +- drivers/usb/gadget/udc/snps_udc_core.c | 6 ++--- drivers/usb/host/fhci-sched.c | 2 +- include/linux/interrupt.h | 37 ++++++++++++++++++++++---- kernel/backtracetest.c | 2 +- kernel/debug/debug_core.c | 2 +- kernel/irq/resend.c | 2 +- kernel/softirq.c | 18 ++++++++++++- net/atm/pppoatm.c | 2 +- net/iucv/iucv.c | 2 +- sound/drivers/pcsp/pcsp_lib.c | 2 +- 17 files changed, 66 insertions(+), 25 deletions(-)
there appear to be hardly any users left.. Can't we stage an extinction event here instead?
Oh, I wish, but no. That's just the ones using DECLARE_TASKLET. There are hundred(s?) more (see the referenced tree).
Still, do we really need tasklets? Can we substitute timers executing immediately in their place?
If there is a direct replacement, then sure, I'd be happy to do whatever, however it does not look mechanical to me. If there is a mechanical way that will convert these two directories (as an example of various complexities):
drivers/crypto/ccp/ drivers/gpu/drm/i915/gt/
then let's get it documented. But if not, let's write up a paragraph for the deprecated.rst, mark it as deprecated in comments, and modernize the API (which is a mostly mechanical change) to avoid it being a problem for CFI, for memory corruption, and heap space, etc.
Kees,
Kees Cook keescook@chromium.org writes:
This is the infrastructure changes to prepare the tasklet API for conversion to passing the tasklet struct as the callback argument instead of an arbitrary unsigned long. The first patch details why this is useful (it's the same rationale as the timer_struct changes from a bit ago: less abuse during memory corruption attacks, more in line with existing ways of doing things in the kernel, save a little space in struct, etc). Notably, the existing tasklet API use is much less messy, so there is less to clean up.
It's not clear to me which tree this should go through... Greg since it starts with a USB clean-up, -tip for timer or interrupt, or if I should just carry it. I'm open to suggestions, but if I don't hear otherwise, I'll just carry it.
My goal is to have this merged for v5.9-rc1 so that during the v5.10 development cycle the new API will be available. The entire tree of changes is here[1] currently, but to split it up by maintainer the infrastructure changes need to be landed first.
Review and Acks appreciated! :)
I'd rather see tasklets vanish from the planet completely, but that's going to be a daring feat. So, grudgingly:
Acked-by: Thomas Gleixner tglx@linutronix.de
[heavily trimmed CC list because I think lkml is ignoring this thread...]
On Thu, Jul 30, 2020 at 09:03:55AM +0200, Thomas Gleixner wrote:
Kees,
Kees Cook keescook@chromium.org writes:
This is the infrastructure changes to prepare the tasklet API for conversion to passing the tasklet struct as the callback argument instead of an arbitrary unsigned long. The first patch details why this is useful (it's the same rationale as the timer_struct changes from a bit ago: less abuse during memory corruption attacks, more in line with existing ways of doing things in the kernel, save a little space in struct, etc). Notably, the existing tasklet API use is much less messy, so there is less to clean up.
It's not clear to me which tree this should go through... Greg since it starts with a USB clean-up, -tip for timer or interrupt, or if I should just carry it. I'm open to suggestions, but if I don't hear otherwise, I'll just carry it.
My goal is to have this merged for v5.9-rc1 so that during the v5.10 development cycle the new API will be available. The entire tree of changes is here[1] currently, but to split it up by maintainer the infrastructure changes need to be landed first.
Review and Acks appreciated! :)
I'd rather see tasklets vanish from the planet completely, but that's going to be a daring feat. So, grudgingly:
Understood! I will update the comments near the tasklet API.
Acked-by: Thomas Gleixner tglx@linutronix.de
Thanks!
Kees,
[heavily trimmed CC list because I think lkml is ignoring this thread...]
On Thu, Jul 30, 2020 at 09:03:55AM +0200, Thomas Gleixner wrote:
Kees,
Kees Cook keescook@chromium.org writes:
This is the infrastructure changes to prepare the tasklet API for conversion to passing the tasklet struct as the callback argument instead of an arbitrary unsigned long. The first patch details why this is useful (it's the same rationale as the timer_struct changes from a bit ago: less abuse during memory corruption attacks, more in line with existing ways of doing things in the kernel, save a little space in struct, etc). Notably, the existing tasklet API use is much less messy, so there is less to clean up.
It's not clear to me which tree this should go through... Greg since it starts with a USB clean-up, -tip for timer or interrupt, or if I should just carry it. I'm open to suggestions, but if I don't hear otherwise, I'll just carry it.
My goal is to have this merged for v5.9-rc1 so that during the v5.10 development cycle the new API will be available. The entire tree of changes is here[1] currently, but to split it up by maintainer the infrastructure changes need to be landed first.
Review and Acks appreciated! :)
I'd rather see tasklets vanish from the planet completely, but that's going to be a daring feat. So, grudgingly:
Understood! I will update the comments near the tasklet API.
Acked-by: Thomas Gleixner tglx@linutronix.de
Here's the series re-based on top of 5.8 https://github.com/allenpais/tasklets/tree/V3
Let me know how you would want these to be reviewed.
Also, I was thinking if removing tasklets completely could be a task on KSPP wiki. If yes, I did like to take ownership of that task. I have a couple of ideas in mind, which could be discussed in a separate email.
Thanks.
Kees,
Here's the series re-based on top of 5.8 https://github.com/allenpais/tasklets/tree/V3
Let me know how you would want these to be reviewed.
I see the first set of infrastructure patches for tasklets have landed in Linus's tree. Good time to send out the ~200 patches?
- Allen
On Mon, Aug 03, 2020 at 02:16:15PM +0530, Allen wrote:
Here's the series re-based on top of 5.8 https://github.com/allenpais/tasklets/tree/V3
Great!
Let me know how you would want these to be reviewed.
Was a Coccinelle script used for any of these conversions? I wonder if it'd be easier to do a single treewide patch for the more mechanical changes.
And, actually, I still think the "prepare" patches should just be collapsed into the actual "covert" patches -- there are only a few.
After those, yeah, I think getting these sent to their respective maintainers is the next step.
Also, I was thinking if removing tasklets completely could be a task on KSPP wiki. If yes, I did like to take ownership of that task. I have a couple of ideas in mind, which could be discussed in a separate email.
Sure! I will add it to the tracker. Here's for the refactoring: https://github.com/KSPP/linux/issues/30
and here's for the removal: https://github.com/KSPP/linux/issues/94
if you can added details/examples of how they should be removed, that'd help other folks too, if they wanted to jump in. :)
-Kees
On Tue, 11 Aug 2020 23:33:13 +0200, Kees Cook wrote:
On Mon, Aug 03, 2020 at 02:16:15PM +0530, Allen wrote:
Here's the series re-based on top of 5.8 https://github.com/allenpais/tasklets/tree/V3
Great!
Let me know how you would want these to be reviewed.
Was a Coccinelle script used for any of these conversions? I wonder if it'd be easier to do a single treewide patch for the more mechanical changes.
And, actually, I still think the "prepare" patches should just be collapsed into the actual "covert" patches -- there are only a few.
After those, yeah, I think getting these sent to their respective maintainers is the next step.
Also, I was thinking if removing tasklets completely could be a task on KSPP wiki. If yes, I did like to take ownership of that task. I have a couple of ideas in mind, which could be discussed in a separate email.
Sure! I will add it to the tracker. Here's for the refactoring: https://github.com/KSPP/linux/issues/30
and here's for the removal: https://github.com/KSPP/linux/issues/94
if you can added details/examples of how they should be removed, that'd help other folks too, if they wanted to jump in. :)
I have a patch set to convert the remaining tasklet usage in sound drivers to either the threaded IRQ or the work, but it wasn't submitted / merged for 5.8 due to the obvious conflict with your API changes. Each conversion is rather simple, but it's always a question of the nature of each tasklet usage which alternative is the best fit.
FWIW, the current version is found in test/kill-tasklet branch of sound git tree git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
thanks,
Takashi
I have a patch set to convert the remaining tasklet usage in sound drivers to either the threaded IRQ or the work, but it wasn't submitted / merged for 5.8 due to the obvious conflict with your API changes. Each conversion is rather simple, but it's always a question of the nature of each tasklet usage which alternative is the best fit.
FWIW, the current version is found in test/kill-tasklet branch of sound git tree git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
Great. Currently my tree has these converted to use the new tasklet_setup() api. I will add these to my threaded IRQ/work tree (which is still wip).
Thanks.
Kees,
Was a Coccinelle script used for any of these conversions? I wonder if it'd be easier to do a single treewide patch for the more mechanical changes.
No, I should have written one. Will do it.
And, actually, I still think the "prepare" patches should just be collapsed into the actual "covert" patches -- there are only a few.
Okay. It's been done and pushed to: https://github.com/allenpais/tasklets/tree/V4
After those, yeah, I think getting these sent to their respective maintainers is the next step.
Please look at the above branch, if it looks fine, let me know if I can add your ACK on the patches.
Sure! I will add it to the tracker. Here's for the refactoring: https://github.com/KSPP/linux/issues/30
and here's for the removal: https://github.com/KSPP/linux/issues/94
if you can added details/examples of how they should be removed, that'd help other folks too, if they wanted to jump in. :)
Sure, Thank you.
- Allen
participants (10)
-
Allen
-
Dmitry Torokhov
-
Felipe Balbi
-
Greg Kroah-Hartman
-
Kees Cook
-
Matthew Wilcox
-
Peter Zijlstra
-
Sebastian Andrzej Siewior
-
Takashi Iwai
-
Thomas Gleixner