diff options
| author | Vladimir Kondratyev <wulf@FreeBSD.org> | 2019-02-24 18:47:04 +0000 |
|---|---|---|
| committer | Vladimir Kondratyev <wulf@FreeBSD.org> | 2019-02-24 18:47:04 +0000 |
| commit | f99e7b1aed7ea65ca0dbe5b182f2b9cbfdfe54db (patch) | |
| tree | 1fe791e1296dd88b1ed2997d309686301805e8b6 /sys/dev/evdev/evdev.c | |
| parent | 22c58991e36a0c6ed63875b8b9f5f79d35846f5a (diff) | |
evdev: export event device properties through sysctl interface
A big security advantage of Wayland is not allowing applications to read
input devices all the time. Having /dev/input/* accessible to the user
account subverts this advantage.
libudev-devd was opening the evdev devices to detect their types (mouse,
keyboard, touchpad, etc). This don't work if /dev/input/* is inaccessible.
With the kernel exposing this information as sysctls (kern.evdev.input.*),
we can work w/o /dev/input/* access, preserving the Wayland security model.
Submitted by: Greg V <greg@unrelenting.technology>
Reviewed by: wulf, imp
MFC after: 2 weeks
Differential Revision: https://reviews.freebsd.org/D18694
Notes
svn path=/head/; revision=344494
Diffstat (limited to 'sys/dev/evdev/evdev.c')
| -rw-r--r-- | sys/dev/evdev/evdev.c | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/sys/dev/evdev/evdev.c b/sys/dev/evdev/evdev.c index 2f5eb11b96b2..ee473ea2fbd0 100644 --- a/sys/dev/evdev/evdev.c +++ b/sys/dev/evdev/evdev.c @@ -76,6 +76,8 @@ SYSCTL_INT(_kern_evdev, OID_AUTO, rcpt_mask, CTLFLAG_RW, &evdev_rcpt_mask, 0, "bit2 - mouse hardware, bit3 - keyboard hardware"); SYSCTL_INT(_kern_evdev, OID_AUTO, sysmouse_t_axis, CTLFLAG_RW, &evdev_sysmouse_t_axis, 0, "Extract T-axis from 0-none, 1-ums, 2-psm"); +SYSCTL_NODE(_kern_evdev, OID_AUTO, input, CTLFLAG_RD, 0, + "Evdev input devices"); #endif static void evdev_start_repeat(struct evdev_dev *, uint16_t); @@ -196,6 +198,87 @@ evdev_estimate_report_size(struct evdev_dev *evdev) return (size); } +static void +evdev_sysctl_create(struct evdev_dev *evdev) +{ + struct sysctl_oid *ev_sysctl_tree; + char ev_unit_str[8]; + + snprintf(ev_unit_str, sizeof(ev_unit_str), "%d", evdev->ev_unit); + sysctl_ctx_init(&evdev->ev_sysctl_ctx); + + ev_sysctl_tree = SYSCTL_ADD_NODE_WITH_LABEL(&evdev->ev_sysctl_ctx, + SYSCTL_STATIC_CHILDREN(_kern_evdev_input), OID_AUTO, + ev_unit_str, CTLFLAG_RD, NULL, "", "device index"); + + SYSCTL_ADD_STRING(&evdev->ev_sysctl_ctx, + SYSCTL_CHILDREN(ev_sysctl_tree), OID_AUTO, "name", CTLFLAG_RD, + evdev->ev_name, 0, + "Input device name"); + + SYSCTL_ADD_STRUCT(&evdev->ev_sysctl_ctx, + SYSCTL_CHILDREN(ev_sysctl_tree), OID_AUTO, "id", CTLFLAG_RD, + &evdev->ev_id, input_id, + "Input device identification"); + + /* ioctl returns ENOENT if phys is not set. sysctl returns "" here */ + SYSCTL_ADD_STRING(&evdev->ev_sysctl_ctx, + SYSCTL_CHILDREN(ev_sysctl_tree), OID_AUTO, "phys", CTLFLAG_RD, + evdev->ev_shortname, 0, + "Input device short name"); + + /* ioctl returns ENOENT if uniq is not set. sysctl returns "" here */ + SYSCTL_ADD_STRING(&evdev->ev_sysctl_ctx, + SYSCTL_CHILDREN(ev_sysctl_tree), OID_AUTO, "uniq", CTLFLAG_RD, + evdev->ev_serial, 0, + "Input device unique number"); + + SYSCTL_ADD_OPAQUE(&evdev->ev_sysctl_ctx, + SYSCTL_CHILDREN(ev_sysctl_tree), OID_AUTO, "props", CTLFLAG_RD, + evdev->ev_prop_flags, sizeof(evdev->ev_prop_flags), "", + "Input device properties"); + + SYSCTL_ADD_OPAQUE(&evdev->ev_sysctl_ctx, + SYSCTL_CHILDREN(ev_sysctl_tree), OID_AUTO, "type_bits", CTLFLAG_RD, + evdev->ev_type_flags, sizeof(evdev->ev_type_flags), "", + "Input device supported events types"); + + SYSCTL_ADD_OPAQUE(&evdev->ev_sysctl_ctx, + SYSCTL_CHILDREN(ev_sysctl_tree), OID_AUTO, "key_bits", CTLFLAG_RD, + evdev->ev_key_flags, sizeof(evdev->ev_key_flags), + "", "Input device supported keys"); + + SYSCTL_ADD_OPAQUE(&evdev->ev_sysctl_ctx, + SYSCTL_CHILDREN(ev_sysctl_tree), OID_AUTO, "rel_bits", CTLFLAG_RD, + evdev->ev_rel_flags, sizeof(evdev->ev_rel_flags), "", + "Input device supported relative events"); + + SYSCTL_ADD_OPAQUE(&evdev->ev_sysctl_ctx, + SYSCTL_CHILDREN(ev_sysctl_tree), OID_AUTO, "abs_bits", CTLFLAG_RD, + evdev->ev_abs_flags, sizeof(evdev->ev_abs_flags), "", + "Input device supported absolute events"); + + SYSCTL_ADD_OPAQUE(&evdev->ev_sysctl_ctx, + SYSCTL_CHILDREN(ev_sysctl_tree), OID_AUTO, "msc_bits", CTLFLAG_RD, + evdev->ev_msc_flags, sizeof(evdev->ev_msc_flags), "", + "Input device supported miscellaneous events"); + + SYSCTL_ADD_OPAQUE(&evdev->ev_sysctl_ctx, + SYSCTL_CHILDREN(ev_sysctl_tree), OID_AUTO, "led_bits", CTLFLAG_RD, + evdev->ev_led_flags, sizeof(evdev->ev_led_flags), "", + "Input device supported LED events"); + + SYSCTL_ADD_OPAQUE(&evdev->ev_sysctl_ctx, + SYSCTL_CHILDREN(ev_sysctl_tree), OID_AUTO, "snd_bits", CTLFLAG_RD, + evdev->ev_snd_flags, sizeof(evdev->ev_snd_flags), "", + "Input device supported sound events"); + + SYSCTL_ADD_OPAQUE(&evdev->ev_sysctl_ctx, + SYSCTL_CHILDREN(ev_sysctl_tree), OID_AUTO, "sw_bits", CTLFLAG_RD, + evdev->ev_sw_flags, sizeof(evdev->ev_sw_flags), "", + "Input device supported switch events"); +} + static int evdev_register_common(struct evdev_dev *evdev) { @@ -235,6 +318,12 @@ evdev_register_common(struct evdev_dev *evdev) /* Create char device node */ ret = evdev_cdev_create(evdev); + if (ret != 0) + goto bail_out; + + /* Create sysctls (for device enumeration without /dev/input access rights) */ + evdev_sysctl_create(evdev); + bail_out: return (ret); } @@ -272,6 +361,8 @@ evdev_unregister(struct evdev_dev *evdev) debugf(evdev, "%s: unregistered evdev provider: %s\n", evdev->ev_shortname, evdev->ev_name); + sysctl_ctx_free(&evdev->ev_sysctl_ctx); + EVDEV_LOCK(evdev); evdev->ev_cdev->si_drv1 = NULL; /* Wake up sleepers */ |
