]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
net: rfkill: prevent unlimited numbers of rfkill events from being created
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 12 Apr 2026 16:57:46 +0000 (12:57 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 18 Apr 2026 08:33:38 +0000 (10:33 +0200)
[ Upstream commit ea245d78dec594372e27d8c79616baf49e98a4a1 ]

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>
[ replaced `scoped_guard()` with explicit `mutex_lock()`/`mutex_unlock()` calls ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
net/rfkill/core.c

index 068c7bcd30c94b735c3f059ee63616f20ff65c99..7bcb7a9c1fcfdae257189a960bf9eb26a9a22ee1 100644 (file)
@@ -72,11 +72,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;
 };
@@ -254,10 +257,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;
@@ -270,6 +275,16 @@ 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);
+
+       mutex_lock(&data->mtx);
+       if (data->event_count++ > MAX_RFKILL_EVENT) {
+               data->event_count--;
+               mutex_unlock(&data->mtx);
+               return -ENOSPC;
+       }
+       list_add_tail(&int_ev->list, &data->events);
+       mutex_unlock(&data->mtx);
+       return 0;
 }
 
 static void rfkill_send_events(struct rfkill *rfkill, enum rfkill_operation op)
@@ -281,10 +296,10 @@ static void rfkill_send_events(struct rfkill *rfkill, enum rfkill_operation op)
                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);
        }
 }
@@ -1149,7 +1164,6 @@ static int rfkill_fop_open(struct inode *inode, struct file *file)
        init_waitqueue_head(&data->read_wait);
 
        mutex_lock(&rfkill_global_mutex);
-       mutex_lock(&data->mtx);
        /*
         * start getting events from elsewhere but hold mtx to get
         * startup events added first
@@ -1159,11 +1173,10 @@ static int rfkill_fop_open(struct inode *inode, struct file *file)
                ev = kzalloc(sizeof(*ev), GFP_KERNEL);
                if (!ev)
                        goto free;
-               rfkill_fill_event(&ev->ev, rfkill, RFKILL_OP_ADD);
-               list_add_tail(&ev->list, &data->events);
+               if (rfkill_fill_event(ev, rfkill, data, RFKILL_OP_ADD))
+                       kfree(ev);
        }
        list_add(&data->list, &rfkill_fds);
-       mutex_unlock(&data->mtx);
        mutex_unlock(&rfkill_global_mutex);
 
        file->private_data = data;
@@ -1171,7 +1184,6 @@ static int rfkill_fop_open(struct inode *inode, struct file *file)
        return stream_open(inode, file);
 
  free:
-       mutex_unlock(&data->mtx);
        mutex_unlock(&rfkill_global_mutex);
        mutex_destroy(&data->mtx);
        list_for_each_entry_safe(ev, tmp, &data->events, list)
@@ -1232,6 +1244,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);