summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorajacoutot <ajacoutot@openbsd.org>2016-09-05 11:04:45 +0000
committerajacoutot <ajacoutot@openbsd.org>2016-09-05 11:04:45 +0000
commitcb6f7b6fe9a6fa7d5370ea9b77b8c9846086a8a5 (patch)
treed999269c573b83f6b0b5e99053e992bb950d3641
parentI was bound to forget some files ... (diff)
downloadwireguard-openbsd-cb6f7b6fe9a6fa7d5370ea9b77b8c9846086a8a5.tar.xz
wireguard-openbsd-cb6f7b6fe9a6fa7d5370ea9b77b8c9846086a8a5.zip
Welcome syspatch(8), a binary patch management utility for the base system.
This is currently a POC, maybe it will become something, maybe not. Therefore it will not be hooked to the build before we are happy with it. Workflow would be something like: - fetch and verify signed tarballs containing the patched binaries from a mirror - create a rollback tarball of the files we are about to replace - extract and install the patched files *** BIG FAT RED DISCLAIMER *** This is very much WIP, it does *NOT* work, don't bikeshed, don't use it! "get it in" deraadt@
-rw-r--r--usr.sbin/syspatch/Makefile11
-rw-r--r--usr.sbin/syspatch/syspatch.837
-rw-r--r--usr.sbin/syspatch/syspatch.sh276
3 files changed, 324 insertions, 0 deletions
diff --git a/usr.sbin/syspatch/Makefile b/usr.sbin/syspatch/Makefile
new file mode 100644
index 00000000000..216c8063525
--- /dev/null
+++ b/usr.sbin/syspatch/Makefile
@@ -0,0 +1,11 @@
+# $OpenBSD: Makefile,v 1.1 2016/09/05 11:04:45 ajacoutot Exp $
+
+MAN= syspatch.8
+
+SCRIPT= syspatch.sh
+
+realinstall:
+ ${INSTALL} ${INSTALL_COPY} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${.CURDIR}/${SCRIPT} ${DESTDIR}${BINDIR}/syspatch
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/syspatch/syspatch.8 b/usr.sbin/syspatch/syspatch.8
new file mode 100644
index 00000000000..7fe7e8b6af3
--- /dev/null
+++ b/usr.sbin/syspatch/syspatch.8
@@ -0,0 +1,37 @@
+.\" $OpenBSD: syspatch.8,v 1.1 2016/09/05 11:04:45 ajacoutot Exp $
+.\"
+.\" Copyright (c) 2016 Antoine Jacoutot <ajacoutot@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: September 5 2016 $
+.Dt SYSPATCH 8
+.Os
+.Sh NAME
+.Nm syspatch
+.Nd manage binary patches
+.Sh SYNOPSIS
+.Nm syspatch
+.Op Fl c | l | r Ar patchname
+.Sh DESCRIPTION
+notyet
+.Sh SEE ALSO
+.Xr release 8
+.Sh HISTORY
+.Nm
+first appeared in
+.Ox 6.1 .
+.Sh AUTHORS
+.Nm
+was written by
+.An Antoine Jacoutot Aq Mt ajacoutot@openbsd.org .
diff --git a/usr.sbin/syspatch/syspatch.sh b/usr.sbin/syspatch/syspatch.sh
new file mode 100644
index 00000000000..be7c9115f36
--- /dev/null
+++ b/usr.sbin/syspatch/syspatch.sh
@@ -0,0 +1,276 @@
+#!/bin/ksh
+#
+# $OpenBSD: syspatch.sh,v 1.1 2016/09/05 11:04:45 ajacoutot Exp $
+#
+# Copyright (c) 2016 Antoine Jacoutot <ajacoutot@openbsd.org>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+trap "syspatch_trap" 2 3 9 13 15 ERR
+
+set -e
+
+usage()
+{
+ echo "usage: ${0##*/} [-c | -l | -r patchname ]" >&2 && return 1
+}
+
+needs_root()
+{
+ [[ $(id -u) -eq 0 ]] || \
+ (echo "${0##*/}: need root privileges"; return 1)
+}
+
+syspatch_sort()
+{
+ local _p _patch _patches=$(</dev/stdin)
+ [[ -n ${_patches} ]] || return 0 # nothing to do
+
+ for _patch in ${_patches}; do
+ echo ${_patch##*_}
+ done | sort -u | while read _p; do
+ echo "${_patches}" | \
+ grep -E "syspatch-${_RELINT}-[0-9]{3}_${_p}" | \
+ sort -V | tail -1
+ done
+}
+
+syspatch_trap()
+{
+ rm -rf ${_TMP}
+ exit 1
+}
+
+apply_patches()
+{
+ # XXX cleanup mismatch/old rollback patches and sig (installer should as well)
+ local _patch _patches="$@"
+ [[ -n ${_patches} ]] || return 0 # nothing to do
+
+ install -d -m 0755 /var/syspatch/${_REL}
+
+ for _patch in ${_patches}; do
+ fetch_and_verify "${_patch}" || return
+ install_patch "${_patch}" || return
+ done
+
+ # XXX needed? -- non-fatal
+ mtree -qdef /etc/mtree/4.4BSD.dist -p / -U >/dev/null || true
+ mtree -qdef /etc/mtree/BSD.x11.dist -p / -U >/dev/null || true
+}
+
+create_rollback()
+{
+ local _patch=$1 _type
+ [[ -n ${_patch} ]]
+ shift
+ local _files="${@}"
+ [[ -n ${_files} ]]
+
+ _type=$(tar -tzf ${_TMP}/${_patch}.tgz bsd 2>/dev/null || echo userland)
+
+ _files="$(echo ${_files} \
+ | sed "s|var/syspatch/${_REL}/${_patch#syspatch-60-}.patch.sig||g")"
+
+ (cd / && \
+ if [[ ${_type} == bsd ]]; then
+ # XXX bsd.mp created twice in the tarball
+ if ${_BSDMP}; then
+ tar -czf /var/syspatch/${_REL}/rollback-${_patch}.tgz \
+ -s '/^bsd$/bsd.mp/' -s '/^bsd.sp$/bsd/' \
+ ${_files} bsd.sp 2>/dev/null || return # no /bsd.mp
+ else
+ tar -czf /var/syspatch/${_REL}/rollback-${_patch}.tgz \
+ ${_files} || return
+ fi
+ else
+ tar -czf /var/syspatch/${_REL}/rollback-${_patch}.tgz \
+ ${_files} || return
+ fi
+ )
+}
+
+fetch_and_verify()
+{
+ # XXX privsep ala installer
+ local _patch="$@"
+ [[ -n ${_patch} ]]
+
+ local _key="/etc/signify/openbsd-${_RELINT}-syspatch.pub" _p
+
+ ${_FETCH} -o "${_TMP}/SHA256.sig" "${PATCH_PATH}/SHA256.sig"
+
+ for _p in ${_patch}; do
+ _p=${_p}.tgz
+ ${_FETCH} -mD "Get/Verify" -o "${_TMP}/${_p}" \
+ "${PATCH_PATH}/${_p}"
+ (cd ${_TMP} && /usr/bin/signify -qC -p ${_key} -x SHA256.sig ${_p})
+ done
+}
+
+install_file()
+{
+ # XXX handle sym/hardlinks?
+ # XXX handle dir becoming file and vice-versa?
+ local _src=$1 _dst=$2
+ [[ -f ${_src} && -f ${_dst} ]]
+
+ local _fmode _fown _fgrp
+ eval $(stat -f "_fmode=%OMp%OLp _fown=%Su _fgrp=%Sg" \
+ ${_src})
+
+ install -DFS -m ${_fmode} -o ${_fown} -g ${_fgrp} \
+ ${_src} ${_dst}
+}
+
+install_kernel()
+{
+ local _backup=false _bsd=/bsd _kern=$1
+ [[ -n ${_kern} ]]
+
+ # we only save the original release kernel once
+ [[ -f /bsd.rollback${_RELINT} ]] || _backup=true
+
+ if ${_BSDMP}; then
+ [[ ${_kern##*/} == bsd ]] && _bsd=/bsd.sp
+ fi
+
+ if ${_backup}; then
+ install -FSp /bsd /bsd.rollback${_RELINT} || return
+ fi
+
+ if [[ -n ${_bsd} ]]; then
+ install -FS ${_kern} ${_bsd} || return
+ fi
+}
+
+install_patch()
+{
+ local _explodir _file _files _patch="$1"
+ [[ -n ${_patch} ]]
+
+ local _explodir=${_TMP}/${_patch}
+ mkdir -p ${_explodir}
+
+ _files="$(tar xvzphf ${_TMP}/${_patch}.tgz -C ${_explodir})"
+ create_rollback ${_patch} "${_files}"
+
+ for _file in ${_files}; do
+ # can't rely on _type, we need to install 001_foo.patch.sig
+ if [[ ${_file} == @(bsd|bsd.mp) ]]; then
+ if ! install_kernel ${_explodir}/${_file}; then
+ rollback_patch ${_patch}
+ return 1
+ fi
+ else
+ if ! install_file ${_explodir}/${_file} /${_file}; then
+ rollback_patch ${_patch}
+ return 1
+ fi
+ fi
+ done
+}
+
+ls_avail()
+{
+ ${_FETCH} -o - "${PATCH_PATH}/index.txt" | sed 's/^.* //;s/^M//;s/.tgz$//' | \
+ grep "^syspatch-${_RELINT}-.*$" | sort -V
+}
+
+ls_installed()
+{
+ local _p
+ cd /var/syspatch/${_REL} && set -- *
+ for _p; do
+ [[ ${_p} = rollback-syspatch-${_RELINT}-*.tgz ]] && \
+ _p=${_p#rollback-} && echo ${_p%.tgz}
+ done | sort -V
+}
+
+ls_missing()
+{
+ local _a _installed
+ _installed="$(ls_installed)"
+
+ for _a in $(ls_avail); do
+ if [[ -n ${_installed} ]]; then
+ echo ${_a} | grep -qw -- "${_installed}" || echo ${_a}
+ else
+ echo ${_a}
+ fi
+ done
+}
+
+rollback_patch()
+{
+ local _explodir _file _files _patch=$1 _type
+ [[ -n ${_patch} ]]
+
+ _type=$(tar -tzf /var/syspatch/${_REL}/rollback-${_patch}.tgz bsd \
+ 2>/dev/null || echo userland)
+
+ # make sure the syspatch is installed and is the latest version
+ echo ${_patch} | grep -qw -- "$(ls_installed | syspatch_sort)"
+
+ _explodir=${_TMP}/rollback-${_patch}
+ mkdir -p ${_explodir}
+
+ _files="$(tar xvzphf /var/syspatch/${_REL}/rollback-${_patch}.tgz -C ${_explodir})"
+ for _file in ${_files}; do
+ if [[ ${_type} == bsd ]]; then
+ install_kernel ${_explodir}/${_file} || return
+ else
+ install_file ${_explodir}/${_file} /${_file} || return
+ fi
+ done
+
+ rm /var/syspatch/${_REL}/rollback-${_patch}.tgz \
+ /var/syspatch/${_REL}/${_patch#syspatch-${_RELINT}-}.patch.sig
+}
+
+# we do not run on current
+set -A _KERNV -- $(sysctl -n kern.version | \
+ sed 's/^OpenBSD \([0-9]\.[0-9]\)\([^ ]*\).*/\1 \2/;q')
+[[ -z ${_KERNV[1]} ]] || [[ ${_KERNV[1]} == "-stable" ]]
+
+# check unallowed args (-ab, -a foo -b, -a -b)
+[[ -z $@ || \
+ $@ == @(|-[[:alnum:]]@(|+([[:blank:]])[!-]*([![:blank:]])))*([[:blank:]]) ]] || \
+ usage
+
+# XXX to be discussed
+[[ -n ${PATCH_PATH} ]]
+[[ -d ${PATCH_PATH} ]] && PATCH_PATH="file://$(readlink -f ${PATCH_PATH})"
+
+_FETCH="/usr/bin/ftp -MV -k ${FTP_KEEPALIVE-0}"
+_REL=${_KERNV[0]}
+_RELINT=${_REL%\.*}${_REL#*\.}
+_TMP=$(mktemp -d -p /tmp syspatch.XXXXXXXXXX)
+[[ $(sysctl -n hw.ncpu) -gt 1 ]] && _BSDMP=true || _BSDMP=false
+
+while getopts clr: arg; do
+ case ${arg} in
+ c) ls_missing;;
+ l) ls_installed;;
+ r) needs_root && rollback_patch "${OPTARG}";;
+ *) usage;;
+ esac
+done
+shift $(( OPTIND -1 ))
+[[ $# -ne 0 ]] && usage
+
+if [[ ${OPTIND} == 1 ]]; then
+ needs_root && apply_patches $(ls_missing)
+fi
+
+rm -rf ${_TMP}