]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
logind: add support for hidraw devices
authorPeter Hutterer <peter.hutterer@who-t.net>
Tue, 12 Apr 2022 04:48:04 +0000 (14:48 +1000)
committerLuca Boccassi <luca.boccassi@gmail.com>
Thu, 3 Oct 2024 08:36:57 +0000 (09:36 +0100)
Add support for opening /dev/hidraw devices via logind's TakeDevice().
Same semantics as our support for evdev devices, but it requires the
HIDIOCREVOKE ioctl in the kernel.

rules.d/71-seat.rules.in
src/basic/missing_hidraw.h [new file with mode: 0644]
src/login/logind-session-device.c
src/login/logind-session-device.h
units/systemd-logind.service.in

index 1fd7ec23b097aa87b50ec15b2e92f47060ffe2d7..8cc904c2829f7ec1ecc1e24fcfcfad8fa28908b4 100644 (file)
@@ -12,6 +12,7 @@ ACTION=="remove", GOTO="seat_end"
 TAG=="uaccess", SUBSYSTEM!="sound", TAG+="seat"
 SUBSYSTEM=="sound", KERNEL=="card*", TAG+="seat"
 SUBSYSTEM=="input", KERNEL=="input*", TAG+="seat"
+SUBSYSTEM=="hidraw", KERNEL=="hidraw*", TAG+="seat"
 SUBSYSTEM=="graphics", KERNEL=="fb[0-9]*", TAG+="seat"
 
 # Assign keyboard and LCD backlights to the seat
diff --git a/src/basic/missing_hidraw.h b/src/basic/missing_hidraw.h
new file mode 100644 (file)
index 0000000..98ba5c0
--- /dev/null
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <linux/hidraw.h>
+
+/* b31c9d9dc343146b9f4ce67b4eee748c49296e99 (6.12) */
+#ifndef HIDIOCREVOKE
+#define HIDIOCREVOKE _IOW('H', 0x0D, int)
+#endif
index 2aff0b7c8c3edca479c49945c4b1640714819722..adea60aef6be64fa5e9f9d38919935f46ac208d3 100644 (file)
@@ -16,6 +16,7 @@
 #include "logind-session-dbus.h"
 #include "logind-session-device.h"
 #include "missing_drm.h"
+#include "missing_hidraw.h"
 #include "missing_input.h"
 #include "parse-util.h"
 
@@ -105,6 +106,20 @@ static void sd_eviocrevoke(int fd) {
         }
 }
 
+static void sd_hidiocrevoke(int fd) {
+        static bool warned = false;
+
+        assert(fd >= 0);
+
+        if (!warned && ioctl(fd, HIDIOCREVOKE, NULL) < 0) {
+                if (errno == EINVAL) {
+                        log_warning_errno(errno, "Kernel does not support hidraw-revocation, continuing without revoking device access: %m");
+                        warned = true;
+                } else if (errno != ENODEV)
+                        log_warning_errno(errno, "Failed to revoke hidraw device, continuing without revoking device access: %m");
+        }
+}
+
 static int sd_drmsetmaster(int fd) {
         assert(fd >= 0);
         return RET_NERRNO(ioctl(fd, DRM_IOCTL_SET_MASTER, 0));
@@ -148,6 +163,11 @@ static int session_device_open(SessionDevice *sd, bool active) {
                         sd_eviocrevoke(fd);
                 break;
 
+        case DEVICE_TYPE_HIDRAW:
+                if (!active)
+                        sd_hidiocrevoke(fd);
+                break;
+
         case DEVICE_TYPE_UNKNOWN:
         default:
                 /* fallback for devices without synchronizations */
@@ -181,12 +201,13 @@ static int session_device_start(SessionDevice *sd) {
                 break;
 
         case DEVICE_TYPE_EVDEV:
-                /* Evdev devices are revoked while inactive. Reopen it and we are fine. */
+        case DEVICE_TYPE_HIDRAW:
+                /* Evdev/hidraw devices are revoked while inactive. Reopen it and we are fine. */
                 r = session_device_open(sd, true);
                 if (r < 0)
                         return r;
 
-                /* For evdev devices, the file descriptor might be left uninitialized. This might happen while resuming
+                /* For evdev/hidraw devices, the file descriptor might be left uninitialized. This might happen while resuming
                  * into a session and logind has been restarted right before. */
                 close_and_replace(sd->fd, r);
                 break;
@@ -230,6 +251,14 @@ static void session_device_stop(SessionDevice *sd) {
                 sd_eviocrevoke(sd->fd);
                 break;
 
+        case DEVICE_TYPE_HIDRAW:
+                /* Revoke access on hidraw file-descriptors during deactivation.
+                 * This will basically prevent any operations on the fd and
+                 * cannot be undone. Good side is: it needs no CAP_SYS_ADMIN
+                 * protection this way. */
+                sd_hidiocrevoke(sd->fd);
+                break;
+
         case DEVICE_TYPE_UNKNOWN:
         default:
                 /* fallback for devices without synchronization */
@@ -252,6 +281,9 @@ static DeviceType detect_device_type(sd_device *dev) {
         } else if (device_in_subsystem(dev, "input")) {
                 if (startswith(sysname, "event"))
                         return DEVICE_TYPE_EVDEV;
+        } else if (device_in_subsystem(dev, "hidraw")) {
+                if (startswith(sysname, "hidraw"))
+                        return DEVICE_TYPE_HIDRAW;
         }
 
         return DEVICE_TYPE_UNKNOWN;
@@ -289,6 +321,7 @@ static int session_device_verify(SessionDevice *sd) {
                 break;
 
         case DEVICE_TYPE_DRM:
+        case DEVICE_TYPE_HIDRAW:
                 break;
 
         case  DEVICE_TYPE_UNKNOWN:
index 06a8f80c060c1a3754752b97f6b59ba5a9590c51..1c6f12f21b1bddd20160ce70974bbed7c9af4e2f 100644 (file)
@@ -11,6 +11,7 @@ enum DeviceType {
         DEVICE_TYPE_UNKNOWN,
         DEVICE_TYPE_DRM,
         DEVICE_TYPE_EVDEV,
+        DEVICE_TYPE_HIDRAW,
 };
 
 struct SessionDevice {
index cc1b6be429c9632a30df88c4bad276dab5ec233f..9a918bf0b63c713adc3e6ed962a707037133ef18 100644 (file)
@@ -27,6 +27,7 @@ CapabilityBoundingSet=CAP_SYS_ADMIN CAP_MAC_ADMIN CAP_AUDIT_CONTROL CAP_CHOWN CA
 DeviceAllow=block-* r
 DeviceAllow=char-/dev/console rw
 DeviceAllow=char-drm rw
+DeviceAllow=char-hidraw rw
 DeviceAllow=char-input rw
 DeviceAllow=char-tty rw
 DeviceAllow=char-vcs rw