Hi,
a my Project Owncloud on a Raspberry Pi I want to use AppArmor to protect the lighttpd webserver. Unfortunately the default kernel is complied without apparmor support.
So I decided to build my own kernel:-)
Here are the steps to (cross) compile the new kernel on a x64 Intel based computer.
First of all update the Rasperries Firmware and therefore the kernel to the latest revision.
1 2 | pi@raspi ~$ sudo rpi-updatepi@raspi ~$ sudo reboot |
Check Version
1 2 | pi@raspi ~$ uname -aLinux raspi.yourdomain 4.1.13+ #1 PREEMPT Tue Oct 24 13:10:50 CET 2015 armv6l GNU/Linux |
Get the kernel config file (.config). The kernel provides this in /proc/config.gz. The raspbian kernel does provide it by default. You must load the configs.ko kernel module
1 2 | pi@raspi ~$ sudo modprobe configspi@raspi ~$ zcat /proc/config.gz > ~/.config |
Or after installing kernel sources you can also use the script “extract-ikconfig” in the scripts folder to extract the config from the kernel image file.
Go to the x86 PC. Make sure you have free at least 5GB of disk space. Define the build directory
1 2 | michael@devdeb ~ $ mkdir $HOME/raspbian-kernelmichael@devdeb ~ $ cd $HOME/raspbian-kernel |
Get the kernel config file from Raspberry to your home
1 | michael@devdeb ~ $ scp pi@IPAddressRaspPI:/home/pi/.config ~/.config.raspberry |
Get ARM Compiler
1 | michael@devdeb:/home/michael/raspbian-kernel $ git clone https://github.com/raspberrypi/tools |
The next step is to determine the git path of the current kernel. These steps are not necessary if you want to compile a version 4.1.x
1 2 3 4 5 6 7 | # Determine git pathof current Kernel. Not necessary if you know it, in this example 4.1.x# git clone --depth 1 https://github.com/raspberrypi/linux.git# cd linux# git show-ref# 06d4ed20f68e37bc556062990aa41a8fc11438d1 refs/heads/rpi-4.1.y# 06d4ed20f68e37bc556062990aa41a8fc11438d1 refs/remotes/origin/HEAD# 06d4ed20f68e37bc556062990aa41a8fc11438d1 refs/remotes/origin/rpi-4.1.y |
Some Environmentvariables with a decision first for which Raspberry you want to compile the kernel
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # New Kernelfilenameexport KERNEL=kernel-custom# Kernel sources directorymichael@devdeb ~ $ export KERNEL_SRC=$HOME/raspbian-kernel/rpi-4.1.y# gcc Compiler Prefix# michael@devdeb ~ $ export CCPREFIX=$HOME/raspbian-kernel/tools/arm-bcm2708/arm-bcm2708-linux-gnueabi/bin/arm-bcm2708-linux-gnueabi-michael@devdeb ~ $ export CCPREFIX=$HOME/raspbian-kernel/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/arm-linux-gnueabihf-# Root for tar Archive for the transfer to Pimichael@devdeb ~ $ export RASP_FILE_ROOT=$HOME/raspbian-kernel/root# Folder latest firmwaremichael@devdeb ~ $ export FIRMWARE=$HOME/raspbian-kernel/firmware# Target directory for the new kernel modulesmichael@devdeb ~ $ export MODULES_TEMP=$HOME/raspbian-kernel/lib/modules# Create foldersmichael@devdeb ~ $ mkdir -p $KERNEL_SRCmichael@devdeb ~ $ mkdir -p $MODULES_TEMPmichael@devdeb ~ $ mkdir -p $RASP_FILE_ROOT |
While it is important in which directory a command is executed and the command lines and prompt are partitialy rather long and therefore uses a lot of space. I insert before each command block a pwd to show the working directory and “hide” the prompt in front of the commands.
Get the latest sources
1 2 3 4 5 6 | michael@devdeb ~ $ cd $KERNEL_SRCpwd# /home/michael/raspbian-kernel/rpi-4.1.ygit initgit fetch https://github.com/raspberrypi/linux.git rpi-4.1.y:refs/remotes/origin/rpi-4.1.ygit checkout refs/remotes/origin/rpi-4.1.y |
Clean up
1 2 3 | pwd# /home/michael/raspbian-kernel/rpi-4.1.ymake mrproper |
Copy the .config file to the kernel build folder
1 2 3 | pwd# /home/michael/raspbian-kernel/rpi-4.1.ycp ~/.config.raspberry .config |
It’s time to customize the kernel. I want to enable apparmor. CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1 enables AppArmor by default.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | pwd# /home/michael/raspbian-kernel/rpi-4.1.y# CONFIG_AUDIT=ysed -r 's/^((CONFIG\_AUDIT=.*$)|(^# CONFIG\_AUDIT\s.*$))/CONFIG\_AUDIT=y/m' .config -i # CONFIG_CRYPTO_SHA1=ysed -r 's/^((CONFIG\_CRYPTO\_SHA1=.*$)|(^# CONFIG\_CRYPTO\_SHA1\s.*$))/CONFIG\_CRYPTO\_SHA1=y/m' .config -i# CONFIG_SECURITY=ysed -r 's/^((CONFIG\_SECURITY=.*$)|(^# CONFIG\_SECURITY\s.*$))/CONFIG\_SECURITY=y/m' .config -i # CONFIG_SECURITYFS=Ysed -r 's/^((CONFIG\_SECURITYFS=.*$)|(^# CONFIG\_SECURITYFS\s.*$))/CONFIG\_SECURITYFS=y/m' .config -i# CONFIG_SECURITY_NETWORK=y# CONFIG_SECURITY_PATH=y# CONFIG_SECURITY_APPARMOR=y# CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1# CONFIG_SECURITY_APPARMOR_HASH=y# CONFIG_INTEGRITY=y# CONFIG_INTEGRITY_AUDIT=ysed '/CONFIG_SECURITYFS=y/a CONFIG_SECURITY_NETWORK=y\nCONFIG_SECURITY_PATH=y\nCONFIG_SECURITY_APPARMOR=y\nCONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1\nCONFIG_SECURITY_APPARMOR_HASH=y\nCONFIG_INTEGRITY=y\nCONFIG_INTEGRITY_AUDIT=y' .config -i# Version -apparmorsed -r 's/^CONFIG_LOCALVERSION=.*$/CONFIG_LOCALVERSION="-apparmor"/m' .config -i |
You can make your own changes by opening the kernels config menu. Prior to this you have to install the ncurses-dev paket.
1 2 3 4 | pwd# /home/michael/raspbian-kernel/rpi-4.1.yapt-get install libncurses5-devARCH=arm CROSS_COMPILE=${CCPREFIX} make menuconfig |
Start compiling and get a coup of coffee or two. This takes a while.
1 2 3 4 5 | pwd# /home/michael/raspbian-kernel/rpi-4.1.yARCH=arm CROSS_COMPILE=${CCPREFIX} make olddefconfigARCH=arm CROSS_COMPILE=${CCPREFIX} make zImage modules dtbsARCH=arm CROSS_COMPILE=${CCPREFIX} INSTALL_MOD_PATH=${MODULES_TEMP} make modules_install |
Move the lib folder which contains the new kernel modules to the root of the to created tar archive
1 2 3 4 | cd ${MODULES_TEMP} pwd# /home/michael/raspbian-kernel/lib/modulesmv lib $RASP_FILE_ROOT |
Copy the new kernel, the device tree binaries and the overlays to tar archive
1 2 3 4 5 6 7 | pwd# /home/michael/raspbian-kernel/rpi-4.1.ymkdir -p $RASP_FILE_ROOT/boot/overlays./scripts/mkknlimg ${KERNEL_SRC}/arch/arm/boot/zImage $RASP_FILE_ROOT/boot/${KERNEL}.imgcp ${KERNEL_SRC}/arch/arm/boot/dts/*.dtb $RASP_FILE_ROOT/boot/cp ${KERNEL_SRC}/arch/arm/boot/dts/overlays/*.dtb* $RASP_FILE_ROOT/boot/overlayscp ${KERNEL_SRC}/arch/arm/boot/dts/overlays/README $RASP_FILE_ROOT/boot/overlays |
Get the latest firmware.Use showref to get the path for git checkout
1 2 3 4 5 6 7 | cd $HOME/raspbian-kernelpwd# /home/michael/raspbian-kernelgit clone --depth=1 https://github.com/raspberrypi/firmware.gitcd firmware # git show-refgit checkout refs/remotes/origin/master |
And also copy the firmware to the tar root
1 2 3 4 5 6 | cp $HOME/raspbian-kernel/firmware/boot/bootcode.bin $RASP_FILE_ROOT/bootcp $HOME/raspbian-kernel/firmware/boot/fixup*.dat $RASP_FILE_ROOT/bootcp $HOME/raspbian-kernel/firmware/boot/start*.elf $RASP_FILE_ROOT/bootmkdir -p $RASP_FILE_ROOT/optcd $HOME/raspbian-kernel/firmware/hardfp/optcp -r . $RASP_FILE_ROOT/opt |
Create the tar archive to transfer the new kernel to the Raspberry
1 2 3 4 5 | cd $RASP_FILE_ROOTpwd# /home/michael/raspbian-kernel/roottar -cvf $HOME/raspbian-kernel/kernel.tar .gzip $HOME/raspbian-kernel/kernel.tar |
Copy the complete kernel archive to the Raspberry
1 | scp /home/michael/raspbian-kernel/kernel.tar.gz pi@IPAddressRaspPI:/home/pi |
And install the new kernel. Note: This overwrites the already installed kernel.img.
1 2 3 4 5 | pi@raspi ~$ sudo su -root@raspi:/home/pi # tar --no-same-owner -xvzf kernel.tar.gz -C /# Edit config.txtroot@raspi:/home/pi # cp /boot/config.txt /boot/config.txt-`date +%Y%m%k-%I%M%S`root@raspi:/home/pi # grep -q '^kernel=.*' /boot/config.txt && sed -i 's/^kernel=.*/kernel=kernel-custom.img/m' /boot/config.txt || echo 'kernel=kernel-custom.img' >> /boot/config.txt |
Reboot the raspberry an check the new kernel version
1 2 | pi@raspi ~$ uname -aLinux raspi.yourdomain 4.1.13-apparmor+ #1 PREEMPT Tue Oct 25 23:10:50 CET 2015 armv6l GNU/Linux |
The script (currently works only an Raspberry Models 1 and it requieres sshpass to run) attached does all things to create the tar archive at once, adjust the IP_RASPBERRY= with the IP Address of your Pi, the SSHPASS= variable with the password of user “pi”, you can also give the password as parameter to the script and then start the script with
1 2 | apt-get install sshpassbash BuildKernelRaspberryPi.sh PiPassword |
and wait…… 🙂
Michael
References: eLinux.org
Raspberry.org
thank you for your insperation. I built up a “little” ansible-playbook based on your tutorial. You can read it here: