Beyond dual boot, make Linux and FreeBSD friends

This is a continuation of a previous post on dual boot UEFI Linux/FreeBSD.

Dual boot is not enough and we want both FreeBSD and Linux to get along for the better. To this end we will discuss several aspect of making both OS recognize each other and work in parallel.

Note that this post in particular is subject to changes. These things evolve rapidly so some details may not be accurate, not up-to-date or differ from your specific setup. So please feel free to comment/update/add ideas/point out errors or missing details. Thanks!

We will look at the following aspect:

Access each other data

The first step is to recall your partition layout and what it looks like on FreeBSD and Linux. Take time to note it on a piece of paper. That’s especially useful if you have extra hard disks with additional data partitions. To recall in the previous post we had:

Name FreeBSD Linux
EFI /dev/ada0p1 /dev/sda1
Linux SWAP /dev/ada0p2 /dev/sda2
Linux ‘/’ (ext4) /dev/ada0p3 /dev/sda3
FreeBSD SWAP /dev/ada0p4 /dev/sda4
FreeBSD ‘/’ (UFS) /dev/ada0p5 /dev/sda5

FreeBSD and Linux can both access their counterpart ext4 and UFS partition. In particular, FreeBSD can also write to Linux’s ext4 partitions. Linux supports writing to UFS in theory, but I would strongly recommend against that. Last time I tested, it only completely wrecked the UFS partition and had to reformat it. In fact, I’d recommend that you mount the counterpart OS partition in read-only to avoid messing with anything. Eventually setup another shared ext4 partition that you access in writing from both Linux and FreeBSD. At least if something goes wrong, you only loose that.

As for the swap partitions, both OS can use each other partition. Linux however requires a special signature which can be created with mkswap. However I don’t think this is still required and it works fine without it.

We will add the mount point in /mnt, that’s as good a place as any. Of course everything below must be done as root.

FreeBSD

Create the mount point for Linux:

mkdir /mnt/linux

We want to mount the second (Linux swap) and third (Linux ext4) partitions, that is for FreeBSD /dev/ada0p2 and /dev/ada0p3. Add the partitions to the end of /etc/fstab:

/dev/ada0p2 none swap sw 0 0
/dev/ada0p3 /mnt/linux ext2fs failok,ro 0 0

Notice the failok option for /mnt/linux. It means that the FreeBSD boot should not fail if the ext4 partition fails to mount. Otherwise, if the partition was marked as dirty by Linux (for instance you did a hard reboot) and then you reboot directly into FreeBSD, mounting the ext4 partition would fail because it requires an fsck.

Linux

Create the mount point for FreeBSD:

mkdir /mnt/freebsd

We want to mount the fourth (FreeBSD swap) and fifth (FreeBSD UFS) partitions, that is for Linux /dev/sda4 and /dev/sda5. Add the partitions to the end of /etc/fstab:

/dev/sda4 none swap sw 0 0
/dev/sda5 /mnt/freebsd ufs nofail,ro,ufstype=ufs2 0 0

Notice the nofail similar to failok in FreeBSD.

Share documents

Now that both OS can access each other data, it’s time to see if we can put this to some use. A first thing that you might do is to share some parts of your home directory. Of course this will be read-only.

What I personally do is selecting the OS that I use most frequently. This one contains everything. Then on the other OS, I use symlinks to some part of my home directory. For instance on Linux:

  • /home/user/Music    -> /mnt/freebsd/home/user/Music
  • /home/user/Pictures -> /mnt/freebsd/home/user/Pictures
  • /home/user/Videos   -> /mnt/freebsd/home/user/Videos

Those don’t change that often when I’m on Linux, but I least I got to listen to music, watch movies and can access pictures.

Share ssh keys

If you frequently use ssh to access your laptop or rsync+ssh to sync your documents, you will soon find yourself with ssh complaining that the host key has changed on the same host. Of course FreeBSD and Linux will both have a separate set of ssh host keys. Thankfully we can use the same key on both.

Suppose that we use FreeBSD’s ssh host keys. On Linux, go into /etc/ssh:

# Remove Linux's ssh host keys
rm ssh_host_*key*

# Link FreeBSD's ssh host keys
for key in /mnt/freebsd/etc/ssh/ssh_host_*key*
do
  ln -s "$key"
done

Don’t forget to service ssh restart. Now you can access both Linux and FreeBSD with ssh as if it was the same host (which it is actually).

Share WPA supplicant (WiFi)

Same principle now for WPA supplicant configuration file. However it’s not as simple as it was for ssh. You see, the WPA supplicant configuration needs different options for the control socket on FreeBSD and Linux. Unfortunately, wpa_supplicant.conf does not allow for file include. Actually it should be possible to arrange FreeBSD and Linux so that the same wpa_supplicant.conf is used on both OS. But this option allows for more flexibility. So here is what I do.

First I create /etc/wpa in both FreeBSD and Linux. Then I edit /etc/wpa/local.conf with the wpa_supplicant options specific to this OS. Then I use this small script to select a particular profile and create the appropriate wpa_supplicant.conf.

#!/bin/sh

if [ ! -r "$1" ]
then
  echo "error: cannot read '$1'"
  exit 1
fi

cat /etc/wpa/local.conf > /etc/wpa_supplicant.conf
cat "$1" >> /etc/wpa_supplicant.conf

The idea behind those profiles is to restrict scanning of new networks depending on the situation. For instance you can have one profile for your home, one for your working place, one when you go abroad. It’s easier to organize your configuration that way and also avoids to send probe requests on the air that can disclose information about you.

Thus on FreeBSD, I create /etc/wpa/profiles along with the various profiles and on Linux, I just link to it.

Share nullmailer

If you happen to use nullmailer as your local MTA, you can share your smtp credentials too. But there is a catch. The remotes file in the nullmail configuration must be owned by the nullmailer user/group. This user/group is different on Linux than it is on FreeBSD (nullmail on FreeBSD, mail on Linux). Fortunately when you mount a filesystem, it only cares about the UID/GID, not the actual user/group name. So if we change the UID/GID of the user/group mail to match the UID/GID of the nullmail user/group on FreeBSD, it will appear as the same user but with a different name on each OS. That’s what we’ll do on Linux, we will change the UID/GID of mail to match the one on FreeBSD.

First, let’s list all files owned by user mail:

find / -xdev -user mail > user
find / -xdev -group mail > group

Second, check that we won’t mess around too much by changing these files:

$ cat user group | sort | uniq
/etc/nullmailer/remotes
/usr/bin/dotlockfile
/usr/bin/mailq
/usr/sbin/nullmailer-queue
/var/mail
/var/spool/nullmailer
/var/spool/nullmailer/failed
/var/spool/nullmailer/tmp
/var/spool/nullmailer/trigger

Seems OK. Now let’s find out the UID/GID of the nullmail user group on FreeBSD:

$ cat /mnt/freebsd/etc/passwd | grep nullmail
nullmail:*:522:522:Nullmailer Mail System:/var/spool/nullmailer:/bin/sh
$ cat /mnt/freebsd/etc/group | grep nullmail
nullmail:*:522:

The UID/GID is 522:522 on FreeBSD. We will change user/group mail on Linux to UID/GID 522:

# Stop nullmailer so that we can change the UID/GID
service nullmailer stop

# Change UID/GID
usermod -u 522 mail
groupmod -u 522 mail

# The files are still owned by the old UID/GID.
# We change that
cat user | while read file
do
  chown mail: "$file"
done
cat group | while read file
do
  chown :mail "$file"
done

# Clean
rm user group

Now we link nullmailer configuration into Linux:

rm -rf /etc/nullmailer
ln -s /mnt/freebsd/usr/local/etc/nullmailer /etc/nullmailer

You should be able to service nullmailer restart now.

Dual boot UEFI Linux/FreeBSD

There a lot of tutorials out there explaining how to dual boot Linux and FreeBSD on legacy BIOS but not so much for UEFI only systems. So I will share my experience installing Debian 10.2 and FreeBSD 12.1 on my ThinkPad X250 in UEFI only mode. It should be easy to adapt this to other Linux distributions and other systems than FreeBSD.

This post will be soon followed by another post explaining how FreeBSD and Linux can get along with each other after being installed. But now for the installation.

First ensure in your UEFI/BIOS settings that boot is set to UEFI only and CSM disabled. You don’t want to boot the installer in legacy mode by accident.

We will use a GTP partition table and the create the following partitions:

  1. EFI System Partition (ESP): To store the UEFI bootloaders
  2. SWAP + ext4: For Linux
  3. SWAP + UFS: For FreeBSD

Note that we could technically use the same SWAP for both FreeBSD and Linux. Still I prefer to use 2 SWAP partitions and use both of them in each OS. It’s a matter of preference I guess.

Install Linux and FreeBSD

Install Linux

We start installing Debian so that Linux stays in charge of GRUB. We do so because it’s frequent on Linux to have multiple kernel variants, for instance a more recent version of the kernel, custom or a RT patched kernel. So we let Linux’s package manager handle all of that.

At the partitioning step, select “Manual partitioning” and create a GPT partition table. For UEFI to function properly, we need a EFI System Partition (ESP), 500MB should be more than enough for this. Then a Linux swap partition and a Linux ext4 partition for the data. Leave some space unallocated for FreeBSD.

It is possible to use Linux’s swap partition in FreeBSD. More about that later. For now we will let each OS have its own swap partition.

Complete the Debian installation. It should install grub bootloader in the EFI partition. Check that Debian boots properly. Then start the FreeBSD install.

Install FreeBSD

There used to be a separate installation image for FreeBSD UEFI. This is not the case anymore, so you can use the AMD64 memstick image for 12.1-RELEASE on the FreeBSD download page.

Boot the installer and go ahead up to the partitioning step. Use the space you left unallocated for the freebsd-swap and freebsd-ufs partitions. The installer will complain that an EFI partition is required for the system to work properly and propose to create it. Ignore this as the partition was already created under Linux. It is weird though that the FreeBSD installer does not detect this, but there is a FreeBSD forum post about this issue.

Proceed and complete the FreeBSD installation. Then reboot into Debian to configure the dual boot.

GRUB dual boot

It is now time to tell Linux’s GRUB about our newly installed FreeBSD system.

We created the swap partitions before the data partitions for each OS, so to resume our partition table we now have:

  1. EFI System Partition
  2. Linux SWAP
  3. Linux ext4
  4. FreeBSD SWAP
  5. FreeBSD UFS

So our FreeBSD partition is (hd0, gpt5) in GRUB parlance. You may need to adapt this to your own partition scheme though. Once in Debian as root edit /etc/grub.d/40_custom and after the comment add:


menuentry 'FreeBSD' {
insmod ufs2
set root='(hd0,gpt5)'
chainloader /boot/loader.efi
}

Then update grub with update-grub2, finally reboot and select FreeBSD in the GRUB menu. You can now boot both Linux and FreeBSD.

FreeBSD aware UEFI

It is now possible to boot both Debian and FreeBSD from GRUB. However it is not yet possible to boot FreeBSD directly from UEFI. To do so we need to copy the FreeBSD UEFI loader in to EFI partition and register it. Debian already mounts the EFI partition but FreeBSD doesn’t, so for the fun of it, let’s manage all that under FreeBSD and install the FreeBSD UEFI loader. /dev/ada0p1 is the EFI partition, but you may need to adapt this to your partition scheme though.

# We mount the EFI partition on /boot/efi similarly to Linux.
mkdir /boot/efi
echo '/dev/ada0p1 /boot/efi msdosfs rw,noatime 0 0' >> /etc/fstab
mount /boot/efi

# Install the FreeBSD UEFI loader.
mkdir /boot/efi/EFI/freebsd
cp /boot/boot1.efi /boot/efi/EFI/freebsd/bootx64.efi

Now let’s create an UEFI entry for this loader. Note that this is for FreeBSD’s efibootmgr, not the Linux’s one.

# Create the boot variable.
efibootmgr -c -l /boot/efi/EFI/freebsd/bootx64.efi -L "FreeBSD"

# Check the variable number for the new boot variable and activate it.
efibootmgr
efibootmgr -a 15

# Change the boot order to leave Debian and GRUB in charge.
efibootmgr -o 14,15

Time to reboot! Select the boot menu with (generally with F12, at least on my ThinkPad X250) and FreeBSD should appear. Select it and it should boot FreeBSD directly.

You are done! Next time how to let FreeBSD and Linux talk to each other.

Intel kernel panic

If you recently had your FreeBSD 12.1 running ThinkPad X250 (or any other laptop with a Intel GPU) crashing systematically on boot, it may be because of the i915kms module from the graphics/drm-kmod port. If you did install this or drm-fbsd12.0-kmod through the packages, you should know that the binary package is only compatible with FreeBSD 12.0. If you want this to work (that is, not to cause a kernel panic), you should compile the port manually [1]. In other words:

portsnap fetch update
cd /usr/ports/graphics/drm-fbsd12.0-kmod
make install clean

Drop TCP connections

On FreeBSD you can drop existing TCP connection using the tcpdrop command. For instance you can drop all ESTABLISHED connections using tcpdrop -s ESTABLISHED. Or you can even list them all with:

$ tcpdrop -la
tcpdrop ::1 59298 ::1 1180
tcpdrop 10.0.0.10 59299 163.172.87.245 80
tcpdrop 10.0.0.10 59300 163.172.87.245 22
tcpdrop 10.0.0.10 59301 96.47.72.84 443

Notice the fun thing here. Those are actual commands that you can use to drop the connections. In fact you can use this to filter which connection you want to drop. For example:

# Drop all but SSH connections
tcpdrop -la | grep -vw 22 | sh

# Drop all incoming HTTP connections
tcpdrop -la | grep -v " 80 " | sh

# Drop all connections to a specific IP
tcpdrop -la | grep -vw 8.8.8.8 | sh

This can be useful for instance on a desktop when you just switched interface, or say just started a VPN daemon, and want all prior TCP connections not originating from your new addresses to be killed. Then you would just add those IP you would like to keep and filter them out:

# List of IPs you want to keep
echo 192.168.1.122 > keep-ip.txt
echo 10.0.0.10 >> keep-ip.txt

tcpdrop -la | grep -Ev "(::1|127.0.0.1)" | grep -vwf keep-ip.txt | sh

Automount not working with FreeBSD 12

FreeBSD 12 is out. This is great! However I had the surprise to find that the automount feature didn’t work in KDE, probably also Gnome, XFCE and any other desktop environment that provide such a feature.

The culprit was easy to find, the Hardware Abstraction Layer has not yet updated to the peculiarities of the latest FreeBSD release.

See, when HAL tries to mount a vfat filesystem on FreeBSD, it adds by default the large option which according to FreeBSD 11.2 mount_msdosfs’s manpage provide support for very large files (>128GB). This option, however, was removed in FreeBSD 12. Thus automount fails.

To temporarily fix this, edit /usr/local/share/hal/fdi/policy/10osvendor/20-storage-methods.fdi. Then remove the large option in the vfat match for FreeBSD. That is:

  <match key="volume.fstype" string="vfat">
    <match key="/org/freedesktop/Hal/devices/computer:system.kernel.name" string="Linux">
      ...
  </match>
  <match key="/org/freedesktop/Hal/devices/computer:system.kernel.name" string="FreeBSD">
    ...
    <!-- <append key="volume.mount.valid_options" type="strlist">large</append> -->
  </match>

This was already reported in #221709.

Epson 3490 Scanner

This is an information that tends to be forgotten on the Internet, so I’m publishing it here. How to get an Epson Perfection 3490 Photo scanner running under Linux, FreeBSD or whatever. Paths may change on your system, so you may need to adapt the instructions below.

1. Install xsane.

2. Download the Epson firmwares. For the Epson 3490, you need esfw52.bin. You may find this file on Internet, although it tends to disappear. But in any case you can also find this file here.

3. Uncompress the firmwares. That is, sudo tar -Jxvf epson-firmwares.tar.xz -C /usr/local/share/sane.

4. Modify /usr/local/etc/sane.d/snapscan.conf, change the firmware line to point to the esfw52.bin firmware. That is following the commands above, change the firmware line to firmware /usr/local/share/sane/epson-firmwares/esfw52.bin.

If you are running FreeBSD

You should still ensure that you can use the scanner as a normal user.

5.Let’s change the owner of the scanner so that it’s available to users in the saned group. Create /etc/devd/saned.conf and add:

notify 100 {
  match "system" "USB";
  match "subsystem" "INTERFACE";
  match "type" "ATTACH";
  match "cdev" "ugen[0-9].[0-9]";
  match "vendor" "0x04b8";
  match "product" "0x0122";
  action "chown -L cups:saned /dev/$cdev && chmod -L 660 /dev/$cdev";
};

Notice the 0x4b8:0x0122, identifying the scanner USB device which you can get from the lsusb command while the scanner is plugged in.

6.Restart devd with service devd restart.

7.Add yourself to the saned group with sudo pw groupmod saned -m

8.You may need to log in again so that new group changes are taken into account.

Fastd on FreeBSD

Fastd is nice and small secure tunneling daemon. A bit like OpenVPN, if you wish, but geared toward small devices, simpler in its design and in some ways more generic.

There was a FreeBSD port, but it has been marked as broken. The fix, however, is very simple, if you accept to get rid of AES128 and instead use the SALSA stream cipher:

cmake -DWITH_CIPHER_AES128_CTR=FALSE CMakeLists.txt
make
make install

Chromium on FreeBSD

Good news everyone! Chromium is now perfectly usable on FreeBSD.
The longstanding hanging tab bug has been resolved. See also PR 212812 and this this FreeBSD forum post.

This was fixed in r337328 but is not yet available in 11.2-RELEASE. Fortunately there are temporary fixes too that you can use while waiting for the patch to be included in the next release.

First add this line to /etc/sysctl.conf:

net.local.stream.recvspace=16384

Second use a memory backed filesystem for the chromium cache. A script to do so was included in the chromium package, but it has since been removed now that a proper fix is coming in.

But if you want to do this manually, first ensure that ~/.cache/chromium directory exists and is empty. Then in /etc/fstab add this line with $USER changed accordingly:

md /home/$USER/.cache/chromium mfs rw,late,noatime,noexec,nosuid,-w$USER:$USER,-s300m 2 0

This will mount the chromium cache path on an UFS partition over a memory backed virtual disk.

I’ve been testing this for several days now and it works like a charm. Don’t forget to remove this workaround when you are past r337328 though.

FreeBSD on Intel Broadwell

Around two years ago I posted about using FreeBSD 10 on the X250. A great deal has happened since then.

It is now possible to use the Intel Broadwell integrated graphic card (among others) under FreeBSD-CURRENT FreeBSD-STABLE! Also if I’m right, this will be integrated in FreeBSD 11.2-RELEASE. What a great day it is for FreeBSD on the desktop. I bet FreeBSD 12 will be truly great!

Note that it works much better on STABLE now than CURRENT because CURRENT is -well- not that stable…

So if you want to try this now, what you first need to do is to upgrade to the STABLE branch. For this you need to fetch the source, buildworld, buildkernel and installworld. Here is a very quick tuto (that you may need to adapt though). You can also find this here.


# Don't forget to upgrade RELEASE
# in any case that there were any bugs in the building tools.
freebsd-update fetch
freebsd-update install
reboot
freebsd-update install

# Replace the current source tree with STABLE.
mv /usr/src /usr/src-RELEASE
svn checkout svn://svn.freebsd.org/base/stable/11 /usr/src

# Build! Build! Build!
cd /usr/src
make buildworld -j4

# Customize (while you are at it) and build STABLE kernel.
cd /usr/src/sys/amd64/conf
cp GENERIC {YOUR-CONF}
vim {YOUR-CONF}
cd /usr/src
make buildkernel KERNCONF={YOUR-CONF}
make installkernel KERNCONF={YOUR-CONF}
reboot

# Now it's time to install world over the new kernel.
# In the meantime we also update configuration files
# with mergemaster.
mergemaster -p
cd /usr/src
make installworld
mergemaster -Ui
reboot

Now that your are on the latest STABLE, you can update the ports tree and install drm-next.


# Install ports tree if needed.
portsnap fetch
portsnap extract

# Install drm-next.
cd /usr/ports/graphics/drm-next-kmod
make install clean

Finally you must tell rc.conf to use the new i915 module instead. That is, add in /etc/rc.conf:


kld_list="/boot/modules/i915kms.ko"

Just one final reboot and you are done! Test this with the xorg and mesa-demos ports. Just startx from your user and check /var/log/Xorg.0.log to see if the intel driver was correctly loaded.