The 14.04 release of Unity unfortunately shipped with a few security vulnerabilities in the newly introduced screenlocker. As we will also ship a reworked screenlocker in Plasma Next I started to do another code audit, add more unit tests and try to make the code easier to understand and maintain. Furthermore I think it’s a good reason to explain how screenlockers work in general on X11 (and why it is easy to introduce security vulnerabilities) and the screenlocker in Plasma Next in particular. To make one thing clear: this post is not meant to shame Ubuntu for the issues. Some of these whoopies would have been possible in Plasma, too, and that’s the reason why I looked at the code again in more detail. On the other hand I think that our screenlocker in Plasma Next could be a solution for Unity’s use cases and I would appreciate if Ubuntu would adpot our solution.
What a screenlocker should protect
Before looking at how it works in X11, I shortly want to discuss what a screenlocker can protect and what is out of scope for a screenlocker. In general there are two tasks for a screenlocker:
- Blocking input devices, so that an attacker cannot interact with the running session
- Blanking the screen to prevent private information being leaked
The lock is hold till an authorization is provided (e.g. password). I’ll discuss in more detail what these authorizations are in the case of Plasma.
There are a few things the screenlocker cannot protect against:
- Evil software already running under the user’s account
- Attackers having access to a tty running under the same user
To explain the first problem we must remember that X11 is very bad from a security point of view. This adds a general limitation to what can be protected. Getting a key logger with X11 is extremely trivial, there are easier ways to get the password than to try to attack the locker.
The second problem goes in the same direction: if someone has access to a tty, he can install an X11 key logger. It will not get the password, but still it’s a huge problem. Also the attacker could reconfigure the locker or run a debugger on the lock process to just end the locker. Some of these problems can be mitigated by the distribution through hardening (e.g. SELinux).
I plan to harden the system against these two problems in a future release. Though given the general problems of X11 it will never be possible to completely solve these two problems on X11.
How screenlockers work in X11
X11 doesn’t really know the concept of a screenlocker. Thus one needs to use the concepts of X11 to try to get something like a screenlocker. The main features are grabbing the keyboard and grabbing the pointer. What’s important to know about these two X11 features is that only one X Client is allowed to grab the keyboard and pointer. If the keyboard or pointer is already grabbed the lock cannot be established. For example if a (context) menu is open the screen cannot be locked or if Present Windows is active.
Having the keyboard and pointer grabbed are essential to fulfill the first task of the screenlocker. This also shows why it’s so difficult to get a locker right. As soon as the process grabbing the keyboard goes away the lock is released. As soon as that happens the screen is unlocked. Thus there is an easy scenario to attack a screenlocker: get the lock process to crash and restart and try to grab the keyboard before the screenlocker is able to re-install the grab.
This is the problem Unity run in and to be honest we also almost run into this issue in the past. Thus a screenlocker implementation must be able to hold the keyboard grab during a crash. A lock file might not be sufficient. I will explain later how we made the screenlocker in Plasma crash resistant, so that the session will never be unlocked.
The second task is blanking the screen. This is done by creating a lock window and raise it on top of all windows and ensure that the lock window is always on top of all windows. Given the description one can notice that this is kind of a fragile process. Assume one has two processes trying to be on top of each other: they will constantly try to raise on top of the other. Something I once experienced by having the screen locked during session startup resulting in a race between login and lock screen. Again Wayland will improve the situation as the compositor (in our case KWin) will be aware of the screenlocker and will ensure the restrictions.
Screenlocker architecture in Plasma Next
The architecture for locking screens got simplified in Plasma Next. Support for screen savers got completely removed (fear not: we have plans for replacement, probably not in Plasma Next, but in a future release) and that helped a lot to trim down the architecture.
In Plasma Next the locking consists of three interacting processes:
- KSLD in KSMServer
- kscreenlocker_greet (greeter)
- kcheckpass
While this might sound complex to have three processes it’s following the unix philosophy of one tool, one task. So let’s look at what the processes do.
KSLD
KSLD (for KScreenLocker Daemon) is a library used by KSMServer. KSMServer is our session server which gets started during session startup and keeps the session alive. If it crashes the session dies with it and you are returned to the login screen. KSLD is the main component of the screenlocker: it listens to the activation signal (e.g. global shortcut or logind), installs the X11 lock, blanks the screen and waits for the authorization to unlock the screen again.
At the moment KSLD has three authorization mechanisms:
- User configurable grace time: any user input during the grace time interval immediately unlocks the screen
- logind: listens to Unlock signal on the session’s object
- greeter process: exits with exit code 0
The most complex authorization mechanism is the greeter. For that the greeter process needs to be started and is monitored by KSLD. If the greeter process crashes the lock is kept and the greeter process is started again. The authorization to unlock is provided by the exit code of the process. If it exits with 0 the screen gets unlocked, with any other code the greeter gets started again.
Of course we need to show the greeter – so far the screen is blanked and no window is allowed to go above the blanked window. To achieve this the greeter can set a special window property on its windows and ksld will raise those above the locker and forward input events to this X client.
Security note: this cannot protect against malicious software already running on the user’s session. A malicious software could set the same property and thus read the input events. I intend to change this for a future release to have a socket communication between ksld and the greeter to pass window information and input events. Obviously it’s a good idea to use the Wayland protocol for this task – also on X11.
kscreenlocker_greet
The second process in our architecture is kscreenlocker_greet which got partially already explained in the previous section. In Plasma it’s responsible for rendering the unlock screen interface and the session switching interface. The user interface is implemented using QML allowing us to easily adopt to new use cases – e.g. the unlock screen in Plasma Active is just a different QML package.
For future releases we have some ideas to improve the experience by allowing to run our normal wallpaper plugins (bringing back animations) and allowing some selected plasmoids to go on the lock screen. Of course we need to white list the plasmoids which are allowed to go on the lock screen to not expose private information or even allow to start processes. It would be a bad idea to add a terminal emulator as a plasmoid.
kcheckpass
As mentioned our architecture is following the “do one thing, do it right” approach and the task of the greeter is only to provide the user interface. It does not perform any password verification. For that it uses kcheckpass, which is a small terminal application to verify a provided user password. If the user clicks the unlock in the greeter kcheckpass is invoked and the password is passed to kcheckpass through a binary socket protocol. Kcheckpass communicates with PAM to verify the password and can pass back an authentication success, authentication error or further information for PAM modules needing further interaction like a fingerprint reader. These messages and authentication failure are passed back to the greeter ui. If the authentication is successful the greeter exits with exit code 0.
This concludes the look on the various components. I would encourage all readers to try to break the architecture before we have a release. I’m quite confident that the architecture is secure and also more secure than what we had in 4.x.
XScreenSaver
Last but not least I want to share some thoughts on XScreenSaver. Whenever an issue arises like the ones in Unity we can hear people claiming one should use XScreenSaver because it’s way more secure. Now personally I don’t believe in silver bullets – especially not if it comes to security. In the beginning of this long blog post I stated two tasks a screenlocker needs to provide and XScreenSaver can fail with the second: the screen content can be exposed. Consider for example the linked screenshot. For a screen saver of the last millennium this was a suitable solution, but not for an implementation where we want to focus on security.
As we can read in the section On Toolkit Dialogs the security of XScreenSaver is based on the fact of not using a GUI toolkit. While the argumentation sounds good, it fails to see the need of today’s desktop environments. Providing an unlock dialog which can be styled with XLib might be a solution for the 90ies but not in a world where we want to provide an awesome user experience. Today users also expect the current time, battery state and many more information on the lock screen. We need to provide accessibility features which is not possible in XScreenSaver. We need to use proper idle mechanism shared with other applications. We need DBus integration, inhibition (XScreenSaver doesn’t support this!) and logind integration. Not using toolkits also means to have to fix bugs which the toolkit would solve for you, this is again increasing the risk of broken code and crashes in the daemon. Just consider this piece of code I found in XScreenSaver:
/* It turns out that if we do setlocale (LC_ALL, "") here, people running in Japanese locales get font craziness on the password dialog, presumably because it is displaying Japanese characters in a non-Japanese font. However, if we don't call setlocale() at all, then XLookupString() never returns multi-byte UTF-8 characters when people type non-Latin1 characters on the keyboard. The current theory (and at this point, I'm really guessing!) is that using LC_CTYPE instead of LC_ALL will make XLookupString() behave usefully, without having the side-effect of screwing up the fonts on the unlock dialog. See https://bugs.launchpad.net/ubuntu/+source/xscreensaver/+bug/671923 from comment #20 onward. -- jwz, 24-Sep-2011 */
Now if you consider the architecture I explained the “problem” of the toolkit doesn’t matter at all. We are running an interpreted (QML) language which heavily uses OpenGL without introducing any security risks by using separate processes. If the application which holds the lock (and also heavily uses Qt) crashes the complete session goes down. In turn I think that the argumentation provided by the XScreenSaver maintainer doesn’t hold. Even more I haven’t seen anything about crash resistance like we have in Plasma to have the session getting killed if the lock process crashes. I’m not saying that this doesn’t exist (the code base is very large and I haven’t done a full audit) but I haven’t seen anything in the very prominent documentation about why it’s better.
Of course one could ask why we don’t work on XScreenSaver to improve it and make it work for our use cases. I don’t think that this is possible and at least I would not even try to. It’s quite clear that code using toolkits is not wanted. I also doubt that the needs of desktop environments like Plasma, GNOME Shell or Unity are understood at all. Let me quote the FAQ:
KDE suffers from the same brain damage as GNOME, above.
The only sensible (and secure) way to use a screen saver under KDE is to turn off KDE’s built-in screen saver, and use xscreensaver instead.
With that attitude I think it’s quite obvious why at least I see zero chances to use XScreenSaver in any desktop environment.
Thank you! Always enjoy reading your articles.
This is great. The design is sound and if I understood everything correctly, you could use the Wayland subsurface feature to avoid the “window on top” hack for the greeter (with Wayland of course). I’m looking forward to the first Plasma Next release to try this out.
Great article, thank you very much!
Something I’m missing from lock screens is ability to (optionally) control music player running in background and tune audio volume using multimedia keys on keyboard without the need to unlock the screen. Is that possible with new “kscreenlocker_greet” ?
IIRC it’s not possible on X11, but is on Wayland.
That’s out of scope for the screenlocker. In fact it would be wrong as the task of the lock screen is to grab all input.
It looks like there’s a potential conflicting requirements here. On the one hand nobody should be able to alter session state until after they have been authenticated, so things like play/pause/stop controls might have to be disallowed by definition.
On the other hand some basic control over hardware things like screen brightness and muting/unmuting sound might be rather desirable. In the case of volume perhaps the ‘best’ thing could be to stop all playback automatically and resume it once the user logs back in?
that’s something the video players could do. E.g. listen to the dbus signal that the screen gets locked.
Well, indeed, but also it might allow to some “whitelisted” clients to receive “some” events… In this way you can allow a whitelisted client A to register to receive the VolumeUp key event for example. This is still safe.
Some Android lock screen allow people to change songs, go in silent mode etc. I don’t kinda like the idea of the screenlock to be “on top”.
Ubuntu’s unity provides some sort of seamless lock screen which is much more aesthetically pleasing. The screenlocker is here to serve us. Not the opposite.
well it’s not a phone.
This is something we support in the new Unity lockscreen, and that’s one of the reasons why we did it.
Although, we had to “reinvent the wheel” a little, here… Because – as said – the lockscreen gets all the input, then we basically had – at lockscreen level – to filter the keyboard events, check if they match any of the user-configured “global key”, and finally call via-dbus the relvant service for performing the relative action…
Thanks to the Indicators and Gtk actions being pretty generic, we have been able to do this without introducing much “custom code”, but still this is some kind of duplication. :/
IMHO KDE 4.X’s Screen Locker is pretty poor. On my system, screen goes off at 10 minutes when connected to AC power, 5 minutes on battery and 2 minutes when in low battery. I would like screen locker to lock system as soon as screen goes off but screen locker has two archaic settings. System locker can only be activated in increments of a minutes and password lock can be triggered with other timer that goes from 1 second to 100 seconds.
Am I right in thinking that the Screenlocker kicks in after resume, instead of before suspend? I’m pretty sure this exposes my entire screen under some resumes (There is some sort of race condition so this isn’t every resume), alternatively is this Kubuntu’s ‘fault’ rather than KDE’s and the suspend and resume scripts need improving?
Additionally would it be possible (and a good idea?) to wipe 1/2 entered passwords on suspend as on a couple of occasions (e.g low battery and jumping over cables to plug myself back in), I’ve entered my full password and then on resume this was not wiped so anybody would have been able to login.
The screen should be locked before suspend. I plan to make this better by making more proper use of Logind, but overall it should work.
Very nice article as usual !
I wonder, doesn’t it make more sense to have kdm (or its potential successor) handle screen locking ? So user-switching can be done seamlessly from locked sessions and it would look consistent with the login screen UI.
If I’m not mistaken that’s how it’s done in GNOME.
“I wonder, doesn’t it make more sense to have kdm (or its potential successor) handle screen locking ?”
I am likely in a minority, but I don’t even have KDM installed, nor any other graphical login manager. I am specifically opting to login at the command line and then run startx ~if~ I want to at that time. I hope I still have this CLI option with Wayland as well (e.g., startw?).
A graphical login manager locked me out once after a system upgrade and went into an infinite loop thereafter on reboots (it was in fact KDM). Thus I’d rather deal with something seemingly simpler and perhaps more fault-tolerant(?) like a command line login interface, with the ~option~ to start a graphical environment thereafter. Maybe if I had understood all the factors better at the time I would’ve been able to troubleshoot KDM, but my solution has worked for me ever since. My desire for a CLI entry point, and running a graphical login manager, to me seem like mutually exclusive goals.
I really hope kde won’t go the way of the dodo and make the locker part of kdm. Because that means you will only be able to lock your plasma desktop if you use kdm. It hurts if I have to switch login manager in order to test a different DE. If the user has no admin rights (or the password/sudoers entry) he will be lost.
Furthermore some users have problems with certain login managers. For me gdm takes ~25 seconds to startup (kdm: ~3 seonds), which makes complete startup take ~1 minute (including BIOS startup). I read in the german Gentoo-forums about people having issues with KDM messing up network services, lightDM/GDM/sddm work fine for them.
Having the choice is important. If you depend hard on a certain infrastructure you will quite likely loose users. Don’t kow if this is worth the gained eye candy.
KDM is dead, it’s not a part of Plasma 2. People will have a choice between LightDM and SDDM. This locker makes use of Plasma 2 and KWin 5.
Hi Martin,
About the greeter, it is meant to exit (0) only when kcheckpass tells it to, isn’t it? Logind unlock signals and the grace time input would be processed directly by KSLD?
If so, then what about getting kcheckpass to tell KSLD to unlock rather than relying on the greeter exiting gracefully? If I found a buffer overflow, string format vuln, etc. in the greeter (for any reason including a bug introduced later in the toolkit) then my strategy would consist of calling exit (0) directly. With your current architecture, that would suffice to unlock, wouldn’t it? Whilst if kcheckpass tells KSLD to unlock then I would have to break the greeter (in a way that allows more than mov 1 eax; mov 0 ebx; int 0x80) AND kcheckpass. This should make attacks harder.
It’d of course be very very hard to find an exploit that can be written in a toolkit’s input field and transform itself into bytecode but it’d allegedly be harder to find that AND another exploit on kcheckpass.
Yeah could make sense. Though I don’t think there is lots of chance to get there for an attack. The UI is in QML, so already in a sandbox. It would need to get from the QML to the C++ part to make that possible.
As mentioned in the blog post I prefer moving from the exit code to a socket based communication.
Well I don’t know QML the least so I’ll take your word! In any case I think it’s better for kcheckpass to return the final decision since it’s the component that decides whether authentication failed or not and since it’s buried deeper away from the attacker than the greeter.
In other words I think greeter->kcheckpass->ksld is nicer than greeter->kcheckpass->greeter->ksld (the greeter being the weakest link, and if compromised then being able to unlock directly without talking to kcheckpass). However I might be missing some aspects that make you prefer your architecture. If so I’m keen to learn 🙂
More Pictures Please, Keep up the Good Work 🙂
Thanks for the nice article, explaing things more deeply…
As said, in unity we were initially using the “2-processes” method, using gnome-screensvaer as fallback option, to keep things safe in case of crashes, but this was actually complicating things and introducing more bugs… Thus we moved to keep everything inside unity.
The idea here is that if unity (compiz actually) crashes, then we reload it immediately locking the screen since its first initialization… And, because when compiz crashes and reloads it’s not possible to interact with any app, there’s no risk of an attacker interaction. There might be a slight risk of presenting to the person watching the screen the user content, but that would last few ms, and thus we accepted it for now (but yes, having another process here would help; but it’s not the only solution).
Anyway, this whole infrastructure looks nice to me, having this in unity would have required a lot more efforts than we had the ability to put during the 14.04 timeframe, but I think we’re still far more safer than we used to be in the past, falling back to gnome-screensaver.
About the fact of making sure that the locking window will be and stay on top, a part from using the X capabilities, in Unity we use the compiz + nux power to make sure that nothing, but the lockscreen window itself, is drawn when unity is locked.
In this way there’s no possibility that another window (such as some strange popup or the old chromium notifications) might be drawn over it.
That’s not the case. We also planed to move the screenlocker into KWin and moved away from it as there still is a risk. A right click at the right place and the screen is unlocked when the window manager crashes.
Good article.
Will there be an ability to attach a non-gui process to the screen locker e.g. akonadi, to run in the background when the screen lock is active?
any process can listen to the dbus signals