Simple App: a Linux toy application for user and kernel space

Figure 1 – Simple App architecture

In the context of the Open Source Study Group, we decided to explore some Linux kernel APIs related to IPC and namespaces. An effective approach to this is exercising APIs from a crafted user-space application, while debugging at the kernel level. After some progress and setting breakpoints here and there, a challenge became evident: breakpoints in common functions are hit all the time from different processes. We need to filter out non-relevant hits, while staying focused on our application. This can be done, perhaps, by means of a conditional breakpoint in the debugger. Checking the binary image associated to the current task (looking into the mm_struct) should make it, but debugging complexity starts growing rapidly.

To tackle the aforementioned problem, and extending the concept further, I developed Simple App. It’s a toy application that serves as a playground to test user and kernel space Linux APIs, as well as privileged and unprivileged x86-64 assembly instructions. It does nothing by itself: think of it as a template to start poking around. Note that this is intended for educational purposes only; it was not designed for security or performance and, thus, none of its code or patterns should be taken into production environments.

As shown in Fig. 1, the architecture is fairly simple:

  • a user-space application (simpleapp),
  • a user-space shared library (libsimplelib.so), and
  • a kernel-module (simplemodule.ko).
Figure 2 – Command line interface Simple App output

Once launched, simpleapp dynamically loads the simplemodule kernel-module using one of the simplelib services. The kernel-module creates a character device on-the-fly (/dev/simplemodule_dev) and communication with the user-space application happens through IOCTLs. Once done, the kernel-module is unloaded and all the resources freed for the next execution. Even though it’s possible to execute in a local environment (instead of deploying to a testing virtual machine), this is not recommended as may affect the system’s integrity -and, of course, a Kernel debugger cannot be attached-.

Here there is a list of features currently implemented:

  • direct system calls (from simpleapp to the kernel);
  • proxied system calls (from simpleapp to the kernel passing through the kernel-module);
  • kernel-module output (debug prints) retrieval, for displaying in user-space;
  • multi-process support in the kernel-module (per-process output);
  • user and kernel space x86-64 assembly example;
  • an extensible platform to execute chosen tests in the kernel-module, sending and receiving data buffers of arbitrary length; and,
  • user and kernel space debugging capabilities -automation from the GDB side required to take full advantage-.

More details about the application in the README file.

Code is under a GPLv3 license.

Leave a Reply

Your email address will not be published.