Librem 5 kernel hacking

I would like to learn how things work regarding the Linux kernel on the Librem 5, how to modify and rebuild the kernel, how to install a modified version and how to choose which kernel gets used in case several versions are installed. Things like that.

Here is what I figured out so far.

We can get the kernel source code from the git repo at https://source.puri.sm/Librem5/linux-next like this:

sudo apt install git
git clone https://source.puri.sm/Librem5/linux-next.git

That takes a while, it’s a big repo.

Then enter the source directory and install dependencies:

cd linux-next/
sudo apt-get build-dep .

Before building, I made a little change to help convince myself that the modified kernel is really used, to recognize “my own” kernel version. When booting there is a log message like this:

sudo journalctl -b | grep Booting
Feb 25 19:45:35 pureos kernel: Booting Linux on physical CPU 0x0000000000 [0x410fd034]

that comes from this line in the source code, in arch/arm64/kernel/setup.c:

pr_info("Booting Linux on physical CPU 0x%010lx [0x%08x]\n",

which I changed like this:

pr_info("Booting Linux -- modified by Skalman :-) -- on physical CPU 0x%010lx [0x%08x]\n",

So then when the new kernel is running, that log message should look different.

Now build the kernel:

dpkg-buildpackage -us -uc -b

That took 130 minutes, resulted in 4 different deb files:

cd ..
ls -l *.deb
-rw-r--r-- 1 root root  7352076 Feb 25 23:44 linux-headers-5.9.0-1-librem5_5.9.16pureos0~amber0_arm64.deb
-rw-r--r-- 1 root root 15868196 Feb 25 23:46 linux-image-5.9.0-1-librem5_5.9.16pureos0~amber0_arm64.deb
-rw-r--r-- 1 root root    15676 Feb 25 23:46 linux-image-librem5_5.9.16pureos0~amber0_arm64.deb
-rw-r--r-- 1 root root  1113868 Feb 25 23:44 linux-libc-dev_5.9.16pureos0~amber0_arm64.deb

The largest one seems to be the kernel itself, so install that:

sudo dpkg --install linux-image-5.9.0-1-librem5_5.9.16pureos0~amber0_arm64.deb

and then reboot.

Now, after rebooting, check that log message to see if the new kernel is used:

sudo journalctl -b | grep Booting
Feb 25 23:57:06 pureos kernel: Booting Linux -- modified by Skalman :-) -- on physical CPU 0x0000000000 [0x410fd034]

So it worked, I am now a kernel developer! :sunglasses:

Some questions about this:

  • It took quite a long time, more than two hours to build, and if using this procedure the whole build will be repeated and it will take two hours again if a small change is made. That will slow down the trial-and-error procedure when debugging or testing something. How to make it faster? If we skip the debian packaging stuff then I think we can just do “make” and that can be quick it there was only a small change, but then both configuration and installation needs to be done differently, when the debian packaging is no longer used for that. What is the best way, to allow testing kernel code changes more quickly?
  • Things are installed in the /boot/ directory, notably vmlinuz and initrd.img files, and it seems like several of those for different kernel versions can be installed in /boot/ and at boot time one of them is picked somehow. How does that work, how can we choose which kernel is used in case several kernel versions are installed? I have seen that grub can be used for this, but on the Librem 5 it seems grub is not used, something else is going on.
  • I think the main reason that the source code package is so large and takes such a long time to build is that it contains drivers for lots and lots of hardware, most of which does not exist on the Librem 5 so that code is built but is not really going to be used, is that right? If so, could we simplify things and get a smaller kernel that is quicker to build by simply removing unused parts?
  • Any other useful tips and tricks regarding kernel building and installing and so on?
8 Likes

Awesome job! :slight_smile:

Are you building on the Librem 5 itself?

1 Like

Yes, that’s the only way I know how to do it so far. I don’t have any other arm64 machine, if I did then I think it should work to build on the other machine and just copy the deb file over. Building a kernel on my laptop is much faster, only takes 30 minutes or so I think, but then that’s x86_64 architecture so it is not going to work on the L5. I’m sure it’s possible to cross-compile and that may be one way to build it faster, I’d like to learn how to do that.

Anyway, it kind of feels good to build things on the device itself, even if it is slow. :slight_smile:

3 Likes

That’s what I was thinking.

I think the goodness will wear off quickly after the third small-fix+build+install+test two hour cycle. :wink:

1 Like

It’s pretty damn cool to me that you own a phone that can build its own kernel.

7 Likes

I don’t think rebuilds will take so long time. Could you change the print again and rebuild? It should be a lot faster!

1 Like

Hmm, the recipe for cross-building the package is not much different. If you have a Debian on your machine:

  1. Install the toolchain. I.e. just run the first apt-get install.
  2. run dpkg-buildpackage -us -uc -b --host-arch=arm64

Find this also in the kernel’s README.source.

Took real 8m35.383s here on a modest pc.

Normally, i would not compile a kernel this way, this procedure is more for packing things up for debian. The above link briefly mentions the regular procedure. Though to compile the kernel on the phone itself is not the usual way, it demonstrates, that the system is properly self-hoisting.

Another important step is to actually flash and recover the system. One better tries this first before making any modifications that could break the preinstalled software. Unfortunately, the documentation might be somewhat outdated in this respect as it focuses more on the devkit but on the phone.

The most central trick is how to get into u-boot. Perhaps a combination of

might do it … at least the serial download mode makes a device available for uuu:

$ uuu -lsusb
uuu (Universal Update Utility) for nxp imx chips -- lib1.4.77

Connected Known USB Devices
    Path     Chip    Pro     Vid     Pid     BcdVersion
    ==================================================
    1:913    MX8MQ   SDP:    0x1FC9 0x012B   0x0001

An uuu package is regularly available for debian.

Next, librem5-devkit-tools appear to be needed:

$ git clone https://source.puri.sm/Librem5/librem5-devkit-tools.git

Therein, boot_librem5.lst looks promissing … but misses all of .../files

$ scripts/fetch_latest.sh -T current

gets some …

4 Likes

Great, then that’s easier than I thought, I will try that.

Yes of course, see here:

Reflashing as described there works fine, I have done it several times already.

Its encouraging to read that you’ve already tried it.

I’m using uuu the very first time and its documentation is brief at best. Normally, one would start u-boot with it and from there run the linux kernel. So far, i’ve tried:

  • uuu files/u-boot-librem5.imx
  • uuu uuu_scripts/boot_librem5.lst

but did not get any u-boot dialog nor kernel output.

To clarify, what I have done to reflash, and found to work well, is to run the ./scripts/librem5-flash-image script. I think that script is using uuu internally but I have not used uuu directly myself, I just let that script do it for me.

Here’s the script I use to build the kernel. It’s somewhat complicated because it ssh’s to my build host and builds there, and then starts the phone with the new kernel.

The build computer needs to have the git repo initialiized.

#!/bin/sh
set -e

VERSION=`git show --pretty=format:"%h" --no-patch`
REMOTE=worker@192.168.5.232
PHONE=purism@10.42.0.69

ssh $REMOTE 'git -C /home/worker/purism/cameras/linux-next/ checkout -f cb1'
git push worker -f HEAD:cb0
ssh $REMOTE 'git -C /home/worker/purism/cameras/linux-next/ checkout cb0'
git push worker -f HEAD:cb1

# CAUTION: make should start in the directory /home/worker/purism/cameras/linux-next/
ssh $REMOTE 'make -j8 ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- librem5_defconfig'
ssh $REMOTE 'make -j8 ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- bindeb-pkg'
# CAUTION: here ~/mnt/worker is a sshfs mount to the worker host. I'm sure you can figure out how to adjust this line.
RELEASE=`ls ~/mnt/worker/purism/cameras/linux-image-*g$VERSION-*_arm64.deb | head -n 1 | sed -nr 's/.*linux-image-(.+-g.*)_.*-g.*/\1/p'`
scp ~/mnt/worker/purism/cameras/linux-image-*g$VERSION-*_arm64.deb $PHONE:.

ssh $PHONE "sudo apt-get remove -y 'linux-image-5.*.0-librem5-g*'"
ssh $PHONE "sudo sh -c 'rm "/boot/*.bak" "/boot/*.tmp" || true'"
ssh $PHONE 'sudo apt-get install -y ./linux-image-*g'"$VERSION"'-*_arm64.deb'
#ssh $PHONE "sudo flash-kernel --force 5.11.0-rc5-librem5-g$VERSION"
ssh $PHONE "sudo flash-kernel --force $RELEASE"
ssh $PHONE "sudo reboot"

It’s more complicated than you’re going to need it (I removed podman integration), but should at least answer your questions about building. It also takes 2-15 min to build, depending on how much changed between changes.

4 Likes

Great, thank you very much!

Sounds very good, then it will be much smoother to try different things. :slight_smile:

1 Like

so ? judging from that internal PHONE IP do you have 69 devices on your network ? :stuck_out_tongue:

The following seems to work well (using some parts of the script from @dcz above) to cross-compile. Do the following on the build computer, in my case an x86 laptop:

First get the kernel source code:

git clone https://source.puri.sm/Librem5/linux-next.git

Then checkout the branch you want and/or make your own changes.

Install build dependencies by running this command inside the linux-next directory:

sudo apt-get build-dep .

Configure and build like this:

make -j8 ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- librem5_defconfig
make -j8 ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- bindeb-pkg

That should result in a .deb file created in the parent directory, one step outside the linux-next directory, the deb file is called something like linux-image-5.9.16-librem5-00002-gefe0e25dccf0_5.9.16-librem5-00002-gefe0e25dccf0-1_arm64.deb. Copy that .deb file to the Librem 5 using scp.

On the Librem 5, install it like this:

sudo apt-get reinstall -y --allow-downgrades ./linux-image-something.deb

where linux-image-something.deb is the deb file that was just copied over.

Then reboot the Librem 5 and it should be running your newly built kernel.

This procedure is much faster than running dpkg-buildpackage on the Librem 5 itself, both because the x86 laptop does the job faster and because doing make like this means that it only rebuilds the parts needed so after small changes building again it is very quick, in contrast to the dpkg-buildpackage approach which seems to always rebuild everything from scratch.

So I’m happy with this, now it just remains to learn more about how the kernel actually works. :slight_smile:

4 Likes

One use for this ability to compile your own kernel could be to cause the OS to do things that are unique to only your own phone. For example, some odd combination of keyboard strokes or a command line call could cause the phone to hide your persona and switch to a different persona. Maybe the old persona could be stored in encrypted binary format somewhere in a dedicated area of memory that is typically used only by the kernel itself.

So it would take only a few seconds on the way to the airport to hide your real identity and present a different one. Unless the people at the airport want to reverse-engineer the kernel of the OS on your phone, the only evidence about this feature would exist exclusively in your own mind. Just don’t alter the build number information. As far as anyone else is concerned, the phone has the same OS it was shipped to you with. The experts would be looking at the data in the file system and not at the OS itself.

1 Like

Just be careful to fake the hash of your kernel to match the original one :3

1 Like

Otherwise you may be in real trouble: https://www.eff.org/document/eff-border-search-pocket-guide

The most common use of the kernel is just maintainability, i.e. one will be able to upgrade it. Because virtual every other phone vendor pretty quickly abnegates that they ever produced the phone you just bought from them, this is in fact a very unique property. But a phone can be maintained a least for a much longer period if it is properly open sourced.

The Nicole Faerber explains in her article how difficult this is to achieve in the current state of the industry.

1 Like

Yes and no.

On the one hand: cute, and best of luck with that.

Don’t let me discourage anyone’s creativity.

On the other hand: You will perpetually be having to reapply your changes and that could result in an overall decrease in security if you hold off applying critical security updates to the underlying kernel because you “don’t have time right now” to download the updated kernel sources, apply your changes, recompile and reinstall.

There is obscurity benefit in not upstreaming your changes but maybe someone else could benefit from the same change.

The “recommended” way of dealing with “persona” is to be organised and plan in advance - rather than be scrambling around on the way to the airport.

It all depends on the level of interest that they are showing in you. If you are a Chinese agent attempting to enter the US then the US authorities could and should go to those lengths (and you can forget about accessing your phone anytime in the next few months, if ever). If you are a random with a bit of attitude then not very likely that they would go to those lengths (they will just delay you for an extra hour because you pissed them off).

Any hash worth its salt can’t be faked.

I’m pretty sure that law enforcement (maybe not so much at the border, but let’s say that they have raided your house and taken away your computers) will already run through the entire file system looking for files that don’t match a standard offline hash i.e. anything that you have added or changed.

You would need to go deep in order to fake the contents of the file so that the hash comes out right but only faking the contents of the file under the circumstances that someone else is using your computer.

If faking things then the build date may need to be faked too but that at least is easy.