5
0
mirror of git://git.proxmox.com/git/proxmox-backup-restore-image.git synced 2025-01-02 05:17:39 +03:00

initial commit

proxmox-restore-vm-data provides means to build a debian package
containing a minimalistic Linux kernel and a corresponding initramfs
image for use in a file-restore VM.

Launched with QEMU/KVM, it boots in 1.6 seconds to userspace (on AMD
2700X) and has a minimal attack surface (no network stack other than
virtio-vsock, no auxiliary device support (USB, etc...), userspace
written in Rust) as opposed to mounting backup archives directly on the
host.

Since our Rust binaries are currently not fully statically linked, we
need to include some libraries into the initramfs as well. This is done
in 'build_initramfs.sh'.

A minimal /init is included as a Rust binary (init-shim-rs), doing only
the bare-minimum userspace setup before handing over control to the
file-restore daemon (see 'proxmox-backup' repository).

The debian package comes with a 'activate-noawait
pbs-file-restore-initramfs' trigger activation to rebuild the cached
initramfs when the base image shipped here updates. This is taken care
of by proxmox-file-restore.

Signed-off-by: Stefan Reiter <s.reiter@proxmox.com>
This commit is contained in:
Stefan Reiter 2021-02-16 18:06:51 +01:00 committed by Thomas Lamprecht
commit 3b259e7a26
19 changed files with 623 additions and 0 deletions

9
.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
build/
init-shim-rs/target/
*.deb
*.dsc
*.buildinfo
*.changes
*.prepared
*.tar.gz

6
.gitmodules vendored Normal file
View File

@ -0,0 +1,6 @@
[submodule "submodules/zfsonlinux"]
path = submodules/zfsonlinux
url = git://git.proxmox.com/git/mirror_zfs.git
[submodule "submodules/ubuntu-hirsute"]
path = submodules/ubuntu-hirsute
url = git://git.proxmox.com/git/mirror_ubuntu-hirsute-kernel.git

103
Makefile Normal file
View File

@ -0,0 +1,103 @@
include /usr/share/dpkg/pkg-info.mk
include /usr/share/dpkg/architecture.mk
PACKAGE=proxmox-restore-vm-data
BUILDDIR=build
INITRAMFS_BUILDDIR=build/initramfs
ZFSONLINUX_SUBMODULE=submodules/zfsonlinux
KERNEL_SUBMODULE=submodules/ubuntu-hirsute
SHIM_DIR=init-shim-rs
KERNEL_IMG=${BUILDDIR}/${KERNEL_SUBMODULE}/arch/x86/boot/bzImage
INITRAMFS_IMG=${INITRAMFS_BUILDDIR}/initramfs.img
CONFIG=config-base
RUST_SRC=$(wildcard ${SHIM_DIR}/**/*.rs) ${SHIM_DIR}/Cargo.toml
DEB=${PACKAGE}_${DEB_VERSION_UPSTREAM_REVISION}_${DEB_BUILD_ARCH}.deb
DSC=${PACKAGE}_${DEB_VERSION_UPSTREAM_REVISION}.dsc
all: deb
submodules.prepared:
git submodule update --init ${KERNEL_SUBMODULE}
git submodule update --init --recursive ${ZFSONLINUX_SUBMODULE}
touch $@
${BUILDDIR}.prepared: submodules.prepared ${CONFIG}
rm -rf ${BUILDDIR}
mkdir -p ${BUILDDIR}
cp -a submodules debian patches ${BUILDDIR}/
cp ${CONFIG} ${BUILDDIR}/${KERNEL_SUBMODULE}
cd ${BUILDDIR}/${KERNEL_SUBMODULE}; \
for p in ../../patches/kernel/*.patch; do \
patch -Np1 < $$p; \
done
touch $@
kernel.prepared: ${BUILDDIR}.prepared
cd ${BUILDDIR}/${KERNEL_SUBMODULE}; \
KCONFIG_ALLCONFIG=${CONFIG} make allnoconfig && \
make -j$(nproc) prepare scripts
touch $@
zfs.prepared: kernel.prepared
cd ${BUILDDIR}/${ZFSONLINUX_SUBMODULE}; \
sh autogen.sh && \
./configure \
--enable-linux-builtin \
--with-linux=../../${KERNEL_SUBMODULE} \
--with-linux-obj=../../${KERNEL_SUBMODULE} && \
./copy-builtin ../../${KERNEL_SUBMODULE}
# only now can we enable CONFIG_ZFS
cd ${BUILDDIR}/${KERNEL_SUBMODULE}; \
./scripts/config -e CONFIG_ZFS
touch $@
${KERNEL_IMG}: zfs.prepared
cd ${BUILDDIR}/${KERNEL_SUBMODULE}; \
make -j$(nproc)
mv ${BUILDDIR}/${KERNEL_SUBMODULE}/arch/x86/boot/bzImage ${BUILDDIR}/
${INITRAMFS_IMG}: ${BUILDDIR}.prepared ${RUST_SRC} build_initramfs.sh
cd ${SHIM_DIR}; cargo build --release
sh build_initramfs.sh
.PHONY: dinstall
dinstall: deb
dpkg -i ${DEB}
.PHONY: deb
deb: ${DEB}
${DEB}: ${KERNEL_IMG} ${INITRAMFS_IMG}
cd ${BUILDDIR}; dpkg-buildpackage -b -us -uc
lintian ${DEB}
.PHONY: dsc
dsc: ${DSC}
${DSC}: ${KERNEL_IMG} ${INITRAMFS_IMG}
cd ${BUILDDIR}; dpkg-buildpackage -S -us -uc -d
lintian ${DSC}
.PHONY: upload
upload: ${DEB}
tar cf - ${DEB} | ssh -X repoman@repo.proxmox.com upload --product pbs --dist buster
tar cf - ${DEB} | ssh -X repoman@repo.proxmox.com upload --product pve --dist buster
.PHONY: test-run
test-run: ${KERNEL_IMG} ${INITRAMFS_IMG}
# note: this will always fail since /proxmox-restore-daemon is not
# included in the initramfs, but it can be used to test the
# kernel/init-shim-rs builds
qemu-system-x86_64 -serial stdio -vnc none -enable-kvm \
-kernel build/${KERNEL_SUBMODULE}/arch/x86/boot/bzImage \
-initrd build/initramfs/initramfs.img
.PHONY: clean
clean:
rm -rf *~ ${BUILDDIR} ${INITRAMFS_BUILDDIR} *.prepared
rm -f ${PACKAGE}_${DEB_VERSION_UPSTREAM_REVISION}.tar.gz
rm -f *.deb *.changes *.buildinfo *.dsc

42
build_initramfs.sh Executable file
View File

@ -0,0 +1,42 @@
#!/bin/sh
set -e
ROOT="root"
BUILDDIR="build/initramfs"
INIT="../../init-shim-rs/target/release/init-shim-rs"
PKGS=" \
libc6:amd64=2.28-10 \
libgcc1:amd64=1:8.3.0-6 \
libstdc++6:amd64=8.3.0-6 \
libssl1.1:amd64=1.1.1d-0+deb10u4 \
libattr1:amd64=1:2.4.48-4 \
libacl1:amd64=2.2.53-4
"
echo "Using build dir: $BUILDDIR"
rm -rf "$BUILDDIR"
mkdir -p "$BUILDDIR"
cd "$BUILDDIR"
mkdir "$ROOT"
# add necessary packages to initramfs
for pkg in $PKGS; do
apt-get download "$pkg"
dpkg-deb -x ./*.deb "$ROOT"
rm ./*.deb
done
rm -rf ${ROOT:?}/usr/share # contains only docs and debian stuff
cp $INIT "$ROOT/init"
chmod a+x "$ROOT/init" # just to be sure
# tell daemon it's running in the correct environment
touch "$ROOT/restore-vm-marker"
fakeroot -- sh -c "
cd '$ROOT';
find . -print0 | cpio --null -oV --format=newc -F ../initramfs.img
"

144
config-base Normal file
View File

@ -0,0 +1,144 @@
CONFIG_LOCALVERSION="-pbs-restore"
# kernel commandline override
CONFIG_CMDLINE_BOOL=y
CONFIG_CMDLINE="console=ttyS0"
# NOTE: ZFS will be enabled from Makefile, since we can only activate it after
# 'copy-builtin' creates the necessary Kconfig in the kernel tree.
# CONFIG_ZFS=y
# in case we crash the kernel, so we can at least read the stacktraces
CONFIG_KALLSYMS=y
# CPU settings
CONFIG_64BIT=y
CONFIG_MMU=y
CONFIG_SMP=y
CONFIG_X86_X2APIC=y
CONFIG_ACPI=y
# not super necessary, but avoids a warning
CONFIG_RETPOLINE=y
# basic kernel features
CONFIG_MULTIUSER=y
CONFIG_POSIX_TIMERS=y
CONFIG_BUG=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_AIO=y
CONFIG_BINFMT_ELF=y
CONFIG_ELFCORE=y
CONFIG_PRINTK=y
CONFIG_EVENTFD=y
CONFIG_MODULES=y
# initramfs support
CONFIG_TMPFS=y
CONFIG_BLK_DEV_INITRD=y
# paravirt acceleration
CONFIG_KVM_GUEST=y
CONFIG_PARAVIRT=y
CONFIG_PARAVIRT_CLOCK=y
CONFIG_PARAVIRT_SPINLOCKS=y
CONFIG_VIRTIO_MENU=y
CONFIG_VIRTIO=y
# enable terminal on serial for debugging/logging
CONFIG_TTY=y
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_INPUT_KEYBOARD=y
# vsock support
CONFIG_PCI=y
CONFIG_NET=y
CONFIG_UNIX=y
CONFIG_VSOCKETS=y
CONFIG_VIRTIO_VSOCKETS=y
CONFIG_VIRTIO_VSOCKETS_COMMON=y
# block device support, especially virtio-scsi/blk
CONFIG_BLOCK=y
CONFIG_BLK_DEV=y
CONFIG_BLK_DEV_SD=y
CONFIG_BLK_DEV_SR=y
CONFIG_VIRT_DRIVERS=y
CONFIG_SCSI=y
CONFIG_SCSI_VIRTIO=y
CONFIG_BLK_MQ_VIRTIO=y
CONFIG_VIRTIO_BLK=y
CONFIG_VIRTIO_MMIO=y
CONFIG_VIRTIO_PCI=y
# md/LVM/device-mapper support
CONFIG_DM_CRYPT=y
CONFIG_DM_MIRROR=y
CONFIG_DM_RAID=y
CONFIG_DM_SNAPSHOT=y
CONFIG_DM_THIN_PROVISIONING=y
CONFIG_DM_UNSTRIPED=y
CONFIG_MD=y
CONFIG_MD_AUTODETECT=y
CONFIG_MD_LINEAR=y
CONFIG_MD_RAID0=y
CONFIG_MD_RAID1=y
CONFIG_MD_RAID10=y
CONFIG_MD_RAID456=y
CONFIG_BLK_DEV_MD=y
CONFIG_BLK_DEV_DM=y
# basic fs features
CONFIG_FS_POSIX_ACL=y
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
CONFIG_PROC_FS=y
# proc_sysctl is necessary for ZFS, it panics otherwise
CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
CONFIG_NLS=y
CONFIG_NLS_UTF8=y
CONFIG_NLS_ISO8859_1=y
CONFIG_MSDOS_PARTITION=y
CONFIG_EFI_PARTITION=y
# filesystem support
CONFIG_MISC_FILESYSTEMS=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT2_FS_POSIX_ACL=y
CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_XATTR=y
CONFIG_EXT3_FS_POSIX_ACL=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_XATTR=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_REISERFS_FS=y
CONFIG_REISERFS_FS_XATTR=y
CONFIG_REISERFS_FS_POSIX_ACL=y
CONFIG_JFS_FS=y
CONFIG_JFS_POSIX_ACL=y
CONFIG_XFS_FS=y
CONFIG_XFS_POSIX_ACL=y
CONFIG_BTRFS_FS=y
CONFIG_BTRFS_FS_POSIX_ACL=y
CONFIG_F2FS_FS=y
CONFIG_F2FS_FS_XATTR=y
CONFIG_F2FS_FS_POSIX_ACL=y
CONFIG_F2FS_FS_COMPRESSION=y
CONFIG_F2FS_FS_LZO=y
CONFIG_F2FS_FS_LZ4=y
CONFIG_F2FS_FS_ZSTD=y
CONFIG_F2FS_FS_LZORLE=y
CONFIG_HFS_FS=y
CONFIG_HFSPLUS_FS=y
CONFIG_BEFS_FS=y
CONFIG_SYSV_FS=y
CONFIG_UFS_FS=y
CONFIG_ISO9660_FS=y
CONFIG_NTFS_FS=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y

6
debian/changelog vendored Normal file
View File

@ -0,0 +1,6 @@
proxmox-restore-vm-data (1.0.0-1) pbs; urgency=medium
* initial release
-- Proxmox Support Team <support@proxmox.com> Tue, 16 Feb 2021 16:49:20 +0100

1
debian/compat vendored Normal file
View File

@ -0,0 +1 @@
10

34
debian/control vendored Normal file
View File

@ -0,0 +1,34 @@
Source: proxmox-restore-vm-data
Section: admin
Priority: optional
Maintainer: Proxmox Support Team <support@proxmox.com>
Build-Depends: asciidoc-base,
automake,
bc,
bison,
cpio,
debhelper (>= 10~),
dh-python,
flex,
gcc (>= 8.3.0-6),
git,
libdw-dev,
libelf-dev,
libtool,
lintian,
perl-modules,
python-minimal,
sed,
sphinx-common,
tar,
xmlto,
zlib1g-dev,
Standards-Version: 4.5.1
Homepage: https://www.proxmox.com
Package: proxmox-restore-vm-data
Architecture: amd64
Recommends: proxmox-file-restore
Description: VM kernel/initramfs images for PBS single file restore
Preconfigured images used as base for single file restore of PBS backup
snapshots. Useless on their own, use together with proxmox-file-restore.

22
debian/copyright vendored Normal file
View File

@ -0,0 +1,22 @@
Copyright (C) 2020 Proxmox Server Solutions GmbH
This package contains a version of a linux kernel binary image (including
patches by Ubuntu/Canonical and Proxmox) with built-in ZFS support.
Linux is copyrighted by Linus Torvalds and others and distributed under the
terms of the GPL-2.0 license.
The complete text of the GNU General Public License can be found in
`/usr/share/common-licenses/GPL-2'.
ZFS is licensed under the Common Development and Distribution License (CDDL).
The shipped initramfs image contains several files from other debian packages.
For their copyright notices see the respective packages in the versions
mentioned in build_initramfs.sh.
The initramfs also contains a rust binary as /init, built from 'init-shim-rs'
available in this package's sources. This binary is released under the terms of
the AGPLv3 by Proxmox Server Solutions GmbH.
This package was put together by Proxmox Server Solutions GmbH
<support@proxmox.com>.

2
debian/install vendored Normal file
View File

@ -0,0 +1,2 @@
bzImage /usr/lib/x86_64-linux-gnu/proxmox-backup/file-restore/
initramfs/initramfs.img /usr/lib/x86_64-linux-gnu/proxmox-backup/file-restore/

13
debian/rules vendored Executable file
View File

@ -0,0 +1,13 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Sample debian/rules that uses debhelper.
# This file was originally written by Joey Hess and Craig Small.
# As a special exception, when this file is copied by dh-make into a
# dh-make output file, you may use that output file without restriction.
# This special exception was added by Craig Small in version 0.37 of dh-make.
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
%:
dh $@

1
debian/triggers vendored Normal file
View File

@ -0,0 +1 @@
activate-noawait pbs-file-restore-initramfs

51
init-shim-rs/Cargo.lock generated Normal file
View File

@ -0,0 +1,51 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "anyhow"
version = "1.0.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf8dcb5b4bbaa28653b647d8c77bd4ed40183b48882e130c1f1ffb73de069fd7"
[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "cc"
version = "1.0.62"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1770ced377336a88a67c473594ccc14eca6f4559217c34f64aac8f83d641b40"
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "init-shim-rs"
version = "1.0.0"
dependencies = [
"anyhow",
"nix",
]
[[package]]
name = "libc"
version = "0.2.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614"
[[package]]
name = "nix"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85db2feff6bf70ebc3a4793191517d5f0331100a2f10f9bf93b5e5214f32b7b7"
dependencies = [
"bitflags",
"cc",
"cfg-if",
"libc",
]

9
init-shim-rs/Cargo.toml Normal file
View File

@ -0,0 +1,9 @@
[package]
name = "init-shim-rs"
version = "1.0.0"
authors = ["Stefan Reiter <s.reiter@proxmox.com>"]
edition = "2018"
[dependencies]
anyhow = "1.0"
nix = "0.19"

122
init-shim-rs/src/main.rs Normal file
View File

@ -0,0 +1,122 @@
use anyhow::Error;
use std::ffi::CStr;
use std::fs;
const URANDOM_MAJ: u64 = 1;
const URANDOM_MIN: u64 = 9;
/// Set up a somewhat normal linux userspace environment before starting the restore daemon, and
/// provide error messages to the user if doing so fails.
///
/// This is supposed to run as /init in an initramfs image.
fn main() {
println!("[init-shim] beginning user space setup");
// /dev is mounted automatically
wrap_err("mount /sys", || do_mount("/sys", "sysfs"));
wrap_err("mount /proc", || do_mount("/proc", "proc"));
// make device nodes required by daemon
wrap_err("mknod /dev/urandom", || {
do_mknod("/dev/urandom", URANDOM_MAJ, URANDOM_MIN)
});
let uptime = read_uptime();
println!("[init-shim] reached daemon start after {:.2}s", uptime);
do_run("/proxmox-restore-daemon");
}
fn do_mount(target: &str, fstype: &str) -> Result<(), Error> {
use nix::mount::{mount, MsFlags};
fs::create_dir(target)?;
let none_type: Option<&CStr> = None;
mount(
none_type,
target,
Some(fstype),
MsFlags::MS_NOSUID | MsFlags::MS_NOEXEC,
none_type,
)?;
Ok(())
}
fn do_mknod(path: &str, maj: u64, min: u64) -> Result<(), Error> {
use nix::sys::stat;
let dev = stat::makedev(maj, min);
stat::mknod(path, stat::SFlag::S_IFCHR, stat::Mode::S_IRWXU, dev)?;
Ok(())
}
fn read_uptime() -> f32 {
let uptime = wrap_err("read /proc/uptime", || {
fs::read_to_string("/proc/uptime").map_err(|e| e.into())
});
// this can never fail on a sane kernel, so just unwrap
uptime
.split_ascii_whitespace()
.next()
.unwrap()
.parse()
.unwrap()
}
fn do_run(cmd: &str) -> ! {
use std::io::ErrorKind;
use std::process::Command;
let spawn_res = Command::new(cmd).env("RUST_BACKTRACE", "1").spawn();
match spawn_res {
Ok(mut child) => {
let res = wrap_err("wait failed", || child.wait().map_err(|e| e.into()));
error(&format!(
"child process {} (pid={} exitcode={}) exited unexpectedly, check log for more info",
cmd,
child.id(),
res.code().unwrap_or(-1),
));
}
Err(err) if err.kind() == ErrorKind::NotFound => {
error(&format!(
concat!(
"{} missing from image.\n",
"This initramfs should only be run with proxmox-file-restore!"
),
cmd
));
}
Err(err) => {
error(&format!(
"unexpected error during start of {}: {}",
cmd, err
));
}
}
}
fn wrap_err<R, F: FnOnce() -> Result<R, Error>>(op: &str, f: F) -> R {
match f() {
Ok(r) => r,
Err(e) => error(&format!("operation '{}' failed: {}", op, e)),
}
}
fn error(msg: &str) -> ! {
use nix::sys::reboot;
println!("\n--------");
println!("ERROR: Init shim failed\n");
println!("{}", msg);
println!("--------\n");
// in case a fatal error occurs we shut down the VM, there's no sense in continuing and this
// will certainly alert whoever started us up in the first place
let err = reboot::reboot(reboot::RebootMode::RB_POWER_OFF).unwrap_err();
println!("'reboot' syscall failed: {} - cannot continue", err);
// in case 'reboot' fails just loop forever
loop {
std::thread::sleep(std::time::Duration::from_secs(600));
}
}

View File

@ -0,0 +1,30 @@
From 4cf77185b43a29ad2d70749648cac83330030cf9 Mon Sep 17 00:00:00 2001
From: Stefan Reiter <s.reiter@proxmox.com>
Date: Tue, 17 Nov 2020 14:42:52 +0100
Subject: [PATCH] OVERRIDE: do not build xr-usb-serial
We don't have USB support in the kernel, so this will fail - and for
some reason there's no Kconfig setting for this...
Signed-off-by: Stefan Reiter <s.reiter@proxmox.com>
---
ubuntu/Makefile | 3 ---
1 file changed, 3 deletions(-)
diff --git a/ubuntu/Makefile b/ubuntu/Makefile
index 67c6d5b98b53..6e7264845b66 100644
--- a/ubuntu/Makefile
+++ b/ubuntu/Makefile
@@ -19,9 +19,6 @@ obj-$(CONFIG_HIO) += hio/
##
##
##
-ifeq ($(ARCH),x86)
-obj-y += xr-usb-serial/
-endif
##
##
##
--
2.20.1

View File

@ -0,0 +1,26 @@
From 2c972569ef5b641846773bee3b3a0191ba66165e Mon Sep 17 00:00:00 2001
From: Stefan Reiter <s.reiter@proxmox.com>
Date: Tue, 16 Feb 2021 17:14:41 +0100
Subject: [PATCH] FIXUP: syntax error in Ubuntu Sauce
Signed-off-by: Stefan Reiter <s.reiter@proxmox.com>
---
include/linux/audit.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 55cc03c1bed8..8f84c9503827 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -253,7 +253,7 @@ static inline void audit_log_path_denied(int type, const char *operation)
static inline void audit_log_lsm(struct lsmblob *blob, bool exiting)
{ }
static inline int audit_log_task_context(struct audit_buffer *ab,
- struct lsmblob *blob);
+ struct lsmblob *blob)
{
return 0;
}
--
2.20.1

@ -0,0 +1 @@
Subproject commit 01f2ad60c19fc07666c3cad5e6f527bc46af6303

1
submodules/zfsonlinux Submodule

@ -0,0 +1 @@
Subproject commit 9f5f86626620c52ad1bebf27d17cece6a28d39a0