Prevent keystrokes from leaking through to the console when using evdev.
authorGabriel Jacobo <gabomdq@gmail.com>
Sun, 13 Oct 2013 17:15:43 -0300
changeset 7809 fd53b2b2a205
parent 7808 627f256b0e56
child 7810 ab1b92bf0327
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
src/input/evdev/SDL_evdev.c
src/input/evdev/SDL_evdev.h
--- a/README-raspberrypi.txt	Sat Oct 12 16:29:34 2013 -0300
+++ b/README-raspberrypi.txt	Sun Oct 13 17:15:43 2013 -0300
@@ -148,5 +148,8 @@
  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.
+  
 
--- a/src/input/evdev/SDL_evdev.c	Sat Oct 12 16:29:34 2013 -0300
+++ b/src/input/evdev/SDL_evdev.c	Sun Oct 13 17:15:43 2013 -0300
@@ -45,6 +45,18 @@
 #include <linux/keyboard.h>
 #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 @@
     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 @@
         
         /* 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 @@
         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);
--- a/src/input/evdev/SDL_evdev.h	Sat Oct 12 16:29:34 2013 -0300
+++ b/src/input/evdev/SDL_evdev.h	Sun Oct 13 17:15:43 2013 -0300
@@ -43,6 +43,8 @@
     int numdevices;
     int ref_count;
     int console_fd;
+    int kb_mode;
+    int tty;
 } SDL_EVDEV_PrivateData;
 
 extern int SDL_EVDEV_Init(void);