Table of Contents

OS - BSD - OpenBSD - binpatch

Maurice Janssen - Binary Updates for OpenBSD maintains an FTP-server with stable (release) builds of a number of recent OpenBSD releases.
binpatchng is based on binpatch but can package binpatches so that they can be installed/removed with the native OpenBSD pkg_* tools.

What is binpatch for OpenBSD?

OpenBSD doesn't have update packages. To apply the patches from OpenBSD errata you need to do the following:

  1. Make sure that the compiler set is installed on the server.
  2. Download the sourcecode for the system and extract it.
  3. Download the errata patches and apply these to the extracted sourcecode.
  4. Compile the patched sourcecode and install the modified binaries.

This process wil need to be repeated on each OpenBSD server, unless you upgrade to a new release or build your own install set from patched sourcecode and use this to upgrade.

Binpatch was created by Gerardo Santana to offer another option. With binpatch you only have to compile the patched sourcecode on one system (per architecture) and add the modified files to a binpatch archive ready to be extracted on other systems that need the patch.

Binpatch creates a fake install directory and extracts the complete system with sourcecode to it. A Makefile is used to apply the patches to the fake install directory and monitor changed files to add to a binpatch archive.

Random observation: If after editing Makefile you run into the error ““Makefile”, line 55: Missing dependency operator” check if there are no spaces in the file where they should not be.

Creating a binpatch computer

Download binpatch.
If you don't have the official OpenBSD CD set, download src.tar.gz and sys.tar.gz from one of the OpenBSD HTTP/FTP mirrors.

Install OpenBSD on a machine.

Example disk layout for a VMware Workstation virtual machine with a 16 GB VMDK:

a150M/
b512Mswap
d4G/usr
e6G/var
f4G/tmp
g1,3G/home

Create work directories

Execute the following commands to create the first few directories for binpatch:

mkdir -p /var/binpatch/distfiles/`uname -m`
mkdir /var/binpatch/patches

Mount the correct CD for the architecture and copy the distfiles to the binpatch environment:

mount /dev/cd0a /mnt
cp /mnt/`uname -r`/`uname -m`/* /var/binpatch/distfiles/`uname -m`/
umount /dev/cd0a

Mount the sparc64 CD (CD 3) and copy the compressed sourcetree:

mount /dev/cd0a /mnt
cp /mnt/src.tar.gz /var/binpatch/distfiles
umount /dev/cd0a

If you don't have CD 3, download the correct version of src.tar.gz and sys.tar.gz from one of the OpenBSD FTP mirrors and place this in /var/binpatch/distfiles. The src.tar.gz on CD 3 of an OpenBSD CD set also contains the contents of sys.tar.gz.

Place x.x.tar.gz in /var/binpatch/patches.
Extract the patches:

cd /var/binpatch/patches
ftp ftp://ftp.openbsd.org/pub/OpenBSD/patches/`uname -r`.tar.gz
tar xvzf `uname -r`.tar.gz

Move the directories below /var/binpatch/patches/x.x/ to /var/binpatch/patches/:

mv /var/binpatch/patches/`uname -r`/* /var/binpatch/patches/

Place binpatch-1.1.0.tar.gz in /var/binpatch, extract the file and move binpatch-1.1.0/* to /var/binpatch:

cd /var/binpatch
tar xvzf binpatch-1.1.0.tar.gz
mv binpatch-1.1.0/* .

Apply the following patch to bsd.binpatch.mk to handle:

--- bsd.binpatch.mk.original	Thu May 22 00:02:11 2008
+++ bsd.binpatch.mk	Sun Mar  1 11:59:39 2015
@@ -49,6 +49,9 @@
 # Defaults to $ARCH
 DISTSUBDIR?=${ARCH}
 
+# Wether to fetch signed patches
+PATCH_SIGNED?=".sig"
+
 # FETCH program
 FETCH=ftp
 
@@ -56,6 +59,9 @@
 MASTER_SITE_OPENBSD?=ftp://ftp.openbsd.org/pub
 MASTER_SITE_SUBDIR?=OpenBSD/patches/${OSREV}
 
+# Used for building set names
+_OSREV=${OSREV:S/.//g}
+
 # The working directories. All of them will be created, and removed.
 WRKDIR?=${.CURDIR}/work-${DISTNAME}
 WRKSRC?=${WRKDIR}/src
@@ -88,16 +94,20 @@
 	${MAKE_ENV} make depend && \
 	${MAKE_ENV} make && \
 	if [ ${_kern} = "GENERIC" ]; then \
-	cp -p bsd ${WRKINST}; \
+		cp -p bsd ${WRKINST}; \
+		chmod -x ${WRKINST}/bsd; \
 	elif [ ${_kern} = "GENERIC.MP" ]; then \
-	cp -p bsd ${WRKINST}/bsd.mp; \
+		cp -p bsd ${WRKINST}/bsd.mp; \
+		chmod -x ${WRKINST}/bsd.mp; \
 	else \
-	cp -p bsd ${WRKINST}/bsd.${_kern}; \
+		cp -p bsd ${WRKINST}/bsd.${_kern}; \
+		chmod -x ${WRKINST}/bsd.${_kern}; \
 	fi
 .endfor
 
 # Shortcuts
 _obj=${MAKE_ENV} make obj
+_clean=${MAKE_ENV} make clean
 _cleandir=${MAKE_ENV} make cleandir
 _depend=${MAKE_ENV} make depend
 _includes=${MAKE_ENV} make includes
@@ -142,15 +153,26 @@
 
 # Fetches the patch file
 ${PATCH_FILE_${_number}}:
-	@echo ">> ${.TARGET:T} doesn't seem to exist on this system."
-	@mkdir -p ${.TARGET:H}
-	@cd  ${.TARGET:H} && \
-	for site in ${MASTER_SITE_OPENBSD}; do \
-	echo ">> Attempting to fetch ${.TARGET} from $${site}/${MASTER_SITE_SUBDIR}/"; \
-	if ${FETCH} $${site}/${MASTER_SITE_SUBDIR}/${.TARGET:S@${PATCHDIR}/@@}; then \
-		exit 0; \
-	fi; \
-	done; exit 1
+	@if [ ! -f "${.TARGET}" ]; then \
+		echo ">> ${.TARGET:T} doesn't seem to exist on this system."; \
+		if [ -f "${PATCH_FILE_${_number}}${PATCH_SIGNED}" ]; then \
+			echo ">> ${.TARGET:T}${PATCH_SIGNED} does seem to exist on this system. Using that file."; \
+			if signify -Vep /etc/signify/openbsd-${_OSREV}-base.pub -x ${.TARGET}${PATCH_SIGNED} -m ${.TARGET}; then \
+				exit 0; \
+			fi; \
+		else \
+			mkdir -p ${.TARGET:H}; \
+			cd  ${.TARGET:H} && \
+			for site in ${MASTER_SITE_OPENBSD}; do \
+				echo ">> Attempting to fetch ${.TARGET}${PATCH_SIGNED} from $${site}/${MASTER_SITE_SUBDIR}/"; \
+				if ${FETCH} $${site}/${MASTER_SITE_SUBDIR}/${.TARGET:S@${PATCHDIR}/@@}${PATCH_SIGNED}; then \
+					if signify -Vep /etc/signify/openbsd-${_OSREV}-base.pub -x ${.TARGET:T}${PATCH_SIGNED} -m ${.TARGET:T}; then \
+						exit 0; \
+					fi; \
+				fi; \
+			done; \
+		fi; \
+	fi; exit 1
 
 PATCH_COOKIE_${_number}:=${WRKDIR}/.${_patch}-applied
 
@@ -218,7 +240,7 @@
 	@echo "===>   Creating fake install tree"
 	rm -rf ${WRKINST}
 	mkdir -p ${WRKINST}
-.for _pkg in base comp etc game man misc
+.for _pkg in base comp etc game man
 	tar xzpf ${DISTDIR}/${ARCH}/${_pkg}${OSrev}.tgz -C ${WRKINST}
 .endfor
 	cp -p ${DISTDIR}/${ARCH}/bsd ${WRKINST} && \

Modify the Makefile

Copy Makefile.sample to /var/binpatch/Makefile:

cp Makefile.sample Makefile

Use the more or similar command to look at the first few lines of each patch to figure out the steps needed to apply and compile the fix. You'll need this to create the Makefile for binpatch.

Open /var/binpatch/Makefile in a text editor.

Change the line:

PATCH_COMMON=001_cvs 002_getsockopt 003_sudo 004_libz 005_libz 006_nat-t

To the list of patches for the OpenBSD version you are running. Here is an example for OpenBSD 4.2:

PATCH_COMMON=001_dhcpd 002_openssl 004_pf 005_ifrtlabel 007_tcprespond 008_ip6rthdr 010_openssh 011_openssh2

Change the last part so the necessary steps to compile the different patches are present, use the information from the .patch files and the “documentation” in Makefile to do this. Here is an example for OpenBSD 4.2:

004_pf: _kernel
005_ifrtlabel: _kernel
007_tcprespond: _kernel
008_ip6rthdr: _kernel

001_dhcpd:
  cd ${WRKSRC}/usr.sbin/dhcpd && \
  (${_obj}; ${_cleandir}; ${_depend}; ${_build})

002_openssl:
  cd ${WRKSRC}/lib/libssl && \
  (${_obj}; ${_depend}; ${_build})

009_ppp:
  cd ${WRKSRC}/usr.sbin/ppp && \
  (${_obj}; ${_depend}; ${_build})

.include "bsd.binpatch.mk"

Multiple 'make directories' for one patch

The 012_openssl.patch for OpenBSD 4.4 indicated that make should be run in two separate directories:

This is version 2 of this patch.

Apply by doing:
        cd /usr/src
        patch -p0 < 012_openssl.patch

And then rebuild and install the library and statically-linked binaries
that depend upon it:

        cd lib/libssl
        make depend
        make includes
        make
        make install
        cd ../../sbin
        make obj
        make depend
        make
        make install

The extra 'cd' can be added to the Makefile as follows:

012_openssl:
	cd ${WRKSRC}/lib/libssl && \
	(${_depend}; ${_includes}; ${_build}; \
	cd ${WRKSRC}/sbin; ${_obj}; ${_depend}; ${_build})

For this example it will appear at compile time that all programs from /sbin will be added to the patch, but the resulting binpatch PLIST only contains the following files:

./usr/lib/libcrypto.so.14.0
./usr/lib/libcrypto.a
./usr/lib/libcrypto_p.a
./usr/lib/libcrypto_pic.a
./usr/lib/libssl.a
./usr/lib/libssl_p.a
./usr/lib/libssl_pic.a
./usr/include/openssl/asn1.h
./sbin/isakmpd
./sbin/mount_vnd
./sbin/pfctl
./sbin/vnconfig

Prepare workingdirectories

If you copied src.tar.gz from CD3 of the official OpenBSD release set, you can indicate to binpatch 1.1.0 that it won't need a separate sys.tar.gz for the make extract command with the following command:

export env CDSRC=""

The following commands need to be executed before you can compile patches:

cd /var/binpatch
make init
make extract

Make init creates the fake directory structure and extracts the archives from /var/binpatch/distfiles/arch/ to it.
Make extract extracts the sourcecode archives.

Multiple kernels

After the above steps you have an environment in which you can create binpatches.
By default building the kernel will only be done for the GENERIC uniprocessor kernel and not the GENERIC.MP multiprocessor or other kernels.
If you also want to make patches for the GENERIC.MP or other kernels you can modify the Makefile by adding the kernel names that you want to build instead of or in addition to GENERIC, by adding:

KERNEL=GENERIC GENERIC.MP

Apply patches and create packages

For each patch a set of commands have to be executed to get a package.
Replace 00x in the examples below with the number of the patch that you are building. Make sure you apply patches in the order indicated by its number!

Apply the patch to the sourcecode:

make PATCH=00x patch

Build the patched sourcecode:

make PATCH=00x build

Create the PLIST file with the files that will be added to the binpatch archive:

make PATCH=00x plist

View the contents of the PLIST file to check if it contains the correct files:

cat pkg/PLIST-i386-00x

Create the binpatch package:

make PATCH=00x package

The following message appears:

+-------------------------
|
| The binary patch has been created in
| /var/binpatch/packages
|
| To install it run make install or:
|
| # cd /var/binpatch/packages
| # tar xzpf binpatch-4.2-i386-001.tgz -C /
|
+-------------------------

Repeat the above steps for each patch.

Change to the packages directory after you have created all the binpatch archives:

cd /var/binpatch/packages

Create an SHA512 checksum file in /var/binpatch to distribute together with the binpatch archives:

cksum -a sha512 * > ../checksums

Check the SHA512 checksums with:

cksum -c ../checksums

Copy the binpatch archive for each patch to the servers that need them and extract the archives to the root of the filesystem with:

mkdir /var/binpatch
export PVER=00x && tar xvzpf binpatch-`uname -r`-`uname -m`-$PVER.tgz -C / && touch /var/binpatch/.$PVER-applied

If you built multiple kernel patches then extracting the very last one is sufficient.
When in doubt, just extract the patches in the order indicated by its number. (001 first, 002 second, etc.)