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 7809fd53b2b2a205
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
     1.1 --- a/README-raspberrypi.txt	Sat Oct 12 16:29:34 2013 -0300
     1.2 +++ b/README-raspberrypi.txt	Sun Oct 13 17:15:43 2013 -0300
     1.3 @@ -148,5 +148,8 @@
     1.4   Notes
     1.5  ================================================================================
     1.6  
     1.7 -* Input events from the keyboard leak through to the console
     1.8 +* When launching apps remotely (via SSH), SDL can prevent local keystrokes from
     1.9 +  leaking into the console only if it has root privileges. Launching apps locally
    1.10 +  does not suffer from this issue.
    1.11 +  
    1.12  
     2.1 --- a/src/input/evdev/SDL_evdev.c	Sat Oct 12 16:29:34 2013 -0300
     2.2 +++ b/src/input/evdev/SDL_evdev.c	Sun Oct 13 17:15:43 2013 -0300
     2.3 @@ -45,6 +45,18 @@
     2.4  #include <linux/keyboard.h>
     2.5  #endif
     2.6  
     2.7 +
     2.8 +/* We need this to prevent keystrokes from appear in the console */
     2.9 +#ifndef KDSKBMUTE
    2.10 +#define KDSKBMUTE 0x4B51
    2.11 +#endif
    2.12 +#ifndef KDSKBMODE
    2.13 +#define KDSKBMODE 0x4B45
    2.14 +#endif
    2.15 +#ifndef K_OFF
    2.16 +#define K_OFF 0x04
    2.17 +#endif
    2.18 +
    2.19  #include "SDL.h"
    2.20  #include "SDL_assert.h"
    2.21  #include "SDL_endian.h"
    2.22 @@ -370,6 +382,72 @@
    2.23      return -1;
    2.24  }
    2.25  
    2.26 +/* Prevent keystrokes from reaching the tty */
    2.27 +static int SDL_EVDEV_mute_keyboard(int tty, int *kb_mode)
    2.28 +{
    2.29 +    char arg;
    2.30 +    
    2.31 +    *kb_mode = 0; /* FIXME: Is this a sane default in case KDGKBMODE fails? */
    2.32 +    if (!IS_CONSOLE(tty)) {
    2.33 +        return SDL_SetError("Tried to mute an invalid tty");
    2.34 +    }
    2.35 +    ioctl(tty, KDGKBMODE, kb_mode); /* It's not fatal if this fails */
    2.36 +    if (ioctl(tty, KDSKBMUTE, 1) && ioctl(tty, KDSKBMODE, K_OFF)) {
    2.37 +        return SDL_SetError("EVDEV: Failed muting keyboard");
    2.38 +    }
    2.39 +    
    2.40 +    return 0;  
    2.41 +}
    2.42 +
    2.43 +/* Restore the keyboard mode for given tty */
    2.44 +static void SDL_EVDEV_unmute_keyboard(int tty, int kb_mode)
    2.45 +{
    2.46 +    if (ioctl(tty, KDSKBMUTE, 0) && ioctl(tty, KDSKBMODE, kb_mode)) {
    2.47 +        SDL_Log("EVDEV: Failed restoring keyboard mode");
    2.48 +    }
    2.49 +}
    2.50 +
    2.51 +/* Read /sys/class/tty/tty0/active and open the tty */
    2.52 +static int SDL_EVDEV_get_active_tty()
    2.53 +{
    2.54 +    int fd, len;
    2.55 +    char ttyname[NAME_MAX + 1];
    2.56 +    char ttypath[PATH_MAX+1] = "/dev/";
    2.57 +    char arg;
    2.58 +    
    2.59 +    fd = open("/sys/class/tty/tty0/active", O_RDONLY);
    2.60 +    if (fd < 0) {
    2.61 +        return SDL_SetError("Could not determine which tty is active");
    2.62 +    }
    2.63 +    
    2.64 +    len = read(fd, ttyname, NAME_MAX);
    2.65 +    close(fd);
    2.66 +    
    2.67 +    if (len <= 0) {
    2.68 +        return SDL_SetError("Could not read which tty is active");
    2.69 +    }
    2.70 +    
    2.71 +    if (ttyname[len-1] == '\n') {
    2.72 +        ttyname[len-1] = '\0';
    2.73 +    }
    2.74 +    else {
    2.75 +        ttyname[len] = '\0';
    2.76 +    }
    2.77 +    
    2.78 +    SDL_strlcat(ttypath, ttyname, PATH_MAX);
    2.79 +    fd = open(ttypath, O_RDWR | O_NOCTTY);
    2.80 +    if (fd < 0) {
    2.81 +        return SDL_SetError("Could not open tty: %s", ttypath);
    2.82 +    }
    2.83 +    
    2.84 +    if (!IS_CONSOLE(fd)) {
    2.85 +        close(fd);
    2.86 +        return SDL_SetError("Invalid tty obtained: %s", ttypath);
    2.87 +    }
    2.88 +
    2.89 +    return fd;  
    2.90 +}
    2.91 +
    2.92  int
    2.93  SDL_EVDEV_Init(void)
    2.94  {
    2.95 @@ -403,6 +481,19 @@
    2.96          
    2.97          /* We need a physical terminal (not PTS) to be able to translate key code to symbols via the kernel tables */
    2.98          _this->console_fd = SDL_EVDEV_get_console_fd();
    2.99 +        
   2.100 +        /* Mute the keyboard so keystrokes only generate evdev events and do not leak through to the console */
   2.101 +        _this->tty = STDIN_FILENO;
   2.102 +        if (SDL_EVDEV_mute_keyboard(_this->tty, &_this->kb_mode) < 0) {
   2.103 +            /* stdin is not a tty, probably we were launched remotely, so we try to disable the active tty */
   2.104 +            _this->tty = SDL_EVDEV_get_active_tty();
   2.105 +            if (_this->tty >= 0) {
   2.106 +                if (SDL_EVDEV_mute_keyboard(_this->tty, &_this->kb_mode) < 0) {
   2.107 +                    close(_this->tty);
   2.108 +                    _this->tty = -1;
   2.109 +                }
   2.110 +            }
   2.111 +        }
   2.112      }
   2.113      
   2.114      _this->ref_count += 1;
   2.115 @@ -429,6 +520,12 @@
   2.116          if (_this->console_fd >= 0) {
   2.117              close(_this->console_fd);
   2.118          }
   2.119 +        
   2.120 +        if (_this->tty >= 0) {
   2.121 +            SDL_EVDEV_unmute_keyboard(_this->tty, _this->kb_mode);
   2.122 +            close(_this->tty);
   2.123 +        }
   2.124 +        
   2.125          /* Remove existing devices */
   2.126          while(_this->first != NULL) {
   2.127              SDL_EVDEV_device_removed(_this->first->path);
     3.1 --- a/src/input/evdev/SDL_evdev.h	Sat Oct 12 16:29:34 2013 -0300
     3.2 +++ b/src/input/evdev/SDL_evdev.h	Sun Oct 13 17:15:43 2013 -0300
     3.3 @@ -43,6 +43,8 @@
     3.4      int numdevices;
     3.5      int ref_count;
     3.6      int console_fd;
     3.7 +    int kb_mode;
     3.8 +    int tty;
     3.9  } SDL_EVDEV_PrivateData;
    3.10  
    3.11  extern int SDL_EVDEV_Init(void);