| From ea245d78dec594372e27d8c79616baf49e98a4a1 Mon Sep 17 00:00:00 2001 |
| From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| Date: Mon, 30 Mar 2026 11:14:13 +0200 |
| Subject: net: rfkill: prevent unlimited numbers of rfkill events from being created |
| |
| From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| commit ea245d78dec594372e27d8c79616baf49e98a4a1 upstream. |
| |
| Userspace can create an unlimited number of rfkill events if the system |
| is so configured, while not consuming them from the rfkill file |
| descriptor, causing a potential out of memory situation. Prevent this |
| from bounding the number of pending rfkill events at a "large" number |
| (i.e. 1000) to prevent abuses like this. |
| |
| Cc: Johannes Berg <johannes@sipsolutions.net> |
| Reported-by: Yuan Tan <yuantan098@gmail.com> |
| Reported-by: Yifan Wu <yifanwucs@gmail.com> |
| Reported-by: Juefei Pu <tomapufckgml@gmail.com> |
| Reported-by: Xin Liu <bird@lzu.edu.cn> |
| Cc: stable <stable@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| Link: https://patch.msgid.link/2026033013-disfigure-scroll-e25e@gregkh |
| Signed-off-by: Johannes Berg <johannes.berg@intel.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/rfkill/core.c | 35 ++++++++++++++++++++++++----------- |
| 1 file changed, 24 insertions(+), 11 deletions(-) |
| |
| --- a/net/rfkill/core.c |
| +++ b/net/rfkill/core.c |
| @@ -73,11 +73,14 @@ struct rfkill_int_event { |
| struct rfkill_event_ext ev; |
| }; |
| |
| +/* Max rfkill events that can be "in-flight" for one data source */ |
| +#define MAX_RFKILL_EVENT 1000 |
| struct rfkill_data { |
| struct list_head list; |
| struct list_head events; |
| struct mutex mtx; |
| wait_queue_head_t read_wait; |
| + u32 event_count; |
| bool input_handler; |
| u8 max_size; |
| }; |
| @@ -255,10 +258,12 @@ static void rfkill_global_led_trigger_un |
| } |
| #endif /* CONFIG_RFKILL_LEDS */ |
| |
| -static void rfkill_fill_event(struct rfkill_event_ext *ev, |
| - struct rfkill *rfkill, |
| - enum rfkill_operation op) |
| +static int rfkill_fill_event(struct rfkill_int_event *int_ev, |
| + struct rfkill *rfkill, |
| + struct rfkill_data *data, |
| + enum rfkill_operation op) |
| { |
| + struct rfkill_event_ext *ev = &int_ev->ev; |
| unsigned long flags; |
| |
| ev->idx = rfkill->idx; |
| @@ -271,6 +276,15 @@ static void rfkill_fill_event(struct rfk |
| RFKILL_BLOCK_SW_PREV)); |
| ev->hard_block_reasons = rfkill->hard_block_reasons; |
| spin_unlock_irqrestore(&rfkill->lock, flags); |
| + |
| + scoped_guard(mutex, &data->mtx) { |
| + if (data->event_count++ > MAX_RFKILL_EVENT) { |
| + data->event_count--; |
| + return -ENOSPC; |
| + } |
| + list_add_tail(&int_ev->list, &data->events); |
| + } |
| + return 0; |
| } |
| |
| static void rfkill_send_events(struct rfkill *rfkill, enum rfkill_operation op) |
| @@ -282,10 +296,10 @@ static void rfkill_send_events(struct rf |
| ev = kzalloc(sizeof(*ev), GFP_KERNEL); |
| if (!ev) |
| continue; |
| - rfkill_fill_event(&ev->ev, rfkill, op); |
| - mutex_lock(&data->mtx); |
| - list_add_tail(&ev->list, &data->events); |
| - mutex_unlock(&data->mtx); |
| + if (rfkill_fill_event(ev, rfkill, data, op)) { |
| + kfree(ev); |
| + continue; |
| + } |
| wake_up_interruptible(&data->read_wait); |
| } |
| } |
| @@ -1186,10 +1200,8 @@ static int rfkill_fop_open(struct inode |
| if (!ev) |
| goto free; |
| rfkill_sync(rfkill); |
| - rfkill_fill_event(&ev->ev, rfkill, RFKILL_OP_ADD); |
| - mutex_lock(&data->mtx); |
| - list_add_tail(&ev->list, &data->events); |
| - mutex_unlock(&data->mtx); |
| + if (rfkill_fill_event(ev, rfkill, data, RFKILL_OP_ADD)) |
| + kfree(ev); |
| } |
| list_add(&data->list, &rfkill_fds); |
| mutex_unlock(&rfkill_global_mutex); |
| @@ -1259,6 +1271,7 @@ static ssize_t rfkill_fop_read(struct fi |
| ret = -EFAULT; |
| |
| list_del(&ev->list); |
| + data->event_count--; |
| kfree(ev); |
| out: |
| mutex_unlock(&data->mtx); |