summaryrefslogtreecommitdiffstats
path: root/Documentation/input/uinput.rst
diff options
context:
space:
mode:
authorMuhammad Bilal <meatuni001@gmail.com>2026-07-28 17:54:55 +0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-09-01 12:15:16 +0200
commitff917923f4fb9c83717ba135ee47d7e4c1567bb7 (patch)
treec38fd8fcf58e1937b17fdbc6518b6f8b797fc15a /Documentation/input/uinput.rst
downloadlinux-stable-ff917923f4fb9c83717ba135ee47d7e4c1567bb7.tar.gz
linux-stable-ff917923f4fb9c83717ba135ee47d7e4c1567bb7.zip
staging: rtl8723bs: fix OOB read in rtw_action_frame_parse()grafted
rtw_action_frame_parse() takes a frame_len parameter but never actually checks it before indexing into the frame body: const u8 *frame_body = frame + sizeof(struct ieee80211_hdr_3addr); ... c = frame_body[0]; ... a = frame_body[1]; frame_body already points 24 bytes (sizeof(struct ieee80211_hdr_3addr)) into frame, so reading frame_body[0] and frame_body[1] requires frame_len >= 26. A management action frame shorter than that (e.g. exactly 24 bytes, the minimum a malicious peer can send) causes a 1-2 byte out-of-bounds read. This is reachable from rtw_cfg80211_monitor_if_xmit_entry() and cfg80211_rtw_mgmt_tx() in ioctl_cfg80211.c, both of which pass attacker/user-influenced frame buffers and lengths straight through. Add the missing length check before frame_body is dereferenced. Fixes: 554c0a3abf216 ("staging: Add rtl8723bs sdio wifi driver") Cc: stable@vger.kernel.org Signed-off-by: Muhammad Bilal <meatuni001@gmail.com> Link: https://patch.msgid.link/20260728125456.32359-3-meatuni001@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'Documentation/input/uinput.rst')
-rw-r--r--Documentation/input/uinput.rst245
1 files changed, 245 insertions, 0 deletions
diff --git a/Documentation/input/uinput.rst b/Documentation/input/uinput.rst
new file mode 100644
index 000000000..30fe80e32
--- /dev/null
+++ b/Documentation/input/uinput.rst
@@ -0,0 +1,245 @@
+=============
+uinput module
+=============
+
+Introduction
+============
+
+uinput is a kernel module that makes it possible to emulate input devices
+from userspace. By writing to /dev/uinput (or /dev/input/uinput) device, a
+process can create a virtual input device with specific capabilities. Once
+this virtual device is created, the process can send events through it,
+that will be delivered to userspace and in-kernel consumers.
+
+Interface
+=========
+
+::
+
+ linux/uinput.h
+
+The uinput header defines ioctls to create, set up, and destroy virtual
+devices.
+
+libevdev
+========
+
+libevdev is a wrapper library for evdev devices that provides interfaces to
+create uinput devices and send events. libevdev is less error-prone than
+accessing uinput directly, and should be considered for new software.
+
+For examples and more information about libevdev:
+https://www.freedesktop.org/software/libevdev/doc/latest/
+
+Examples
+========
+
+Keyboard events
+---------------
+
+This first example shows how to create a new virtual device, and how to
+send a key event. All default imports and error handlers were removed for
+the sake of simplicity.
+
+.. code-block:: c
+
+ #include <linux/uinput.h>
+
+ void emit(int fd, int type, int code, int val)
+ {
+ struct input_event ie;
+
+ ie.type = type;
+ ie.code = code;
+ ie.value = val;
+ /* timestamp values below are ignored */
+ ie.time.tv_sec = 0;
+ ie.time.tv_usec = 0;
+
+ write(fd, &ie, sizeof(ie));
+ }
+
+ int main(void)
+ {
+ struct uinput_setup usetup;
+
+ int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
+
+
+ /*
+ * The ioctls below will enable the device that is about to be
+ * created, to pass key events, in this case the space key.
+ */
+ ioctl(fd, UI_SET_EVBIT, EV_KEY);
+ ioctl(fd, UI_SET_KEYBIT, KEY_SPACE);
+
+ memset(&usetup, 0, sizeof(usetup));
+ usetup.id.bustype = BUS_USB;
+ usetup.id.vendor = 0x1234; /* sample vendor */
+ usetup.id.product = 0x5678; /* sample product */
+ strcpy(usetup.name, "Example device");
+
+ ioctl(fd, UI_DEV_SETUP, &usetup);
+ ioctl(fd, UI_DEV_CREATE);
+
+ /*
+ * On UI_DEV_CREATE the kernel will create the device node for this
+ * device. We are inserting a pause here so that userspace has time
+ * to detect, initialize the new device, and can start listening to
+ * the event, otherwise it will not notice the event we are about
+ * to send. This pause is only needed in our example code!
+ */
+ sleep(1);
+
+ /* Key press, report the event, send key release, and report again */
+ emit(fd, EV_KEY, KEY_SPACE, 1);
+ emit(fd, EV_SYN, SYN_REPORT, 0);
+ emit(fd, EV_KEY, KEY_SPACE, 0);
+ emit(fd, EV_SYN, SYN_REPORT, 0);
+
+ /*
+ * Give userspace some time to read the events before we destroy the
+ * device with UI_DEV_DESTROY.
+ */
+ sleep(1);
+
+ ioctl(fd, UI_DEV_DESTROY);
+ close(fd);
+
+ return 0;
+ }
+
+Mouse movements
+---------------
+
+This example shows how to create a virtual device that behaves like a physical
+mouse.
+
+.. code-block:: c
+
+ #include <linux/uinput.h>
+
+ /* emit function is identical to of the first example */
+
+ int main(void)
+ {
+ struct uinput_setup usetup;
+ int i = 50;
+
+ int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
+
+ /* enable mouse button left and relative events */
+ ioctl(fd, UI_SET_EVBIT, EV_KEY);
+ ioctl(fd, UI_SET_KEYBIT, BTN_LEFT);
+
+ ioctl(fd, UI_SET_EVBIT, EV_REL);
+ ioctl(fd, UI_SET_RELBIT, REL_X);
+ ioctl(fd, UI_SET_RELBIT, REL_Y);
+
+ memset(&usetup, 0, sizeof(usetup));
+ usetup.id.bustype = BUS_USB;
+ usetup.id.vendor = 0x1234; /* sample vendor */
+ usetup.id.product = 0x5678; /* sample product */
+ strcpy(usetup.name, "Example device");
+
+ ioctl(fd, UI_DEV_SETUP, &usetup);
+ ioctl(fd, UI_DEV_CREATE);
+
+ /*
+ * On UI_DEV_CREATE the kernel will create the device node for this
+ * device. We are inserting a pause here so that userspace has time
+ * to detect, initialize the new device, and can start listening to
+ * the event, otherwise it will not notice the event we are about
+ * to send. This pause is only needed in our example code!
+ */
+ sleep(1);
+
+ /* Move the mouse diagonally, 5 units per axis */
+ while (i--) {
+ emit(fd, EV_REL, REL_X, 5);
+ emit(fd, EV_REL, REL_Y, 5);
+ emit(fd, EV_SYN, SYN_REPORT, 0);
+ usleep(15000);
+ }
+
+ /*
+ * Give userspace some time to read the events before we destroy the
+ * device with UI_DEV_DESTROY.
+ */
+ sleep(1);
+
+ ioctl(fd, UI_DEV_DESTROY);
+ close(fd);
+
+ return 0;
+ }
+
+
+uinput old interface
+--------------------
+
+Before uinput version 5, there wasn't a dedicated ioctl to set up a virtual
+device. Programs supporting older versions of uinput interface need to fill
+a uinput_user_dev structure and write it to the uinput file descriptor to
+configure the new uinput device. New code should not use the old interface
+but interact with uinput via ioctl calls, or use libevdev.
+
+.. code-block:: c
+
+ #include <linux/uinput.h>
+
+ /* emit function is identical to of the first example */
+
+ int main(void)
+ {
+ struct uinput_user_dev uud;
+ int version, rc, fd;
+
+ fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
+ rc = ioctl(fd, UI_GET_VERSION, &version);
+
+ if (rc == 0 && version >= 5) {
+ /* use UI_DEV_SETUP */
+ return 0;
+ }
+
+ /*
+ * The ioctls below will enable the device that is about to be
+ * created, to pass key events, in this case the space key.
+ */
+ ioctl(fd, UI_SET_EVBIT, EV_KEY);
+ ioctl(fd, UI_SET_KEYBIT, KEY_SPACE);
+
+ memset(&uud, 0, sizeof(uud));
+ snprintf(uud.name, UINPUT_MAX_NAME_SIZE, "uinput old interface");
+ write(fd, &uud, sizeof(uud));
+
+ ioctl(fd, UI_DEV_CREATE);
+
+ /*
+ * On UI_DEV_CREATE the kernel will create the device node for this
+ * device. We are inserting a pause here so that userspace has time
+ * to detect, initialize the new device, and can start listening to
+ * the event, otherwise it will not notice the event we are about
+ * to send. This pause is only needed in our example code!
+ */
+ sleep(1);
+
+ /* Key press, report the event, send key release, and report again */
+ emit(fd, EV_KEY, KEY_SPACE, 1);
+ emit(fd, EV_SYN, SYN_REPORT, 0);
+ emit(fd, EV_KEY, KEY_SPACE, 0);
+ emit(fd, EV_SYN, SYN_REPORT, 0);
+
+ /*
+ * Give userspace some time to read the events before we destroy the
+ * device with UI_DEV_DESTROY.
+ */
+ sleep(1);
+
+ ioctl(fd, UI_DEV_DESTROY);
+
+ close(fd);
+ return 0;
+ }
+