Skip to content

Commit

Permalink
Add tool to adjust partition tables when sector size changes
Browse files Browse the repository at this point in the history
This includes a C program that adjusts partition tables when the device
sector size changes.  It is intended to be secure against malicious
inputs, although it will not be used with untrusted inputs in Qubes OS.
In particular, all calculations are done with sufficiently wide integer
types to prevent overflow or wraparound, partition tables read from disk
are strictly validated before use, and the total size of the partition
table entries is limited to 1MiB.

The partition table adjustment does not change the start or end of any
partition.  If the old sector size is 512 and the new size is 4096, the
tool will return an error if any partition does not start or end on a
4096-byte boundary.  Furthermore, this tool will refuse to write a
partition table if either the primary or backup GPT would overwrite data
that is part of any partition.  This ensures that user data is not
corrupted.  All used entries in the original GPT are preserved.
However, unused entries will be truncated if necessary.

The FirstUsableLBA and LastUsableLBA fields are converted if necessary,
and are rounded in the direction of _less_ usable space.  This means
that FirstUsableLBA is rounded up, while LastUsableLBA is rounded down.
If the new primary GPT uses space after FirstUsableLBA, or the new
backup GPT uses space before LastUsableLBA, the values of these fields
are adjusted accordingly.

The new partition tables are written in a crash-safe way.  This ensures
that in the event of a system crash or power loss, there is always a
valid GPT that can be used.  The specific algorithm used is as follows:

1. If the GPT being written is the primary GPT, start by writing the
   pMBR, followed by (new sector size - 512) bytes of zeroes.
2. If the new sector size is 512, overwrite the old 512-byte-sector GPT
   header with zeroes, then overwrite the old 4096-byte-sector GPT
   header with zeroes.
3. Write the partition entries.
4. Write the new partition header.

All writes are made with O_SYNC, so they cannot be reordered on-disk.
Furthermore, overwriting a single sector is atomic.  If the primary GPT
was valid, the backup GPT is written first; otherwise, the primary GPT
is written first.

The default CFLAGS enable sanitizers and are intended for local
development only.  Production builds should set CFLAGS via the 'make'
command line or an environment variable, which will override the CFLAGS
in the Makefile.

The tool will exit with a failure status if file descriptor 0, 1, or 2
is closed when it is invoked.  Using these FDs could potentially cause
the device to get clobbered or read from accidentally, which would be
bad.

The block device is opened exclusively to prevent racing with other code
that will use the device.  It is fsync()d before being used to ensure
that the code operates on the most recent on-disk state, not on stale
state cached in memory.  The whole block device is locked exclusively to
avoid racing with udev.  If the user passes a partition, the tool exits
with an error.

A BIOS Parameter Block (BPB) is checked for, to avoid accidentally
corrupting a FAT or NTFS file system that happens to have a GPT with
valid checksums at the wrong location.
  • Loading branch information
DemiMarie committed Dec 8, 2024
1 parent 7e2d762 commit f0c98fd
Show file tree
Hide file tree
Showing 9 changed files with 1,107 additions and 8 deletions.
6 changes: 0 additions & 6 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,6 @@ checks:tests:
tags:
- docker
include:
- file: /r4.1/gitlab-base.yml
project: QubesOS/qubes-continuous-integration
- file: /r4.1/gitlab-dom0.yml
project: QubesOS/qubes-continuous-integration
- file: /r4.1/gitlab-vm.yml
project: QubesOS/qubes-continuous-integration
- file: /r4.2/gitlab-base.yml
project: QubesOS/qubes-continuous-integration
- file: /r4.2/gitlab-host.yml
Expand Down
11 changes: 11 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
SBINDIR ?= /usr/sbin
LIBDIR ?= /usr/lib64
SCRIPTSDIR ?= /usr/lib/qubes
SYSLIBDIR ?= /usr/lib
INCLUDEDIR ?= /usr/include
CFLAGS ?= -Wall -Wextra -Werror -O3 -g3 -Werror=format=2
CC ?= gcc

export LIBDIR SCRIPTSDIR SYSLIBDIR INCLUDEDIR
.PHONY: all selinux install install-selinux install-fedora-kernel-support install-debian-kernel-support clean
Expand Down Expand Up @@ -35,6 +38,14 @@ install-debian-kernel-support:
$(MAKE) -C dracut install
$(MAKE) -C grub install-debian

install-gptfix: gptfixer/gpt
install -D gptfixer/gpt $(DESTDIR)$(SBINDIR)/gptfix
gptfixer/gpt_LDLIBS := -lz
gptfixer/gpt_CFLAGS := -D_GNU_SOURCE -fno-strict-aliasing -fno-delete-null-pointer-checks -fno-strict-overflow
%: %.c Makefile
$(CC) $($(@)_CFLAGS) -o $@ $< $(CFLAGS) -MD -MP -MF $@.dep $($(@)_LDLIBS)
-include gptfixer/*.dep

clean:
$(MAKE) -C qrexec-lib clean
$(MAKE) -C qmemman clean
Expand Down
1 change: 1 addition & 0 deletions archlinux/PKGBUILD.in
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,5 @@ package_qubes-vm-kernel-support() {
install -m 611 "${srcdir}/${_pkgnvr}/archlinux/PKGBUILD-initcpio-hook.sh" "${pkgdir}/usr/lib/initcpio/hooks/qubes"
install -m 755 "${srcdir}/${_pkgnvr}/dracut/full-dmroot/qubes_cow_setup.sh" "${pkgdir}/usr/lib/qubes/qubes_cow_setup.sh"
install -m 0644 "${srcdir}/${_pkgnvr}/grub/grub.qubes-kernel-vm-support" "${pkgdir}/etc/default/grub.qubes-kernel-vm-support"
make install-gptfix SBINDIR=/usr/bin "DESTDIR=$pkgdir"
}
3 changes: 2 additions & 1 deletion debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ Build-Depends:
libxen-dev,
pkg-config,
python3-setuptools,
libicu-dev
libicu-dev,
libz-dev,
Standards-Version: 4.4.0.1
Homepage: https://www.qubes-os.org
Vcs-Git: https://github.com/QubesOS/qubes-linux-utils.git
Expand Down
1 change: 1 addition & 0 deletions debian/qubes-kernel-vm-support.install
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ usr/lib/dracut/modules.d/90qubes-vm-modules/*
usr/lib/dracut/modules.d/90qubes-vm-simple/*
usr/lib/dracut/modules.d/80xen-scrub-pages/*
etc/default/grub.d/30-qubes-kernel-vm-support.cfg
usr/sbin/gptfix
1 change: 1 addition & 0 deletions debian/rules
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ override_dh_auto_build:
override_dh_auto_install:
make install LIBDIR=/usr/lib DEBIANBUILD=1 PYTHON_PREFIX_ARG=--install-layout=deb
make install-debian-kernel-support LIBDIR=/usr/lib DEBIANBUILD=1
make install-gptfix SBINDIR=/usr/sbin

override_dh_install:
dh_install --fail-missing
Loading

0 comments on commit f0c98fd

Please sign in to comment.