GNOME Screensaver

I mentioned two posts ago that I had remaining issues with my Linux laptop around firewalld and the lock screen.  The last post covered firewalld, and this one will cover the lock screen.

When I close my laptop lid I like the machine to suspend.  This is controlled in Fedora 23 by /etc/systemd/logind.conf, with the line “HandleLidSwitch=suspend”, which is the default.  However, if the last focus was on my browsing VM (as it often is) the machine would wake up to a completely logged in desktop due to VirtualBox conflicting with gnome-screensaver.  Not good!

The specific error the GNOME desktop reports in the system log is:

gnome-shell.desktop[2189]: Gjs-Message: JS LOG: error: Unable to lock: Lock was blocked by an application

I am sure that there are really good reasons to let VirtualBox block the screensaver.  The most obvious being if the machine can’t detect that it has handed control to virtualbox and starts up the screen saver despite current activity in the VM.  It could also be that there is some resource contention around grabbing control of the keyboard/mouse when some other app has that full control.  However, all of this should go out the window when the laptop goes to sleep.  Whatever the reason, it is horrible and downright unacceptable for security.

After poking around a bit I found that this had been reported previously to the developers, but it was closed with a WONTFIX and a developer statement that “there is nothing we can do about it”:

Awesome, so everyone in their right mind should stop using GNOME forever for security reasons, right?

Not quite.  After some poking around (man systemd-sleep) I found that all executables stored in /usr/lib/systemd/system-sleep will be executed when the machine is put to sleep.  There are a couple options for what can be done here:

  1. wmctrl – this is a handy cli tool which lists the currently open windows and lets you change the focus.
  2. xlock – other screensavers are not as *cough* unable to do anything about it as the GNOME project.

While using xlock was very easy (sleep a couple of seconds to let gnome fail, then run xlock & as a user), but it gives a truly 1995 feel to the lock screen which is completely inconsistent with the rest of the UI.

Instead I wrote a much more complicated shell script around wmctrl and put it in /usr/lib/systemd/system-sleep/lock


# have to grab the newest gnome-session so we don't grab gdm's d-bus session information by mistake
gsPid="`pgrep -n gnome-session | egrep '^[0-9]+$'`"
if [ -z "$gsPid" ]
 echo "gnome-session does not appear to be running" 1>&2
 exit 1

export DISPLAY=:0
export DBUS_SESSION_BUS_ADDRESS="`grep -z ^DBUS_SESSION_BUS_ADDRESS= /proc/${gsPid}/environ | cut -f2- -d=`"

desktopUser="`id -nu \"\`egrep '^[0-9]+$' /proc/${gsPid}/loginuid\`\"`"

running="`/usr/bin/sudo -E -u $desktopUser -- /usr/bin/gnome-screensaver-command --query 2>&1 | awk '{print $4}'`"

# skip everything if the screensaver is already running
if [ "$running" == "inactive" ]
 newfocus="`/usr/bin/sudo -E -u $desktopUser -- /usr/bin/wmctrl -l 2>&1 | /usr/bin/grep -v VirtualBox | /usr/bin/head -n1 | /usr/bin/cut -f5 -d\ `"
 if [ -n "$newfocus" ]
 # change window focus to a non-virtualbox window
 /usr/bin/sudo -E -u $desktopUser -- /usr/bin/wmctrl -a "$newfocus" 2>&1
 # we have no windows open that aren't virtualbox, expose the desktop instead
 /usr/bin/sudo -E -u $desktopUser -- /usr/bin/wmctrl -k on 2>&1
 # lock the screen
 /usr/bin/sudo -E -u $desktopUser -- /usr/bin/gnome-screensaver-command --lock 2>&1

I suppose complicated is an exaggeration.  It’s a horrible horrible hack though.  For the security minded, I did attempt to validate input, quote its use, and separate it from command arguments.  The window name can still contain arbitrary characters, but with how I’m passing the variable to sudo I’m comfortable with the risk on my local laptop.

Come on GNOME…  xlock can do it just fine, let’s be a little inventive and solve it properly.

At least my laptop will lock properly in the meantime.

One thought on “GNOME Screensaver

  1. Struggling against the same thing (but with VMware) right now. Tried to take a slightly different approach of using xdotool to send the VM escape sequence (Ctrl+Alt). Was hoping to catch the “Unable to lock” notification, but it does not show up in dbus-monitor at all, so I’ve got no clue what to do on that front.

    Thank you for your script, though. I tweaked it a little bit to work with xdotool to escape instead of wmctrl, but it does the job.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s