From e9d21339345223698304772c60ca1175b618dd6d Mon Sep 17 00:00:00 2001 From: Gabriel Jacobo Date: Sun, 13 Oct 2013 17:15:43 -0300 Subject: [PATCH] Prevent keystrokes from leaking through to the console when using evdev. This uses the same method Weston and X use. Sadly, to be fully effective when launching remotely, this needs root permissions. --- README-raspberrypi.txt | 5 +- src/input/evdev/SDL_evdev.c | 97 +++++++++++++++++++++++++++++++++++++ src/input/evdev/SDL_evdev.h | 2 + 3 files changed, 103 insertions(+), 1 deletion(-) diff --git a/README-raspberrypi.txt b/README-raspberrypi.txt index 744fd89df25c7..0724a8c909df9 100644 --- a/README-raspberrypi.txt +++ b/README-raspberrypi.txt @@ -148,5 +148,8 @@ this determining the CAPS LOCK behavior: Notes ================================================================================ -* Input events from the keyboard leak through to the console +* When launching apps remotely (via SSH), SDL can prevent local keystrokes from + leaking into the console only if it has root privileges. Launching apps locally + does not suffer from this issue. + diff --git a/src/input/evdev/SDL_evdev.c b/src/input/evdev/SDL_evdev.c index 497cd40d18c7f..92dc4fed71081 100644 --- a/src/input/evdev/SDL_evdev.c +++ b/src/input/evdev/SDL_evdev.c @@ -45,6 +45,18 @@ static _THIS = NULL; #include #endif + +/* We need this to prevent keystrokes from appear in the console */ +#ifndef KDSKBMUTE +#define KDSKBMUTE 0x4B51 +#endif +#ifndef KDSKBMODE +#define KDSKBMODE 0x4B45 +#endif +#ifndef K_OFF +#define K_OFF 0x04 +#endif + #include "SDL.h" #include "SDL_assert.h" #include "SDL_endian.h" @@ -370,6 +382,72 @@ static int SDL_EVDEV_get_console_fd(void) return -1; } +/* Prevent keystrokes from reaching the tty */ +static int SDL_EVDEV_mute_keyboard(int tty, int *kb_mode) +{ + char arg; + + *kb_mode = 0; /* FIXME: Is this a sane default in case KDGKBMODE fails? */ + if (!IS_CONSOLE(tty)) { + return SDL_SetError("Tried to mute an invalid tty"); + } + ioctl(tty, KDGKBMODE, kb_mode); /* It's not fatal if this fails */ + if (ioctl(tty, KDSKBMUTE, 1) && ioctl(tty, KDSKBMODE, K_OFF)) { + return SDL_SetError("EVDEV: Failed muting keyboard"); + } + + return 0; +} + +/* Restore the keyboard mode for given tty */ +static void SDL_EVDEV_unmute_keyboard(int tty, int kb_mode) +{ + if (ioctl(tty, KDSKBMUTE, 0) && ioctl(tty, KDSKBMODE, kb_mode)) { + SDL_Log("EVDEV: Failed restoring keyboard mode"); + } +} + +/* Read /sys/class/tty/tty0/active and open the tty */ +static int SDL_EVDEV_get_active_tty() +{ + int fd, len; + char ttyname[NAME_MAX + 1]; + char ttypath[PATH_MAX+1] = "/dev/"; + char arg; + + fd = open("/sys/class/tty/tty0/active", O_RDONLY); + if (fd < 0) { + return SDL_SetError("Could not determine which tty is active"); + } + + len = read(fd, ttyname, NAME_MAX); + close(fd); + + if (len <= 0) { + return SDL_SetError("Could not read which tty is active"); + } + + if (ttyname[len-1] == '\n') { + ttyname[len-1] = '\0'; + } + else { + ttyname[len] = '\0'; + } + + SDL_strlcat(ttypath, ttyname, PATH_MAX); + fd = open(ttypath, O_RDWR | O_NOCTTY); + if (fd < 0) { + return SDL_SetError("Could not open tty: %s", ttypath); + } + + if (!IS_CONSOLE(fd)) { + close(fd); + return SDL_SetError("Invalid tty obtained: %s", ttypath); + } + + return fd; +} + int SDL_EVDEV_Init(void) { @@ -403,6 +481,19 @@ SDL_EVDEV_Init(void) /* We need a physical terminal (not PTS) to be able to translate key code to symbols via the kernel tables */ _this->console_fd = SDL_EVDEV_get_console_fd(); + + /* Mute the keyboard so keystrokes only generate evdev events and do not leak through to the console */ + _this->tty = STDIN_FILENO; + if (SDL_EVDEV_mute_keyboard(_this->tty, &_this->kb_mode) < 0) { + /* stdin is not a tty, probably we were launched remotely, so we try to disable the active tty */ + _this->tty = SDL_EVDEV_get_active_tty(); + if (_this->tty >= 0) { + if (SDL_EVDEV_mute_keyboard(_this->tty, &_this->kb_mode) < 0) { + close(_this->tty); + _this->tty = -1; + } + } + } } _this->ref_count += 1; @@ -429,6 +520,12 @@ SDL_EVDEV_Quit(void) if (_this->console_fd >= 0) { close(_this->console_fd); } + + if (_this->tty >= 0) { + SDL_EVDEV_unmute_keyboard(_this->tty, _this->kb_mode); + close(_this->tty); + } + /* Remove existing devices */ while(_this->first != NULL) { SDL_EVDEV_device_removed(_this->first->path); diff --git a/src/input/evdev/SDL_evdev.h b/src/input/evdev/SDL_evdev.h index 34f369d28712e..b9311d4f3f0fa 100644 --- a/src/input/evdev/SDL_evdev.h +++ b/src/input/evdev/SDL_evdev.h @@ -43,6 +43,8 @@ typedef struct SDL_EVDEV_PrivateData int numdevices; int ref_count; int console_fd; + int kb_mode; + int tty; } SDL_EVDEV_PrivateData; extern int SDL_EVDEV_Init(void);