]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: rfkill: prevent unlimited numbers of rfkill events from being created
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 30 Mar 2026 09:14:13 +0000 (11:14 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 7 Apr 2026 10:35:04 +0000 (12:35 +0200)
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>
net/rfkill/core.c

index 2444237bc36a44bee6f2a2addd2794c71ba5ca7d..4827e1fb8804ade237eade1a6a9a353a4096fe47 100644 (file)
@@ -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_unregister(void)
 }
 #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 rfkill_event_ext *ev,
                                        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 rfkill *rfkill, enum rfkill_operation op)
                ev = kzalloc_obj(*ev);
                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 *inode, struct file *file)
                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 file *file, char __user *buf,
                ret = -EFAULT;
 
        list_del(&ev->list);
+       data->event_count--;
        kfree(ev);
  out:
        mutex_unlock(&data->mtx);