Custom Kernel: Difference between revisions

From Alpine Linux
(Undo revision 31901 by Prabuanand (talk))
Tag: Undo
 
(85 intermediate revisions by 15 users not shown)
Line 7: Line 7:
You want to build a custom kernel to enable experimental hardware or features or outdated hardware, to reduce bloat further, to tune the kernel to the hardware.
You want to build a custom kernel to enable experimental hardware or features or outdated hardware, to reduce bloat further, to tune the kernel to the hardware.


The vanilla kernel for most Alpine ARCHs uses defaults to balance throughput at the expense of some responsiveness, and support for many devices.  You can tweak the kernel for desktop use and low latency and responsiveness.
The lts kernel for most Alpine ARCHs uses defaults to balance throughput at the expense of some responsiveness, and support for many devices.  You can tweak the kernel for desktop use and low latency and responsiveness.
 
You should disable modules to increase security.  By default, Alpine will install modules but not disable most of them.  Disabling modules will reduce an DMA attack but not eliminate it completely.  If you have a newer processor with VT-d, you can mitigate as long as you:
 
Leave <code>CONFIG_INTEL_IOMMU_DEFAULT_ON=y</code> or pass <code>intel_iommu=on</code> as a kernel parameter and disable kernel logging so the attacker doesn't gain DMAR address information through dmesg.[https://blog.frizk.net/2016/11/disable-virtualization-based-security.html]  Also remove references to the kernel version to calculate the IOMMU addresses.[https://link.springer.com/content/pdf/10.1186/s13173-017-0066-7.pdf]
 
You may also want to harden your kernel by adding at least some of the config changes recommended by <code>kernel-hardening-checker</code> [https://github.com/a13xp0p0v/kernel-hardening-checker/]
 
To increase the security of the boot process, if you have a TPM, you could set <code>CONFIG_INTEL_TXT=y</code> (Enable Intel(R) Trusted Execution Technology (Intel(R) TXT)) (which is not enabled in the hardened kernel by default), then you would need the SINIT module (provided only by Intel)[https://software.intel.com/en-us/articles/intel-trusted-execution-technology], a possibly compiled TrustedGrub2[https://github.com/Rohde-Schwarz-Cybersecurity/TrustedGRUB2], trousers[https://sourceforge.net/projects/trousers/?source=navbar], tboot[https://sourceforge.net/projects/tboot/].  These packages are not in aports and it is unknown if these tools work on musl.  It's not recommended for Edge.  Also, there would be trigger packages to generate hashes for the kernel and the mkinitfs updates.


== Setting up the Alpine Build System ==
== Setting up the Alpine Build System ==


First, you need to follow the steps in [[Creating_an_Alpine_package#Setup_your_system_and_account|Setup your system and account for building packages]].  You also need to configure your /etc/apk/repositories so that they search locally for your apks.  See [[Creating_an_Alpine_package#Testing_the_package_locally|Testing the package locally]] for details.
First, you need to follow the steps in [[Creating_an_Alpine_package#Setup_your_system_and_account|Setup your system and account for building packages]].  You also need to configure your {{path|/etc/apk/repositories}} so that they search locally for your apks.  See [[Creating_an_Alpine_package#Testing_the_package_locally|Testing the package locally]] for details.
 
After setting up accounts and repos, change your shell's current working directory to '''aports''' that you just cloned.
 
{{cmd|$ cd aports}}


== Working with aports ==
== Working with aports ==


There are several ways to maintain a kernel.  The first option is to create a new kernel package.  The other option is to just use the existing vanilla kernel just tweaking the configure-vanilla.ARCH file.  
We will try using an existing lts kernel just tweaking the {{path|lts.ARCH.config}} file.


=== Switching to the proper release version ===
=== Switching to the proper release version ===
Line 29: Line 41:
| master
| master
|-
|-
| 3.7.0
|{{#expr:{{AlpineLatest}}}}
| 3.7-stable
|{{#expr:{{AlpineLatest}}}}-stable
|-  
|-  
|}
|}


The following is required to get access to the APKBUILD released for that version of Alpine and which you will create a commit for.
The following is required to get access to the {{path|APKBUILD}} released for that version of Alpine and which you will create a commit for.


If you are on 3.7 do:
If you are on {{#expr:{{AlpineLatest}}}} do:


  git checkout -b 3.7-stable origin/3.7-stable
{{cmd|$ git checkout -b {{#expr:{{AlpineLatest}}}}-stable origin/{{#expr:{{AlpineLatest}}}}-stable}}


If you are on Edge do:
If you are on Edge do:


  git checkout master
{{cmd|$ git checkout master}}
 
=== Creating your config ===
 
You can use {{pkg|linux-lts}} but what you should do is create a local branch by doing:
 
For <var>linux-lts</var> kernel on Alpine {{#expr:{{AlpineLatest}}}}:


=== Option A: Creating a new kernel package ===
{{cmd|$ git checkout -b my-custom-kernel origin/{{#expr:{{AlpineLatest}}}}-stable}}


Use this option only if you want to want to be a kernel package maintainer or have custom patches.
For Alpine Edge:


What you need to do is copy ''main/linux-vanilla'' folder to ''testing/linux-NAME'', where NAME could be anything but usually initials or a project name to a special kernel patch or patchset.  Just use your last name if you don't know what to put.  Rename all files from vanilla to NAME.  Rename everything in APKBUILD from vanilla to NAME.
{{cmd|$ git checkout -b my-custom-kernel}}


=== Option B: Vanilla with native settings and minimal edits ===
Doing it this way, you do less work in maintaining.  All you need to do is keep ''master'' or ''{{#expr:{{AlpineLatest}}}}-stable'' in sync[https://help.github.com/articles/syncing-a-fork/][https://help.github.com/articles/configuring-a-remote-for-a-fork/] and merge any conflicts. 


Most users will want to use this option.
First switch to the branch by doing:{{cmd|$ git checkout my-custom-kernel}}
Then, you need to navigate to the {{path|main/linux-lts}} folder where you should see a APKBUILD and some config- files.


You can use linux-vanilla but what you should do is create a local branch by doing:
It is a good idea to use custom `FLAVOR` in order to change the name of your kernel and package (custom flavor or revision) so you newly build kernel will not override the existing linux-lts and it's modules. Flavor build will only use your config and omit files that are not for your cpu architectures or virt* configs.(Virt configs provide optimized kernel configurations for running Alpine as a guest in virtual machines.)
This will also speed up the process of applying kernel patches by applying it for your architecture only. (Obviously ARCH in the following example is whatever architecture x86, x86_64...you use.)


For Alpine Edge:
First make a copy of your ARCH config file:
<pre>
cp lts.x86_64.config lts-my_custom.x86_64.config
</pre>


  git checkout -b my-custom-kernel
Edit your custom config file and add your changes. When you are done with your edits you need to run checksum to update APKBUILD:


For Alpine 3.7:
<code>FLAVOR=lts-my_custom abuild checksum</code>


  git checkout -b my-custom-kernel origin/3.7-stable
Then commit your changes:


Doing it this way, you do less work in maintaining.  All you need to do is keep ''master'' or ''3.7-stable'' in sync[https://help.github.com/articles/syncing-a-fork/][https://help.github.com/articles/configuring-a-remote-for-a-fork/] and merge any conflicts. 
<code>git commit -a -m "Enabled these options ...."</code>


First switch to the branch by doing <code>git checkout my-custom-kernel</code>.  Then, you need to navigate to the ''main/linux-vanilla'' folder where you should see a APKBUILD and some config- files.  When you are done with your edits either by editing directly the APKBUILD and copyting the config-vanilla.ARCH as .config in the linux-4.15 folder.  You will then move the .config back overriding the config-vanilla.ARCH generated by <code>make menuconfig</code> (discussed below in the ''Configuring kernel'' section).  After generating your config, you need to <code>abuild checksum</code>.  Then, do <code>git add APKBUILD config-vanilla.ARCH</code> where ARCH is whatever architecture (x86, x86_64, ...) you use.  Then, you need to do <code>git commit APKBUILD config-NAME.ARCH -m "Enabled these options ...."</code> for your custom _flavor and the ARCHitecture of your system.  You do this so that git can keep your code separate from Alpine's and so your changes float forward between kernel updates.
You do this so that git can keep your code separate from Alpine's and so your changes float forward between kernel updates.


== Adding custom patches ==
== Adding custom patches ==
Line 78: Line 101:
== Configuring kernel ==
== Configuring kernel ==


Attempt to build the kernel first. To do that, you do abuild -rK to install most of the dependencies. If it complains about a dependency like elfutils-dev use -rKd. Then, when it prompts for values for new found config options just hold enter till it starts compiling the kernel. There should be two sets one for -vanilla and the other for the -virt. Just Ctrl+C out of the compilation process after the second set so you can further customize the config. Then you go into the src/linux-VER and edit the config file. Copy the .config file overriding the config-NAME.ARCH in the srcdir.
There are multiple ways to prepare and change kernel config. The basic one is to just edit your custom config file. You can also attempt to create a config tailored for your currently running system and modules.
 
To create a kernel config based on your currently running PC, use:
<pre>
make localmodconfig
</pre>
This command reads your current kernel's configuration from /proc/config.gz (if available) or /boot/config-* and creates a .config file that includes only the modules currently loaded on your system. This results in a minimal configuration tailored to your hardware.
Alternatively, you can use:
<pre>make localyesconfig</pre>
This is similar to ''localmodconfig'', but instead of building features as modules (m), it builds them directly into the kernel (y), which can result in a larger kernel image but eliminates the need for separate module files.
Note: Before running either command, make sure you have all the hardware you want to support actively in use (USB devices plugged in, network cards active, etc.) so their modules are loaded and included in the configuration.
 
The alternative is to use the kernel configuration menu in the build-NAME folder, but before you do that you need to <code>sudo apk add {{pkg|ncurses-dev}}</code>
 
After you are done using the menu in the build-NAME folder by doing:
 
<pre>make menuconfig</pre>


The alternative is to use the kernel configuration menu in the build-NAME folder, but before yo do that you need to <code>sudo apk add ncurses-dev</code>
You want to remove <code>ncurses-dev</code>.  When you are done, it will be stored in ''.config'' which you need to again override the {{path|lts.ARCH.config}} file.


After you are done using the menu in the build-NAME folder by doing <code>make menuconfig</code>, you want to remove <code>ncurses-dev</code>.  When you are done, it will be stored in ''.config'' which you need to again override the config-NAME.ARCH file.  When you are done updating the config-NAME.ARCH, you need to do <code>abuild checksum</code>.
When you are done updating the {{path|config-NAME.ARCH}}, you need to update sums:
<pre>
abuild checksum
</pre>


The options in the kernel config are typically defaults.  If your device is old, it may be set to n by default.
The options in the kernel config are typically defaults.  If your device is old, it may be set to n by default.
Line 99: Line 141:
|IBM zEnterprise 114 and 196
|IBM zEnterprise 114 and 196
|IBM zBC12 and zEC12 (<code>-march=zEC12 -mtune=zEC12</code>)
|IBM zBC12 and zEC12 (<code>-march=zEC12 -mtune=zEC12</code>)
|100 Hz
|1000 Hz
|No Forced Preemption (Server)
|No Forced Preemption (Server)
|64
|64
Line 106: Line 148:
|Server processors
|Server processors
|POWER8 (<code>-mcpu=power8</code>), AltiVec (<code>-Wa,-maltivec</code> to assembler or <code>-maltivec -mabi=altivec</code>), VSX
|POWER8 (<code>-mcpu=power8</code>), AltiVec (<code>-Wa,-maltivec</code> to assembler or <code>-maltivec -mabi=altivec</code>), VSX
|100 HZ
|1000 HZ
|No Forced Preemption (Server)
|No Forced Preemption (Server)
|64
|64
Line 115: Line 157:
* Apple PowerMac based machines
* Apple PowerMac based machines
|AltiVec (<code>-Wa,-maltivec</code> to assembler or <code>-maltivec -mabi=altivec</code>) on >=74xx
|AltiVec (<code>-Wa,-maltivec</code> to assembler or <code>-maltivec -mabi=altivec</code>) on >=74xx
|250 HZ
|1000 HZ
|No Forced Preemption (Server)
|No Forced Preemption (Server)
|32
|32
Line 121: Line 163:
|x86_64
|x86_64
|Generic-x86-64
|Generic-x86-64
|(-mtune=generic ; SIMD assembly modules enabled based on simple test and presence of CPU flag)
|(-mtune=generic ; SIMD assembly modules enabled based on simple compile test and/or presence of CPU flag)
|300 HZ
|1000 HZ
|Voluntary Kernel Preemption (Desktop)
|Voluntary Kernel Preemption (Desktop)
|32
|64
|-
|-
|x86
|x86
|586/K5/5x86/6x86/6x86MX
|586/K5/5x86/6x86/6x86MX
|(-mtune=generic ; SIMD assembly modules enabled based on simple test and presence of CPU flag)
|(-mtune=generic ; SIMD assembly modules enabled based on simple compile test and/or presence of CPU flag)
|300 HZ
|1000 HZ
|Voluntary Kernel Preemption (Desktop)
|Voluntary Kernel Preemption (Desktop)
|32
|32
|-
|-
|armhf
|armv7
|
|
* ARMv7 based platforms (Cortex-A, PJ4, Scorpion, Krait)
* ARMv7 based platforms (Cortex-A, PJ4, Scorpion, Krait)
Line 141: Line 183:
* ARM Ldt Versatile Express family --  
* ARM Ldt Versatile Express family --  
|Either <code>-march=armv7-a</code> or <code>-march=armv5t -Wa,-march=armv7-a</code> based on a compile test. <code>-mfpu=vfp</code>
|Either <code>-march=armv7-a</code> or <code>-march=armv5t -Wa,-march=armv7-a</code> based on a compile test. <code>-mfpu=vfp</code>
|100 Hz
|1000 Hz
|Voluntary Kernel Preemption (Desktop)
|Voluntary Kernel Preemption (Desktop)
|32
|32
Line 166: Line 208:
* Xilinx ZynqMP Family
* Xilinx ZynqMP Family
|
|
|300 HZ
|1000 HZ
|Voluntary Kernel Preemption (Desktop)
|Voluntary Kernel Preemption (Desktop)
|64
|64
Line 191: Line 233:
* SHA512 -- avx2, ssse3, neon
* SHA512 -- avx2, ssse3, neon
* POLY1305 -- avx2
* POLY1305 -- avx2
* GHASH -- pclmulqdq, vmx (power8)
* GHASH -- pclmulqdq (part of aes-ni), vmx (power8)
* AES -- aes-ni, neon, vmx (power8), spe
* AES -- aes-ni, neon, vmx (power8), spe
* CRC32 -- pclmulqdq, sse, neon, vmx (power8)
* CRC32 -- pclmulqdq, sse, neon, vmx (power8)
Line 197: Line 239:


=== Fast reboots with kexec ===
=== Fast reboots with kexec ===
{{main|kexec}}


If you want to reboot the kernel fast avoiding the POST test, you need <code>sudo apk add kexec-tools</code> and enable kexec in the kernel:
If you want to reboot the kernel fast avoiding the POST test, you need {{ic|doas apk add {{pkg|kexec-tools}}}} and enable kexec in the kernel:


   Processor type and features
   Processor type and features
     [x] kexec system call
     [*] kexec system call
 
=== For the kernel package maintainer ===
 
Each config-NAME.ARCH should be updated for all ARCHes so that it doesn't disrupt the building process.  To do this for a particular ARCH:
 
  cd src/linux-4.15
  cp ../../config-NAME.ARCH .config
  yes "" | make ARCH=x86 oldconfig
  (hold enter to accept all default options)
  make ARCH=x86 menuconfig (optional to tweak it for the particular arch)
  cp .config ../../config-NAME.ARCH
 
The supported archs are in the linux-4.15/arch directory which you replace x86 in the above block or one of the kernel ARCHs below.  The mapping is as follows:
{|| cellpadding="5" border="1" class="wikitable"
!Alpine ARCH
!Kernel ARCH
!Form Factor
!Dated
|-
|x86
|x86
|Balanced between desktop PC, laptop and server (i586 is minimum)
|Older generation
|-
|x86_64
|x86
|Balanced between desktop PC, laptop and server, including newer Apple PC/laptops.
|Current generation
|-
|s390x
|s390
|Mainframe
|Current generation
|-
|ppc64le (64 bit; little endian)
|powerpc
|Servers and datacenters mostly ; vanilla is setup as server
|Active
|-
|ppc (32 bit)
|powerpc
|Consoles, older Apple PCs, servers ; vanilla is setup as server or unitasker kiosk or appliance
|Dwindling production
|-
|aarch64
|arm64
|Mostly mobile, single board computers (Raspberry PI), newer smaller laptops and tablets, few datacenter
|Current Generation
|-
|armhf (w/hardware floating point)
|arm
|Mobile, single board computers (Raspberry PI)
|Older Generation
|-
|}


(It doesn't make sense to compile to other architectures.  Alpine's precompiled userland is limited to the ARCHes above.  If your architecture is not listed, then you need to cross-compile the whole userland yourself.  Instructions to do this is provided in the cross compile section.)
=== Hibernation to prevent data loss ===


Or after abuild has unpacked and patched your kernel, you can use this script which you will place in the same folder as the APKBUILD:
  Power management and ACPI options
    [*] Hibernation (aka 'suspend to disk')


{{cat|update-menu|<nowiki>
Hibernation should be used if you have a laptop.  You don't want the laptop to suddenly shut off resulting in data loss, you want it to save your work based on a percentage of battery life (this requires special script).  When hibernation resumes, should lock and ask for credentials.  Depending on your needs, the hibernated image can be encrypted/decrypted which again requires additional customization to scripts.
#!/bin/bash
# Copyright 2018 Orson Teodoro
# License: MIT


_flavor="zen"
Hibernation with an unsanitized swap file is generally insecure because data and unlocked memory pages are swapped out in plaintext.  To increase the security either disable swap or use an encrypted swap.  The swap file/partition is typically used as the hibernation resume image.
cd src/build-$_flavor


update_oldconfig() {
== Building ==
        ALPINE_ARCH="$1"
        KERNEL_ARCH="$2"
        cp ../../config-$_flavor.$ALPINE_ARCH .config
        yes "" | make ARCH=$KERNEL_ARCH oldconfig
        cp .config ../../config-$_flavor.$ALPINE_ARCH
}
 
update_menuconfig() {
        ALPINE_ARCH="$1"
        KERNEL_ARCH="$2"
        cp ../../config-$_flavor.$ALPINE_ARCH .config
        make ARCH=$KERNEL_ARCH menuconfig
        cp .config ../../config-$_flavor.$ALPINE_ARCH
}
 
update_all_oldconfig() {
        update_oldconfig aarch64 arm64
        update_oldconfig armhf arm
        update_oldconfig ppc64le powerpc
        update_oldconfig ppc powerpc
        update_oldconfig x86_64 x86
        update_oldconfig x86 x86
        update_oldconfig s390x s390
}
 
update_all_menuconfig() {
        update_menuconfig aarch64 arm64
        update_menuconfig armhf arm
        update_menuconfig ppc64le powerpc
        update_menuconfig ppc powerpc
        update_menuconfig x86_64 x86
        update_menuconfig x86 x86
        update_menuconfig s390x s390
}
 
update_all_oldconfig
update_all_menuconfig
</nowiki>
}}
 
You can comment out the last update_all_menuconfig if you want to edit by hand the config-$_flavor.ARCH.
 
Don't forget to  <code>abuild checksum</code> when you have processed all ARCHs.


The kernel package name should not have the number in the name.  You will either use _gitYYYYMMDD or _p to attach the version number of the patch.
Before building, make sure you have ccache installedThis should reduce compile time on multiple builds.
You may also want to read up on compile flags - perhaps you want your build to be optimized for speed (or size which is the default).
Review <code>/etc/abuild.conf</code> and set:
<pre>
PACKAGER_PRIVKEY="/home/MY_USER_HERE/.abuild/my-email@mydomain.com-ID.rsa"
USE_CCACHE=1
</pre>
Please note that kernel build process may not use some of the settings you set in `abuild.conf` so in order to customize compiler or linker and/or it's flags you may need to edit APKBUILD.
If you have your config ready, first try building with:
<pre>
FLAVOR=lts-my_custom abuild -rK 2>&1 | tee build1.log
</pre>


== Building ==
This will install most of the dependencies and keep buildtime temp dirs and files (srcdir/pkgdir/deps).


You should then do an <code>abuild -r</code> to attempt to build it.
If it complains about a dependency like {{pkg|elfutils-dev}} use <code>-rKd</code>.
Then, when it prompts for values for new found config options just hold enter till it starts compiling the kernel.
Unless you use <code>FLAVOR</code> or removed or commented out <code>virt.*.config</code> configs in APKBUILD there should be two sets one for -lts and the other for the -virt.
Just {{Key|Ctrl}}+{{Key|C}} out of the compilation process after
the second set so you can further customize the config.
Then you go into the {{path|src/linux-VER}} and edit the config file.
Copy the {{path|.config}} file overriding the {{path|lts.ARCH.config}} in the srcdir.


== Installing ==
== Installing ==


To install it you do a <code>sudo apk add linux-NAME</code> where NAME is your custom kernel release name or vanilla if you used option B.
If the build was successful the kernel packages are located in <code>~/packages/main/ARCH</code>
You probably already know how to install a package in your Alpine Linux...


== Bootloader ==
== Testing ==
 
You need to configure your bootloader to use the kernel.  Add a new entry but do not replace the old kernel.  The old kernel is your way back if the kernel config was a bad one.  The naming scheme should be similar but with the tag.  You should make sure that the _flavor name is attached for new kernel packages and do not override the existing vanilla kernel and the existing vanilla initramfs.


For Grub, in your /boot/grub/grub.cfg if mounted should contain the new entry something like
In case your new kernel may be missing a module and can't boot it is generally a good idea to keep the default <code>linux-lts</code>, so make sure you have it installed using the command: {{Cmd|# apk add {{pkg|linux-lts}}}}


  menuentry 'Alpine Linux (ck1)' {
Normally during the installation using with [[apk]], there are tools that will update initramfs and a boot loader automatically for you. For easier debugging you may want to change boot loader config and remove <code>quiet</code> from linux command line in {{Path|/etc/default/grub}} or {{Path|/etc/update-extlinux.conf}}.
          set root=(hd0,7)
Or perhaps you want to change other kernel options in {{Path|/etc/mkinitfs/mkinitfs.conf}}. Please remember to generate initramfs and update your bootloader manually, eg:
          linux /vmlinuz-ck1 root=/dev/sda17 rw modules=sd-mod,usb-storage,ext4
{{Cmd|<nowiki># mkinitfs
          initrd /initramfs-ck1
# grub-mkconfig -o /boot/grub/grub.cfg</nowiki>}}
  }


In the above entry hd0,7 (in one based indexing) is associated with the boot partition /dev/sda7.  /dev/sda17 should point to your userland partition containing your Alpine system files (/usr/bin, /bin, ...).
In case something goes wrong with a boot process it is also a good idea to have a bootable rescue Alpine USB ready.


To install the bootloader with grub, you do something like <code>grub-install --force /dev/sda7</code> where /dev/sda7 is your bootable drive found with <code>fdisk -l</code> or <code>grub-install --force /dev/sda</code> to install it at your MBR depending on how you set up grub.
Once you have the default lts kernel and rescue USB <code>reboot</code> the computer.
 
== Testing ==


To test, first you should make a bootable Alpine USB imageThen, when you have your rescue USB done, you <code>sudo reboot</code> the computer.
If you are curious about correctness testing, some kernel modules or components do preform self tests at the beginning of the boot processThe tools may have test suites that you run with the make command.


To test it, you basically do trial and error. Sometimes your config is missing something if you want to have a bare minimum setting.
== See Also ==
* [[Kernels]]
* [https://wiki.archlinux.org/title/Kernel Archwiki Kernels]
* [https://wiki.gentoo.org/wiki/Kernel Gentoo Wiki Kernel]
* [https://wiki.gentoo.org/wiki/Kernel/Configuration Gentoo Wiki Kernel Configuration]
* [[How to build the Alpine Linux kernel]]
* [[Kernel_live_patching|Kernel Live Patching (KLP)]]


[[Category:Kernel]]
[[Category:Kernel]]

Latest revision as of 04:45, 31 December 2025

This material is work-in-progress ...

Do not follow instructions here until this notice is removed.
(Last edited by Prabuanand on 31 Dec 2025.)

This process of building a custom configured kernel assumes you are running on Alpine Linux utilizing abuild & aports.

But why?

You want to build a custom kernel to enable experimental hardware or features or outdated hardware, to reduce bloat further, to tune the kernel to the hardware.

The lts kernel for most Alpine ARCHs uses defaults to balance throughput at the expense of some responsiveness, and support for many devices. You can tweak the kernel for desktop use and low latency and responsiveness.

You should disable modules to increase security. By default, Alpine will install modules but not disable most of them. Disabling modules will reduce an DMA attack but not eliminate it completely. If you have a newer processor with VT-d, you can mitigate as long as you:

Leave CONFIG_INTEL_IOMMU_DEFAULT_ON=y or pass intel_iommu=on as a kernel parameter and disable kernel logging so the attacker doesn't gain DMAR address information through dmesg.[1] Also remove references to the kernel version to calculate the IOMMU addresses.[2]

You may also want to harden your kernel by adding at least some of the config changes recommended by kernel-hardening-checker [3]

To increase the security of the boot process, if you have a TPM, you could set CONFIG_INTEL_TXT=y (Enable Intel(R) Trusted Execution Technology (Intel(R) TXT)) (which is not enabled in the hardened kernel by default), then you would need the SINIT module (provided only by Intel)[4], a possibly compiled TrustedGrub2[5], trousers[6], tboot[7]. These packages are not in aports and it is unknown if these tools work on musl. It's not recommended for Edge. Also, there would be trigger packages to generate hashes for the kernel and the mkinitfs updates.

Setting up the Alpine Build System

First, you need to follow the steps in Setup your system and account for building packages. You also need to configure your /etc/apk/repositories so that they search locally for your apks. See Testing the package locally for details.

After setting up accounts and repos, change your shell's current working directory to aports that you just cloned.

$ cd aports

Working with aports

We will try using an existing lts kernel just tweaking the lts.ARCH.config file.

Switching to the proper release version

You need to switch to the proper branch that matches the release so that the kernel compiles against the dependencies properly.

Alpine version Remote branch
Edge master
3.23 3.23-stable

The following is required to get access to the APKBUILD released for that version of Alpine and which you will create a commit for.

If you are on 3.23 do:

$ git checkout -b 3.23-stable origin/3.23-stable

If you are on Edge do:

$ git checkout master

Creating your config

You can use linux-lts but what you should do is create a local branch by doing:

For linux-lts kernel on Alpine 3.23:

$ git checkout -b my-custom-kernel origin/3.23-stable

For Alpine Edge:

$ git checkout -b my-custom-kernel

Doing it this way, you do less work in maintaining. All you need to do is keep master or 3.23-stable in sync[8][9] and merge any conflicts.

First switch to the branch by doing:

$ git checkout my-custom-kernel

Then, you need to navigate to the main/linux-lts folder where you should see a APKBUILD and some config- files.

It is a good idea to use custom `FLAVOR` in order to change the name of your kernel and package (custom flavor or revision) so you newly build kernel will not override the existing linux-lts and it's modules. Flavor build will only use your config and omit files that are not for your cpu architectures or virt* configs.(Virt configs provide optimized kernel configurations for running Alpine as a guest in virtual machines.) This will also speed up the process of applying kernel patches by applying it for your architecture only. (Obviously ARCH in the following example is whatever architecture x86, x86_64...you use.)

First make a copy of your ARCH config file:

cp lts.x86_64.config lts-my_custom.x86_64.config

Edit your custom config file and add your changes. When you are done with your edits you need to run checksum to update APKBUILD:

FLAVOR=lts-my_custom abuild checksum

Then commit your changes:

git commit -a -m "Enabled these options ...."

You do this so that git can keep your code separate from Alpine's and so your changes float forward between kernel updates.

Adding custom patches

Custom patches should be added to sources=.

After you added the URL, you need to produce a checksum by doing abuild checksum.

The custom patches may not be autopatched, due to being distributed as an archive or different patch level, so you need to define what to do with it in the prepare().

Configuring kernel

There are multiple ways to prepare and change kernel config. The basic one is to just edit your custom config file. You can also attempt to create a config tailored for your currently running system and modules.

To create a kernel config based on your currently running PC, use:

make localmodconfig

This command reads your current kernel's configuration from /proc/config.gz (if available) or /boot/config-* and creates a .config file that includes only the modules currently loaded on your system. This results in a minimal configuration tailored to your hardware. Alternatively, you can use:

make localyesconfig

This is similar to localmodconfig, but instead of building features as modules (m), it builds them directly into the kernel (y), which can result in a larger kernel image but eliminates the need for separate module files. Note: Before running either command, make sure you have all the hardware you want to support actively in use (USB devices plugged in, network cards active, etc.) so their modules are loaded and included in the configuration.

The alternative is to use the kernel configuration menu in the build-NAME folder, but before you do that you need to sudo apk add ncurses-dev

After you are done using the menu in the build-NAME folder by doing:

make menuconfig

You want to remove ncurses-dev. When you are done, it will be stored in .config which you need to again override the lts.ARCH.config file.

When you are done updating the config-NAME.ARCH, you need to update sums:

abuild checksum

The options in the kernel config are typically defaults. If your device is old, it may be set to n by default.

Vanilla targets and tuning

ARCH Processor Type / CPU Selection / System Type Code Generation / Instruction Extensions Timer Frequency Preemption Model Bitness
s390x IBM zEnterprise 114 and 196 IBM zBC12 and zEC12 (-march=zEC12 -mtune=zEC12) 1000 Hz No Forced Preemption (Server) 64
ppc64le Server processors POWER8 (-mcpu=power8), AltiVec (-Wa,-maltivec to assembler or -maltivec -mabi=altivec), VSX 1000 HZ No Forced Preemption (Server) 64
ppc

512x/52xx/6xx/7xx/74xx/82xx/83xx/86xx

  • Apple PowerMac based machines
AltiVec (-Wa,-maltivec to assembler or -maltivec -mabi=altivec) on >=74xx 1000 HZ No Forced Preemption (Server) 32
x86_64 Generic-x86-64 (-mtune=generic ; SIMD assembly modules enabled based on simple compile test and/or presence of CPU flag) 1000 HZ Voluntary Kernel Preemption (Desktop) 64
x86 586/K5/5x86/6x86/6x86MX (-mtune=generic ; SIMD assembly modules enabled based on simple compile test and/or presence of CPU flag) 1000 HZ Voluntary Kernel Preemption (Desktop) 32
armv7
  • ARMv7 based platforms (Cortex-A, PJ4, Scorpion, Krait)
  • Freescale i.MX family -- Cortex A (i.MX51, i.MX53, i.MX6 Quad/DualLite, i.MX6 SoloLite, i.MX6 SoloX, i.MX6 UltraLite, i.MX7 Dual)
  • Qualcomm -- (MSM8X60, MSM8960, MSM8974)
  • Allwinner SoCs -- (A10 (sun4i), A10s / A13 (sun5i), A31 (sun6i), A20 (sun7i), sun8i Family, (sun9i))
  • ARM Ldt Versatile Express family --
Either -march=armv7-a or -march=armv5t -Wa,-march=armv7-a based on a compile test. -mfpu=vfp 1000 Hz Voluntary Kernel Preemption (Desktop) 32
aarch64
  • Allwinner sunxi 64-bit SoC Family
  • Broadcom BCM2835 family
  • Marvell Berlin SoC Family
  • ARMv8 based Samsung Exynos SoC family
  • ARMv8 based Freescale Layerscape SoC family
  • Hisilicon SoC Family
  • Mediatek MT65xx & MT81xx ARMv8 SoC
  • Marvell EBU SoC Family
  • Qualcomm Platforms
  • Rockchip Platforms
  • AMD Seattle SoC Family
  • Altera's Stratix 10 SoCFPGA Family
  • NVIDIA Tegra SoC Family
  • Spreadtrum SoC platform
  • Cavium Inc. Thunder SoC Family
  • ARMv8 software model (Versatile Express)
  • AppliedMicro X-Gene SOC Family
  • Xilinx ZynqMP Family
1000 HZ Voluntary Kernel Preemption (Desktop) 64

If you do desktop multitasking, you may want to switch to Voluntary Kernel Preemption (Desktop) or Preemptible Kernel (Low-Latency Desktop) and up the Timer Frequency. If you run a dedicated render farm node or a dedicated bitcoin miner use No Forced Preemption (Server) and decrease the Timer Frequency.

Optimized modules (most are already compiled as modules):

  • raid6 -- altivec, avx512, ssse3, avx2, mmx, sse, sse2, neon
  • some operations of raid5 -- mmx (32 bit), sse (64 bit), avx

For Kernel API:

  • 32-bit memcpy -- 3dnow
  • 32-bit memory page clearing and copying -- sse (Athlon/K7 only), mmx

From x86/crypto, arm/crypto, powerpc/crypto:

  • CAMELLIA -- avx2, avx, aes-ni
  • CHACHA20 -- avx2, neon
  • CAST5 -- avx
  • CAST6 -- avx
  • TWOFISH -- avx
  • SERPENT -- avx2, avx, sse2
  • SHA1 -- avx2, ssse3, neon, spe
  • SHA2 -- avx2
  • SHA256 -- ssse3, neon, spe
  • SHA512 -- avx2, ssse3, neon
  • POLY1305 -- avx2
  • GHASH -- pclmulqdq (part of aes-ni), vmx (power8)
  • AES -- aes-ni, neon, vmx (power8), spe
  • CRC32 -- pclmulqdq, sse, neon, vmx (power8)
  • CRCT10DIF -- pclmulqdq, sse, neon, vmx (power8)

Fast reboots with kexec

If you want to reboot the kernel fast avoiding the POST test, you need doas apk add kexec-tools and enable kexec in the kernel:

 Processor type and features
   [*] kexec system call

Hibernation to prevent data loss

 Power management and ACPI options
   [*] Hibernation (aka 'suspend to disk')

Hibernation should be used if you have a laptop. You don't want the laptop to suddenly shut off resulting in data loss, you want it to save your work based on a percentage of battery life (this requires special script). When hibernation resumes, should lock and ask for credentials. Depending on your needs, the hibernated image can be encrypted/decrypted which again requires additional customization to scripts.

Hibernation with an unsanitized swap file is generally insecure because data and unlocked memory pages are swapped out in plaintext. To increase the security either disable swap or use an encrypted swap. The swap file/partition is typically used as the hibernation resume image.

Building

Before building, make sure you have ccache installed. This should reduce compile time on multiple builds. You may also want to read up on compile flags - perhaps you want your build to be optimized for speed (or size which is the default). Review /etc/abuild.conf and set:

PACKAGER_PRIVKEY="/home/MY_USER_HERE/.abuild/my-email@mydomain.com-ID.rsa"
USE_CCACHE=1

Please note that kernel build process may not use some of the settings you set in `abuild.conf` so in order to customize compiler or linker and/or it's flags you may need to edit APKBUILD. If you have your config ready, first try building with:

FLAVOR=lts-my_custom abuild -rK 2>&1 | tee build1.log

This will install most of the dependencies and keep buildtime temp dirs and files (srcdir/pkgdir/deps).

If it complains about a dependency like elfutils-dev use -rKd. Then, when it prompts for values for new found config options just hold enter till it starts compiling the kernel. Unless you use FLAVOR or removed or commented out virt.*.config configs in APKBUILD there should be two sets one for -lts and the other for the -virt. Just Ctrl+C out of the compilation process after the second set so you can further customize the config. Then you go into the src/linux-VER and edit the config file. Copy the .config file overriding the lts.ARCH.config in the srcdir.

Installing

If the build was successful the kernel packages are located in ~/packages/main/ARCH You probably already know how to install a package in your Alpine Linux...

Testing

In case your new kernel may be missing a module and can't boot it is generally a good idea to keep the default linux-lts, so make sure you have it installed using the command:

# apk add linux-lts

Normally during the installation using with apk, there are tools that will update initramfs and a boot loader automatically for you. For easier debugging you may want to change boot loader config and remove quiet from linux command line in /etc/default/grub or /etc/update-extlinux.conf. Or perhaps you want to change other kernel options in /etc/mkinitfs/mkinitfs.conf. Please remember to generate initramfs and update your bootloader manually, eg:

# mkinitfs # grub-mkconfig -o /boot/grub/grub.cfg

In case something goes wrong with a boot process it is also a good idea to have a bootable rescue Alpine USB ready.

Once you have the default lts kernel and rescue USB reboot the computer.

If you are curious about correctness testing, some kernel modules or components do preform self tests at the beginning of the boot process. The tools may have test suites that you run with the make command.

See Also