https://www.youtube.com/watch?v=QlzoegSuIzg
To build a minimal linux distro, we need three parts:
- The Kernel
- Userspace (busybox)
- Bootloader (syslinux)
When the system boots, it loads the kernel, which loads busybox.
Bootloader -> Kernel -> Userspace
It's bad to install locallly, so we'll do everything in an Ubuntu container.
docker run --privileged -it ubuntu
You'll notice that --privileged
flag. It is required for mounting some stuff later on.
Start by updating the system:
apt update
Then we need to install some packages.
apt install bzip2 git vim make gcc libncurses-dev flex bison bc cpio libelf-dev libssl-dev
First, we need to get a kernel.
We'll start by cloning linux. We'll use the GitHub mirror, because why not?
git clone --depth 1 https://github.com/torvalds/linux.git
cd linux
--depth 1
just means that it won't clone the entire git history. (That would be significantly longer)
Next, we need to make the kernel config. There's a lot of options, and I'm sure you can find some other tutorial for making a kernel config. For this, we'll just use the default options.
make menuconfig
Then arrow over to < Exit >
, and save the configuration.
So, without further ado, let's build the kernel.
make -j$(nproc)
This will take a LONG time...
At the end, you should see a line that says:
Kernel at arch/x86/boot/bzImage is ready
This is our kernel binary. Since we'll need it later, let's copy it to another place.
mkdir /boot-files
cp arch/x86/boot/bzImage /boot-files/
Busybox is a bundle of many basic linux utilities, for example ls
, grep
, and vi
are all included.
First, let's clone the sources (this process will feel very similar to the Kernel)
git clone --depth 1 https://git.busybox.net/busybox
cd busybox
Now, we can edit the busybox config. In this one, we will need to change one option. Go to Settings --->
and toggle [ ] Build static binary (no shared libraries)
. This will make our build simpler; not depending on any shared libraries.
Then exit, and save changes, just like in the kernel.
Now we'll build it, just like the kernel:
make -j$(nproc)
It shouldn't take nearly as long, but you never know...
Since busybox will go into our initramfs, let's make a folder for it in /boot-files
:
mkdir /boot-files/initramfs
Now, we'll install busybox to that directory:
make CONFIG_PREFIX=/boot-files/initramfs install
This will basically just create a bunch of symlinks in that folder
Also, we can remove linuxrc
, because we don't need it.
rm /boot-files/initramfs/linuxrc
The kernel needs something to execute. It looks in /init
for this file. On a normal linux system, this is a systemd binary, but here, it's just a shell script.
cd /boot-files/initramfs
echo << EOF > ./init
#!/bin/sh
/bin/sh
EOF
chmod +x ./init
This short little script will launch a shell as soon as we boot into the system.
An initramfs is a cpio archive. This archive needs to contain all of the files in initramfs/
. First, let's create a list of all of those files:
find .
Then pass it to cpio
to create the archive:
find . | cpio -o -H newc > ../init.cpio
-o
creates a new archive, and -H newc
specifies the type of the archive.
We don't want to create a whole partition for this device, and, luckily, we don't have to. We'll create an empty file and format it with fat.
dd if=/dev/zero of=./boot bs=1M count=50
Hopefully you can spare 50M...
To format it, we'll need dosfstools
:
apt install dosfstools
Then to format it:
mkfs -t fat boot
We'll need the syslinux
package:
apt install syslinux
Then we can install syslinux with:
syslinux ./boot
We need to mount that image (Here's why our container needed root privileges). Create the mountpoint, then mount it there.
mkdir m
mount boot m
Then move the kernel binary and the initramfs to the image:
cp {bzImage,init.cpio} m/
Now we can umount the filesystem:
umount m
We can test the image using qemu. Assuming you don't want to install qemu on your container, we'll copy the files to the host system.
docker cp {container_name}:/boot-files ~/boot-files
Now we can run ./boot
with qemu:
qemu-system-x86_64 -drive format=raw,file=./boot -display gtk
We'll get a prompt that says boot:
. Type,
/bzImage -initrd=/init.cpio
Just wait for it to boot up, then you'll be greeted with a shell prompt!
~ #
You can install any software that you want to the system using the following procedure:
- Build the software, with
CONFIG_PREFIX=/boot-files/initramfs
- Remount
./boot
tom
- Delete the old
init.cpio
andm/init.cpio
- Create a new one, and copy it to
m/
- Umount
./m
The command "make CONFIG_PREFIX=/boot-files/initramfs install"
Seems to not work. Help please?