Skip to content

General information

Szybet edited this page Jan 28, 2024 · 1 revision

InkBox OS has a very strict security policy which ensures software integrity any time the device boots. The OS is developed in such a way that if the device is not 'rooted', it is completely locked down and can't be accessed from the outside.

Boot

U-Boot

When InkBox OS boots, the device is first handed in to the bootloader, which sets up the hardware (CPU, RAM, EPDC, etc.) to be ready for userspace. The first 20 megabytes of the (e)MMC consist of unpartitioned space in which lives U-Boot and various components required for device startup. In newer devices, U-Boot then loads a Device Tree and then a zImage to boot the Linux kernel. On older devices (e.g. Mini, Touch, Glo), a legacy uImage is used instead, without a Device Tree.

Linux kernel

Once the kernel image has been loaded, it is then started by U-Boot. Usually, it is loaded at memory address 0x80800000. A typical InkBox OS kernel is about 7 MB in size, depending on the device type. It contains the core components needed for it to boot, as well as the kernel modules that pair with that specific version of it. Those can provide services for Wi-Fi, USB mass storage or USB networking. Those modules are located in a SquashFS archive inside the initrd that gets mounted on the main root filesystem (rootfs) during the startup process.

Init ramdisk (initrd)

The initial ramdisk, often called initrd, is the first thing that the kernel sets up after initializing itself. It can be stored in a separate file, usually a (compressed) cpio archive that the kernel loads in RAM at run-time, or it can as well be 'embedded' in it, that is, being completely independent of any external filesystem resource. This is what InkBox uses.

In InkBox OS, the purpose of the initrd is to ensure the system is securely and sanely brought to a functional state by mounting partitions, disk images and SquashFS archives to get the main framework up and running. Boot flags can also offer some control on baked-in features, such as debugging the init ramdisk via telnet if needed.

Standard and Rooted

In InkBox, the two main kernel/initrd combinations are the following:

  • Standard
  • Rooted

Those have huge differences between each other, and it is important to understand them before trying to apply any modification to the current running system. They are described below.

  • A Standard kernel is what all so-called 'factory' InkBox images ship with. The userspace is completely isolated (or as much as possible) from external environment and things such as USB Networking, arbitrary code execution is impossible, if not very difficult. The boot process is heavily secured by digital signature verification for the root filesystem's SquashFS archive, X11/KoBox extensions and additional packages. Even if you succeed in connecting to the device and try to get a shell, the default passwd file will prevent you from doing that since the default login redirects to /sbin/nologin. As such, user access to the framework is very restricted and limits itself to what the default Qt5 and KoBox/X11 (without KTerm) GUI interfaces offer.
  • A rooted kernel, on the other hand, offers a wide range of permissive features for the advanced user. It allows, among other things, USB Networking activation at boot-time, root shell/console (via SSH, telnet or serial port), full system access. However, some restrictions are still there: for example, all the package's digital signatures are still being verified by OpenSSL at boot. The only way to avoid this is then to either recompile the kernel with your own public key embedded in the initrd, or request a developer key from me at kobox.alpine@gmail.com . This will disable (almost) all packages verification at boot and will allow you, for example, to roll your own KoBox/X11 extensions, without you needing to sign them.

Initialization process

InkBox OS is probably not like your standard Linux distribution you have installed on your PC or at work. Instead of using a standard root filesystem stored as a whole in a partition, that part of the framework is in fact a SquashFS file. At boot, it gets mounted by the initrd with the script [initrd-root]/etc/init.d/overlay-mount. A special FUSE-based filesystem layer, overlayfs-fuse, permits a read-write root filesystem with the command ifsctl mnt rootfs rw. Otherwise, it is always read-only to minimize flash storage writes and extend the MMC's lifespan as much as possible. When all the initial mount process is completed, the rootfs can be chroot'ed into to run the main framework. The main partition layout looks like this:

PART. NUMBER    LABEL       DESCRIPTION
1       boot        Contains boot flags
2       recoveryfs  Recovery partition used to restore InkBox OS
3       rootfs      Contains the rootfs SquashFS archive + OpenSSL digest
4       user        All user data, such as config options, books, InkBox Software Archives (*.isa)
KoBox/X11

When the root filesystem has finished mounting, if the user has enabled X11 (see the X11_START, the KoBox subsystem is started up. The initrd proceeds on the steps below, ran from [initrd-root]/etc/init.d/startx:

  1. First, the [initrd-root]/etc/init.d/developer-key script is executed by the main rcS. If a developer key is found and is valid, then signature verification is disabled.
  2. The base system is mounted from a disk image living at [sd-p4]/X11/base.img. This contains another disk image as well as the OpenSSL digest file used for verification against the initrd's public key. It is initially mounted at /opt/X11/base/rootfs.
  3. A VNC client root filesystem is set up at /opt/X11/vnc-touch to handle X11 touch input. Since Qt5 apps work very well on Kobos, especially with touch input, when an X11 app is started, an x11vnc server is launched on the X11 chroot (with the -localhost) and it then interacts with a Qt/LibVNCServer-based VNC viewer which doesn't print anything on the screen actually, but handles touch input only. Graphics work is leveraged by fbink-xdamage. This method of dealing with touch input has its downsides, but scrolling is supported.
  4. Extensions, whether part of the "base" subset or the "user" one, are set up in separate mountpoints. Extensions are in fact other SquashFS archives that contain a small part of a root filesystem. For example, the 'ssh' extension, which is part of the base subset, contains some binaries (ssh, scp) and libraries to get them to work, and really nothing else. The script first starts by mounting (as well as verifying) them in separate folders. Then, same thing is done for the user subset, which contains the extensions the user can add/remove via USB mass storage mode (USBMS), for example the 'C64-Emulator' one.
  5. When all extensions have been mounted and ready, the whole KoBox/X11 is mounted read-write at /xorg by fuse-overlayfs and unionfs-fuse, which handle merging them altogether. For what it's worth, when an user clicks on "Reset KoBox userdata", only a simple rm -rf /opt/X11/rootfs/write + reboot is done.
  6. On InkBox OS, a (yet) unsolvable issue makes X impossible to start after udev initialization. The process is 'frozen' and stopping it is only possible with SIGKILL (9). Therefore, the script starts it when no services (or very few) are running. Interestingly enough, restarting it afterwards works.
Entering the chroot

Once all necessary services have been loaded, the initrd issues three chroot commands on the openrc binary in the chroot:

busybox chroot /mnt openrc sysinit
busybox chroot /mnt openrc boot
busybox chroot /mnt openrc default

Which starts the necessary services and helpers for the main Qt GUI interface.

Run-time services and GUI

InkBox GUI

InkBox's main graphical user interface runs in a chroot too, inside the main rootfs chroot. It uses Qt 5.15.2 and prints directly on the framebuffer, without any X11 server between the screen and it. To communicate with external chroots (such as the root filesystem), it makes use of a FIFO (First-In, First-Out) interface on a named pipe located at /opt/ibxd. A listener runs on the main rootfs and if a line sent is recognized, the corresponding action/command is executed. InkBox GUI is a system service and you can start/stop/restart it by issuing the following command:

rc-service inkbox_gui <start|stop|restart>

or

start inkbox_gui
stop inkbox_gui
restart inkbox_gui

Update packages

InkBox's main Qt 5 GUI comes in a *.isa file, which contains the necessary libraries and binaries needed for it to run in multiple SquashFS archives. This permits a lightweight, portable package that can be upgraded every release seamlessly by the update script.