Compare commits

..

20 commits

Author SHA1 Message Date
81d155cac8
release 1.3.5 2023-03-20 06:26:51 +01:00
b3338bd33b
refine warnings and add documentation for using --include with .deb files in unshare mode 2023-03-19 09:04:06 +01:00
71a9a2e7a9
tests/include-deb-file: run in all modes 2023-03-19 09:03:19 +01:00
19a2ec044a
fix undefined variable in error message 2023-03-19 09:02:43 +01:00
af95b4d778
hooks/file-mirror-automount/setup00.sh: use mmdebstrap --hook-helper upload and sync-in instead of cp 2023-03-19 09:01:37 +01:00
4d44b9dbbe
export MMDEBSTRAP_ARGV0 for hooks 2023-03-19 09:00:46 +01:00
846662276f
tests/multiple-include: be more liberal with packages adding or dropping maintainer scripts 2023-03-18 15:10:28 +01:00
9a19801095
debian-archive-keyring now puts *.asc keys into /etc/apt/trusted.gpg.d 2023-03-18 04:53:28 +01:00
9710ee16a0
release 1.3.4 2023-03-17 22:54:06 +01:00
8db443a6c4
README.md: update list of contributors 2023-03-17 08:03:19 +01:00
ff9b76ed19
improve debug and error message wording 2023-03-16 22:18:49 +01:00
Jakub Wilk
a719ffd20a
Fix apt.conf permissions
Having world-writable apt.conf may be exploited by locals users to
execute arbitrary code in the context of the user running mmdebstrap.
2023-03-16 21:56:16 +01:00
55cae49ec7
let test_unshare_userns error out itself if necessary 2023-03-16 08:14:39 +01:00
055e1719b9
try unsharing before automatically choosing unshare mode 2023-03-15 17:08:12 +01:00
2614924925
make_mirror.sh: clean up more things left over by USE_HOST_APT_CONFIG=yes 2023-03-13 13:22:22 +01:00
901d017099
tests: do not run debug and verbose tests with variant standards for arches affected by #1031276 2023-03-13 13:21:18 +01:00
6b49a2dbbf
coverage.sh: pass any cli args on to coverage.py 2023-03-13 13:20:05 +01:00
034698f8d3
tests/check-for-bit-by-bit-identical-format-output: use the default user check 2023-03-05 19:26:13 +01:00
a184cc003c
tests: run verbose and debug tests with --variant=standard for maximum output 2023-03-05 19:25:13 +01:00
8253daf403
make_mirror.sh: also delete mmdebstrap-*-*.* 2023-03-05 17:43:54 +01:00
17 changed files with 287 additions and 143 deletions

View file

@ -1,3 +1,13 @@
1.3.5 (2023-03-20)
------------------
- bugfix release
1.3.4 (2023-03-16)
------------------
- more safeguards before automatically choosing unshare mode
1.3.3 (2023-02-19)
------------------

View file

@ -152,13 +152,14 @@ Contributors
============
- Johannes Schauer Marin Rodrigues (main author)
- Gioele Barabucci
- Helmut Grohne
- Gioele Barabucci
- Benjamin Drung
- Jochen Sprickerhof
- Josh Triplett
- Konstantin Demin
- David Kalnischkies
- Jakub Wilk
- Joe Groocock
- Nicolas Vigier
- Raul Tambre

View file

@ -69,7 +69,7 @@ mirror="http://127.0.0.1/debian"
export HAVE_QEMU HAVE_BINFMT RUN_MA_SAME_TESTS DEFAULT_DIST SOURCE_DATE_EPOCH CMD mirror
./coverage.py
./coverage.py "$@"
if [ -e shared/cover_db.img ]; then
# produce report inside the VM to make sure that the versions match or

View file

@ -283,10 +283,16 @@ Test: debootstrap-no-op-options
Needs-Root: true
Test: verbose
Needs-Root: true
Variants: - standard
Skip-If:
variant == "-" and hostarch not in ["armel", "armhf", "mipsel"] # #1031276
variant == "standard" and hostarch in ["armel", "armhf", "mipsel"] # #1031276
Test: debug
Needs-Root: true
Variants: - standard
Skip-If:
variant == "-" and hostarch not in ["armel", "armhf", "mipsel"] # #1031276
variant == "standard" and hostarch in ["armel", "armhf", "mipsel"] # #1031276
Test: quiet
Needs-Root: true
@ -396,6 +402,7 @@ Test: error-if-stdout-is-tty
Test: variant-custom-timeout
Test: include-deb-file
Modes: root unshare fakechroot
Needs-APT-Config: true
Test: unshare-include-deb

View file

@ -14,6 +14,10 @@ env APT_CONFIG="$MMDEBSTRAP_APT_CONFIG" apt-get indextargets --no-release-info -
| sort -u \
| while read -r path; do
mkdir -p "$rootdir/run/mmdebstrap"
if [ ! -d "/$path" ]; then
echo "/$path is not an existing directory" >&2
continue
fi
case $MMDEBSTRAP_MODE in
root|unshare)
echo "bind-mounting /$path into the chroot" >&2
@ -22,8 +26,8 @@ env APT_CONFIG="$MMDEBSTRAP_APT_CONFIG" apt-get indextargets --no-release-info -
;;
*)
echo "copying /$path into the chroot" >&2
mkdir -p "$rootdir/$(dirname "$path")"
cp -av "/$path" "$rootdir/$(dirname "$path")"
mkdir -p "$rootdir/$path"
"$MMDEBSTRAP_ARGV0" --hook-helper "$rootdir" "$MMDEBSTRAP_MODE" "$MMDEBSTRAP_HOOK" env "$MMDEBSTRAP_VERBOSITY" sync-in "/$path" "/$path" <&"$MMDEBSTRAP_HOOKSOCK" >&"$MMDEBSTRAP_HOOKSOCK"
;;
esac
printf '/%s\0' "$path" >> "$rootdir/run/mmdebstrap/file-mirror-automount"
@ -47,6 +51,10 @@ for pkg in $MMDEBSTRAP_INCLUDE; do
fi
# make path absolute
pkg="$(realpath "$pkg")"
case "$pkg" in
/*) : ;;
*) echo "path for $pkg is not absolute" >&2; continue;;
esac
mkdir -p "$rootdir/run/mmdebstrap"
mkdir -p "$rootdir/$(dirname "$pkg")"
case $MMDEBSTRAP_MODE in
@ -57,7 +65,7 @@ for pkg in $MMDEBSTRAP_INCLUDE; do
;;
*)
echo "copying $pkg into the chroot" >&2
cp -av "$pkg" "$rootdir/$pkg"
"$MMDEBSTRAP_ARGV0" --hook-helper "$rootdir" "$MMDEBSTRAP_MODE" "$MMDEBSTRAP_HOOK" env "$MMDEBSTRAP_VERBOSITY" upload "$pkg" "$pkg" <&"$MMDEBSTRAP_HOOKSOCK" >&"$MMDEBSTRAP_HOOKSOCK"
;;
esac
printf '/%s\0' "$pkg" >> "$rootdir/run/mmdebstrap/file-mirror-automount"

View file

@ -20,7 +20,10 @@ deletecache() {
return 1
fi
# be very careful with removing the old directory
for dist in oldstable stable testing unstable; do
# experimental is pulled in with USE_HOST_APT_CONFIG=yes on debci
# when testing a package from experimental
for dist in oldstable stable testing unstable experimental; do
# deleting artifacts from test "debootstrap"
for variant in minbase buildd -; do
if [ -e "$dir/debian-$dist-$variant.tar" ]; then
rm "$dir/debian-$dist-$variant.tar"
@ -28,6 +31,18 @@ deletecache() {
echo "does not exist: $dir/debian-$dist-$variant.tar" >&2
fi
done
# deleting artifacts from test "mmdebstrap"
for variant in essential apt minbase buildd - standard; do
for format in tar ext2 squashfs; do
if [ -e "$dir/mmdebstrap-$dist-$variant.$format" ]; then
# attempt to delete for all dists because DEFAULT_DIST might've been different the last time
rm "$dir/mmdebstrap-$dist-$variant.$format"
elif [ "$dist" = "$DEFAULT_DIST" ]; then
# only warn about non-existance when it's expected to exist
echo "does not exist: $dir/mmdebstrap-$dist-$variant.$format" >&2
fi
done
done
if [ -e "$dir/debian/dists/$dist" ]; then
rm --one-file-system --recursive "$dir/debian/dists/$dist"
else
@ -63,11 +78,16 @@ deletecache() {
rm --one-file-system "$f"
fi
done
if [ -e "$dir/debian/pool/main" ]; then
rm --one-file-system --recursive "$dir/debian/pool/main"
# on i386 and amd64, the intel-microcode and amd64-microcode packages
# from non-free-firwame get pulled in because they are
# priority:standard with USE_HOST_APT_CONFIG=yes
for c in main non-free-firmware; do
if [ -e "$dir/debian/pool/$c" ]; then
rm --one-file-system --recursive "$dir/debian/pool/$c"
else
echo "does not exist: $dir/debian/pool/main" >&2
echo "does not exist: $dir/debian/pool/$c" >&2
fi
done
if [ -e "$dir/debian-security/pool/updates/main" ]; then
rm --one-file-system --recursive "$dir/debian-security/pool/updates/main"
else

View file

@ -23,7 +23,7 @@
use strict;
use warnings;
our $VERSION = '1.3.3';
our $VERSION = '1.3.5';
use English;
use Getopt::Long;
@ -305,14 +305,18 @@ sub shellescape {
sub test_unshare_userns {
my $verbose = shift;
my $unshare_fail = shift;
if ($EFFECTIVE_USER_ID == 0) {
my $msg = "cannot unshare user namespace when executing as root";
local *maybe_error = sub {
my $msg = shift;
if ($verbose) {
warning $msg;
error $msg;
} else {
debug $msg;
}
};
if ($EFFECTIVE_USER_ID == 0) {
maybe_error("cannot unshare user namespace when executing as root");
return 0;
}
# arguments to syscalls have to be stored in their own variable or
@ -326,12 +330,7 @@ sub test_unshare_userns {
if ($ret == 0) {
exit 0;
} else {
my $msg = "unshare syscall failed: $!";
if ($verbose) {
warning $msg;
} else {
debug $msg;
}
maybe_error("unshare syscall failed: $!");
exit 1;
}
}
@ -344,120 +343,140 @@ sub test_unshare_userns {
system "newuidmap 2>/dev/null";
if (($? >> 8) != 1) {
if (($? >> 8) == 127) {
my $msg = "cannot find newuidmap";
if ($verbose) {
if ($unshare_fail) {
error $msg;
maybe_error("cannot find newuidmap");
} else {
warning $msg;
}
} else {
debug $msg;
}
} else {
my $msg = "newuidmap returned unknown exit status: $?";
if ($verbose) {
warning $msg;
} else {
debug $msg;
}
maybe_error("newuidmap returned unknown exit status: $?");
}
return 0;
}
system "newgidmap 2>/dev/null";
if (($? >> 8) != 1) {
if (($? >> 8) == 127) {
my $msg = "cannot find newgidmap";
if ($verbose) {
warning $msg;
maybe_error("cannot find newgidmap");
} else {
debug $msg;
maybe_error("newgidmap returned unknown exit status: $?");
}
return 0;
}
my @idmap = read_subuid_subgid($verbose);
if (scalar @idmap == 0) {
maybe_error("failed to parse /etc/subuid and /etc/subgid");
return 0;
}
# too much can go wrong when doing the dance required to unsharing the user
# namespace, so instead of adding more complexity to support maybe_error()
# to a function that is already too complex, we use eval()
eval {
$pid = get_unshare_cmd(
sub {
if ($EFFECTIVE_USER_ID == 0) {
exit 0;
} else {
my $msg = "newgidmap returned unknown exit status: $?";
if ($verbose) {
warning $msg;
} else {
debug $msg;
exit 1;
}
},
\@idmap
);
waitpid $pid, 0;
if ($? != 0) {
maybe_error("failed to unshare the user namespace");
return 0;
}
};
if ($@) {
maybe_error($@);
return 0;
}
return 1;
}
sub read_subuid_subgid() {
sub read_subuid_subgid {
my $verbose = shift;
my @result = ();
my $username = getpwuid $REAL_USER_ID;
my ($subid, $num_subid, $fh, $n);
my @result = ();
local *maybe_warn = sub {
my $msg = shift;
if ($verbose) {
warning $msg;
} else {
debug $msg;
}
};
if (!-e "/etc/subuid") {
warning "/etc/subuid doesn't exist";
maybe_warn("/etc/subuid doesn't exist");
return;
}
if (!-r "/etc/subuid") {
warning "/etc/subuid is not readable";
maybe_warn("/etc/subuid is not readable");
return;
}
open $fh, "<", "/etc/subuid"
or error "cannot open /etc/subuid for reading: $!";
or maybe_warn("cannot open /etc/subuid for reading: $!");
if (!$fh) {
return;
}
while (my $line = <$fh>) {
($n, $subid, $num_subid) = split(/:/, $line, 3);
last if ($n eq $username);
}
close $fh;
if (!length $subid) {
warning "/etc/subuid is empty";
maybe_warn("/etc/subuid is empty");
return;
}
if ($n ne $username) {
warning "no entry in /etc/subuid for $username";
maybe_warn("no entry in /etc/subuid for $username");
return;
}
push @result, ["u", 0, $subid, $num_subid];
if (scalar(@result) < 1) {
warning "/etc/subuid does not contain an entry for $username";
maybe_warn("/etc/subuid does not contain an entry for $username");
return;
}
if (scalar(@result) > 1) {
warning "/etc/subuid contains multiple entries for $username";
maybe_warn("/etc/subuid contains multiple entries for $username");
return;
}
if (!-e "/etc/subgid") {
warning "/etc/subgid doesn't exist";
maybe_warn("/etc/subgid doesn't exist");
return;
}
if (!-r "/etc/subgid") {
warning "/etc/subgid is not readable";
maybe_warn("/etc/subgid is not readable");
return;
}
open $fh, "<", "/etc/subgid"
or error "cannot open /etc/subgid for reading: $!";
or maybe_warn("cannot open /etc/subgid for reading: $!");
if (!$fh) {
return;
}
while (my $line = <$fh>) {
($n, $subid, $num_subid) = split(/:/, $line, 3);
last if ($n eq $username);
}
close $fh;
if (!length $subid) {
warning "/etc/subgid is empty";
maybe_warn("/etc/subgid is empty");
return;
}
if ($n ne $username) {
warning "no entry in /etc/subgid for $username";
maybe_warn("no entry in /etc/subgid for $username");
return;
}
push @result, ["g", 0, $subid, $num_subid];
if (scalar(@result) < 2) {
warning "/etc/subgid does not contain an entry for $username";
maybe_warn("/etc/subgid does not contain an entry for $username");
return;
}
if (scalar(@result) > 2) {
warning "/etc/subgid contains multiple entries for $username";
maybe_warn("/etc/subgid contains multiple entries for $username");
return;
}
@ -1594,6 +1613,9 @@ sub run_hooks {
if (length $ENV{APT_CONFIG}) {
push @env_opts, "MMDEBSTRAP_APT_CONFIG=$ENV{APT_CONFIG}";
}
# I hook script that wants to call mmdebstrap with --hook-helper needs to
# know how mmdebstrap was executed
push @env_opts, "MMDEBSTRAP_ARGV0=$PROGRAM_NAME";
# Storing the mode is important for hook scripts to potentially change
# their behavior depending on the mode. It's also important for when the
# hook wants to use the mmdebstrap --hook-helper.
@ -1801,6 +1823,25 @@ sub setup {
run_hooks('setup', $options);
# apt runs dpkg from inside the chroot and directly passes the filename to
# dpkg. Hence, the included files on the outside must be present under the
# same path on the inside. If they are not, dpkg cannot find them.
if (scalar(grep { /^\// } @{ $options->{include} }) > 0) {
my $ret = 0;
foreach my $f (grep { /^\// } @{ $options->{include} }) {
next if -e "$options->{root}/$f";
warning
"path given via --include is not present inside the chroot: $f";
$ret = 1;
}
if ($ret != 0) {
warning("apt runs chrooted dpkg which needs access to the "
. "package paths given via --include inside the chroot.");
warning "maybe try running mmdebstrap with "
. "--hook-dir=/usr/share/mmdebstrap/hooks/file-mirror-automount";
}
}
if (any { $_ eq 'update' } @{ $options->{skip} }) {
info "skipping update as requested";
} else {
@ -2246,7 +2287,7 @@ sub run_setup() {
# we have to make the config file world readable so that a possible
# /usr/lib/apt/solvers/apt process which is run by the _apt user is also
# able to read it
chmod 0666, "$tmpfile" or error "cannot chmod $tmpfile: $!";
chmod 0644, "$tmpfile" or error "cannot chmod $tmpfile: $!";
if ($verbosity_level >= 3) {
0 == system('apt-get', '--version')
or error "apt-get --version failed: $?";
@ -4348,12 +4389,12 @@ sub main() {
# lxc-usernsexec -- lxc-unshare -s 'MOUNT|PID|UTSNAME|IPC' ...
# but without needing lxc
if (scalar @ARGV >= 1 && $ARGV[0] eq "--unshare-helper") {
if ($EFFECTIVE_USER_ID != 0 && !test_unshare_userns(1)) {
exit 1;
if ($EFFECTIVE_USER_ID != 0) {
test_unshare_userns(1);
}
my @idmap = ();
if ($EFFECTIVE_USER_ID != 0) {
@idmap = read_subuid_subgid;
@idmap = read_subuid_subgid 1;
}
my $pid = get_unshare_cmd(
sub {
@ -4423,10 +4464,8 @@ sub main() {
my ($opt_name, $opt_value) = @_;
my $sanitize_path = sub {
my $pkg = shift;
$pkg = abs_path($pkg);
if (!defined $pkg) {
error "cannot resolve absolute path of $pkg: $!";
}
$pkg = abs_path($pkg)
// error "cannot resolve absolute path of $pkg: $!";
if ($pkg !~ /^\//) {
error "absolute path of $pkg doesn't start with a slash";
}
@ -4781,7 +4820,8 @@ sub main() {
}
exec 'fakechroot', 'fakeroot', @prefix, $PROGRAM_NAME, @ARGVORIG;
} else {
error "unable to pick chroot mode automatically";
error( "unable to pick chroot mode automatically (use --mode for "
. "manual selection)");
}
info "automatically chosen mode: $options->{mode}";
} elsif ($options->{mode} eq 'root') {
@ -4816,26 +4856,8 @@ sub main() {
}
# ...or we are not root and then we need to be able to unshare the user
# namespace.
if ($EFFECTIVE_USER_ID != 0 && !test_unshare_userns(1, 1)) {
my $procfile = '/proc/sys/kernel/unprivileged_userns_clone';
open(my $fh, '<', $procfile)
or error "failed to open $procfile: $!";
chomp(
my $content = do { local $/; <$fh> }
);
close($fh);
if ($content ne "1") {
info "/proc/sys/kernel/unprivileged_userns_clone is set to"
. " $content";
info "Try running:";
info " sudo sysctl -w kernel.unprivileged_userns_clone=1";
info "or permanently enable unprivileged usernamespaces by"
. " putting the setting into /etc/sysctl.d/";
info "THIS SETTING HAS SECURITY IMPLICATIONS!";
info "Refer to https://bugs.debian.org/cgi-bin/"
. "bugreport.cgi?bug=898446";
}
exit 1;
if ($EFFECTIVE_USER_ID != 0) {
test_unshare_userns(1);
}
} elsif ($options->{mode} eq 'chrootless') {
if ($EFFECTIVE_USER_ID == 0) {
@ -5171,12 +5193,14 @@ sub main() {
my $keyring
= get_keyring_by_suite($options->{suite}, \%suite_by_vendor);
if (!defined $keyring) {
debug "get_keyring_by_suite() cannot find keyring";
return '';
}
# we can only check if we need the signed-by entry if we u
# automatically chosen keyring exists
if (!defined $keyring || !-e $keyring) {
debug "found keyring does not exist";
return '';
}
@ -5221,7 +5245,7 @@ sub main() {
# find all the fingerprints of the keys apt currently
# knows about
my @keyrings = ();
opendir my $dh, "$options->{apttrustedparts}"
opendir my $dh, $options->{apttrustedparts}
or error "cannot read $options->{apttrustedparts}";
while (my $filename = readdir $dh) {
if ($filename !~ /\.(asc|gpg)$/) {
@ -5230,7 +5254,7 @@ sub main() {
$filename = "$options->{apttrustedparts}/$filename";
# skip empty keyrings
-s "$filename" || next;
push @keyrings, "$filename";
push @keyrings, $filename;
}
closedir $dh;
if (-s $options->{apttrusted}) {
@ -5238,6 +5262,7 @@ sub main() {
}
my @aptfingerprints = ();
if (scalar @keyrings == 0) {
debug "no keyring is trusted by apt";
return " [signed-by=\"$keyring\"]";
}
info "finding correct signed-by value...";
@ -5261,6 +5286,7 @@ sub main() {
}
print_progress("done");
if (scalar @aptfingerprints == 0) {
debug "no fingerprints found";
return " [signed-by=\"$keyring\"]";
}
# check if all fingerprints from the keyring that we guessed
@ -5277,6 +5303,7 @@ sub main() {
# if this fingerprint is not known by apt, then we need
#to add the signed-by option
if (none { $_ eq $1 } @aptfingerprints) {
debug "fingerprint $1 is not trusted by apt";
return " [signed-by=\"$keyring\"]";
}
}
@ -5665,7 +5692,7 @@ sub main() {
# for unshare mode the rootfs directory has to have appropriate
# permissions
if ($EFFECTIVE_USER_ID != 0 and $options->{mode} eq 'unshare') {
@idmap = read_subuid_subgid;
@idmap = read_subuid_subgid 1;
# sanity check
if ( scalar(@idmap) != 2
|| $idmap[0][0] ne 'u'
@ -5712,9 +5739,9 @@ sub main() {
);
waitpid $pid, 0;
if ($? != 0) {
warning "no read access for some packages for the unshared user";
warning "maybe try running mmdebstrap with "
. "--hook-dir=/usr/share/mmdebstrap/hooks/file-mirror-automount";
warning("apt on the outside is run as the unshared user and "
. "needs read access to packages outside the chroot given "
. "via --include");
}
}
@ -6450,8 +6477,9 @@ by this option will be the only ones that get either extracted or installed by
dpkg, respectively. For all other variants, apt is used to install the
additional packages. Package names are directly passed to apt and thus, you
can use apt features like C<pkg/suite>, C<pkg=version>, C<pkg->, use a glob or
regex for C<pkg>, use apt patterns or pass a path to a .deb package file. See
apt(8) for the supported syntax.
regex for C<pkg>, use apt patterns or pass a path to a .deb package file (see
below for notes concerning passing the path to a .deb package file in
B<unshare> mode). See apt(8) for the supported syntax.
The option can be specified multiple times and the packages are concatenated in
the order in which they are given on the command line. If later list items are
@ -6479,6 +6507,22 @@ apt. To add more packages, use multiple B<--include> options. To disable this
detection of patterns and paths, start the argument to B<--include> with a
comma or whitespace.
If you pass the path to a .deb package file using B<--include>, B<mmdebstrap>
will ensure that the path exists. If the path is a relative path, it will
internally by converted to an absolute path. Since apt (outside the chroot)
passes paths to dpkg (on the inside) verbatim, you have to make the .deb
package available under the same path inside the chroot as well or otherwise
dpkg inside the chroot will be unable to access it. This can be achieved using
a setup-hook. A hook that automatically makes the contents of C<file://>
mirrors as well as .deb packages given with B<--include> available inside the
chroot is provided by B<mmdebstrap> as
B<--hook-dir=/usr/share/mmdebstrap/hooks/file-mirror-automount>. This hook
takes care of copying all relevant file to their correct locations and cleans
up those files at the end. In B<unshare> mode, the .deb package paths have to
be accessible by the unshared user as well. This means that the package itself
likely must be made world-readable and all directory components on the path to
it world-executable.
=item B<--components>=I<comp1>[,I<comp2>,...]
Comma or whitespace separated list of components like main, contrib, non-free
@ -6668,9 +6712,9 @@ decides which way this is achieved.
This mode automatically selects a fitting mode. If the effective user id is the
one of the superuser, then the B<sudo> mode is chosen. Otherwise, the
B<unshare> mode is picked if the system has the sysctl
C<kernel.unprivileged_userns_clone> set to C<1>. Should that not be the case
and if the fakechroot binary exists, the B<fakechroot> mode is chosen.
B<unshare> mode is picked if F</etc/subuid> and F</etc/subgid> are set up
correctly. Should that not be the case and if the fakechroot binary exists, the
B<fakechroot> mode is chosen.
=item B<sudo>, B<root>
@ -6935,11 +6979,13 @@ C<MMDEBSTRAP_APT_CONFIG> environment variable. All environment variables set by
the user are preserved, except for C<TMPDIR> which is cleared. See section
B<TMPDIR>. Furthermore, C<MMDEBSTRAP_MODE> will store the mode set by
B<--mode>, C<MMDEBSTRAP_HOOK> stores which hook is currently run (setup,
extract, essential, customize) and C<MMDEBSTRAP_VERBOSITY> stores the numerical
verbosity level (0 for no output, 1 for normal, 2 for verbose and 3 for debug
output). The C<MMDEBSTRAP_INCLUDE> variable stores the list of packages, apt
patterns or file paths given by the B<--include> option, separated by a comma
and with commas and percent signs in the option values urlencoded.
extract, essential, customize), C<MMDEBSTRAP_ARGV0> stores the name of the
binary with which B<mmdebstrap> was executed and C<MMDEBSTRAP_VERBOSITY> stores
the numerical verbosity level (0 for no output, 1 for normal, 2 for verbose and
3 for debug output). The C<MMDEBSTRAP_INCLUDE> variable stores the list of
packages, apt patterns or file paths given by the B<--include> option,
separated by a comma and with commas and percent signs in the option values
urlencoded.
In special hooks, the paths inside the chroot are relative to the root
directory of the chroot. The path on the outside is relative to current

View file

@ -5,14 +5,19 @@ if [ ! -e /mmdebstrap-testenv ]; then
echo "this test modifies the system and should only be run inside a container" >&2
exit 1
fi
for f in /etc/apt/trusted.gpg.d/*.gpg /etc/apt/trusted.gpg.d/*.asc; do
[ -e "$f" ] || continue
rm "$f"
done
rmdir /etc/apt/trusted.gpg.d
mkdir /etc/apt/trusted.gpg.d
for f in /usr/share/keyrings/*.gpg; do
name=$(basename "$f" .gpg)
gpg --enarmor < "/usr/share/keyrings/$name.gpg" \
| sed 's/ PGP ARMORED FILE/ PGP PUBLIC KEY BLOCK/;/^Comment: /d' \
> "/etc/apt/trusted.gpg.d/$name.asc"
rm "/usr/share/keyrings/$name.gpg"
done
rm /etc/apt/trusted.gpg.d/*.gpg
rm /usr/share/keyrings/*.gpg
{{ CMD }} --mode=root --variant=apt {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }}
tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt -
rm -r /tmp/debian-chroot.tar

View file

@ -5,14 +5,21 @@ export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }}
trap "rm -f /tmp/debian-chroot-{{ MODE }}.{{ FORMAT }}" EXIT INT TERM
if ! id "${SUDO_USER:-user}" >/dev/null 2>&1; then
case {{ MODE }} in unshare|fakechroot) : ;; *) exit 1;; esac
prefix=
if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && [ "{{ MODE }}" != "auto" ]; then
if ! id "${SUDO_USER:-user}" >/dev/null 2>&1; then
if [ ! -e /mmdebstrap-testenv ]; then
echo "this test modifies the system and should only be run inside a container" >&2
exit 1
fi
useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}"
fi
prefix="runuser -u ${SUDO_USER:-user} --"
fi
runuser -u "${SUDO_USER:-user}" -- {{ CMD }} --mode={{ MODE }} --variant={{ VARIANT }} {{ DIST }} /tmp/debian-chroot-{{ MODE }}.{{ FORMAT }} {{ MIRROR }}
$prefix {{ CMD }} --mode={{ MODE }} --variant={{ VARIANT }} {{ DIST }} /tmp/debian-chroot-{{ MODE }}.{{ FORMAT }} {{ MIRROR }}
cmp ./cache/mmdebstrap-{{ DIST }}-{{ VARIANT }}.{{ FORMAT }} /tmp/debian-chroot-{{ MODE }}.{{ FORMAT }} \
|| diffoscope ./cache/mmdebstrap-{{ DIST }}-{{ VARIANT }}.{{ FORMAT }} /tmp/debian-chroot-{{ MODE }}.{{ FORMAT }}

View file

@ -1,6 +1,17 @@
#!/bin/sh
set -eu
export LC_ALL=C.UTF-8
{{ CMD }} --mode=root --variant=apt --debug {{ DIST }} /tmp/debian-chroot {{ MIRROR }}
tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt -
rm -r /tmp/debian-chroot
export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }}
trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM
# we use variant standard in verbose mode to see the maximum number of packages
# that was chosen in case of USE_HOST_APT_CONFIG=yes
# we use variant important on arches where variant standard is not bit-by-bit
# reproducible due to #1031276
case {{ VARIANT }} in standard|-) : ;; *) exit 1;; esac
{{ CMD }} --variant={{ VARIANT }} --debug {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }}
cmp ./cache/mmdebstrap-{{ DIST }}-{{ VARIANT }}.tar /tmp/debian-chroot.tar \
|| diffoscope ./cache/mmdebstrap-{{ DIST }}-{{ VARIANT }}.tar /tmp/debian-chroot.tar

View file

@ -13,4 +13,4 @@ if [ "$ret" = 0 ]; then
echo expected failure but got exit $ret >&2
exit 1
fi
rm -r /tmp/debian-chroot
[ ! -e /tmp/debian-chroot ]

View file

@ -14,4 +14,4 @@ if [ "$ret" = 0 ]; then
echo expected failure but got exit $ret >&2
exit 1
fi
rm -r /tmp/debian-chroot
[ ! -e /tmp/debian-chroot ]

View file

@ -5,6 +5,18 @@ export LC_ALL=C.UTF-8
trap "rm -rf /tmp/dummypkg.deb /tmp/dummypkg" EXIT INT TERM
prefix=
if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && [ "{{ MODE }}" != "auto" ]; then
if ! id "${SUDO_USER:-user}" >/dev/null 2>&1; then
if [ ! -e /mmdebstrap-testenv ]; then
echo "this test modifies the system and should only be run inside a container" >&2
exit 1
fi
useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}"
fi
prefix="runuser -u ${SUDO_USER:-user} --"
fi
# instead of obtaining a .deb from our cache, we create a new package because
# otherwise apt might decide to download the package with the same name and
# version from the cache instead of using the local .deb
@ -22,7 +34,7 @@ Description: dummypkg
END
dpkg-deb --build "/tmp/dummypkg" "/tmp/dummypkg.deb"
{{ CMD }} --variant=apt --include="/tmp/dummypkg.deb" \
$prefix {{ CMD }} --mode={{ MODE }} --variant=apt --include="/tmp/dummypkg.deb" \
--hook-dir=./hooks/file-mirror-automount \
--customize-hook='chroot "$1" dpkg-query -W -f="\${Status}\n" dummypkg | grep "^install ok installed$"' \
{{ DIST }} /dev/null {{ MIRROR }}

View file

@ -5,7 +5,12 @@ if [ ! -e /mmdebstrap-testenv ]; then
echo "this test modifies the system and should only be run inside a container" >&2
exit 1
fi
rm /etc/apt/trusted.gpg.d/*.gpg
for f in /etc/apt/trusted.gpg.d/*.gpg /etc/apt/trusted.gpg.d/*.asc; do
[ -e "$f" ] || continue
rm "$f"
done
rmdir /etc/apt/trusted.gpg.d
mkdir /etc/apt/trusted.gpg.d
{{ CMD }} --mode=root --variant=apt --keyring=/usr/share/keyrings/debian-archive-keyring.gpg --keyring=/usr/share/keyrings/ {{ DIST }} /tmp/debian-chroot "deb {{ MIRROR }} {{ DIST }} main"
# make sure that no [signedby=...] managed to make it into the sources.list
echo "deb {{ MIRROR }} {{ DIST }} main" | cmp /tmp/debian-chroot/etc/apt/sources.list -

View file

@ -12,14 +12,10 @@ rm /tmp/debian-chroot/etc/timezone
rm -r /tmp/debian-chroot/usr/share/doc/tzdata
rm -r /tmp/debian-chroot/usr/share/zoneinfo
rm /tmp/debian-chroot/var/lib/apt/extended_states
rm /tmp/debian-chroot/var/lib/dpkg/info/doc-debian.list
rm /tmp/debian-chroot/var/lib/dpkg/info/doc-debian.md5sums
rm /tmp/debian-chroot/var/lib/dpkg/info/tzdata.list
rm /tmp/debian-chroot/var/lib/dpkg/info/tzdata.md5sums
rm /tmp/debian-chroot/var/lib/dpkg/info/tzdata.config
rm /tmp/debian-chroot/var/lib/dpkg/info/tzdata.postinst
rm /tmp/debian-chroot/var/lib/dpkg/info/tzdata.postrm
rm /tmp/debian-chroot/var/lib/dpkg/info/tzdata.templates
rm /tmp/debian-chroot/var/lib/dpkg/info/tzdata.preinst
rm /tmp/debian-chroot/var/lib/dpkg/info/tzdata.prerm
for p in doc-debian tzdata; do
for f in list md5sums config postinst postrm templates preinst prerm; do
[ -e "/tmp/debian-chroot/var/lib/dpkg/info/$p.$f" ] || continue
rm "/tmp/debian-chroot/var/lib/dpkg/info/$p.$f"
done
done
tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt -

View file

@ -5,7 +5,12 @@ if [ ! -e /mmdebstrap-testenv ]; then
echo "this test modifies the system and should only be run inside a container" >&2
exit 1
fi
rm /etc/apt/trusted.gpg.d/*.gpg
for f in /etc/apt/trusted.gpg.d/*.gpg /etc/apt/trusted.gpg.d/*.asc; do
[ -e "$f" ] || continue
rm "$f"
done
rmdir /etc/apt/trusted.gpg.d
mkdir /etc/apt/trusted.gpg.d
{{ CMD }} --mode=root --variant=apt {{ DIST }} /tmp/debian-chroot {{ MIRROR }}
printf 'deb [signed-by="/usr/share/keyrings/debian-archive-keyring.gpg"] {{ MIRROR }} {{ DIST }} main\n' | cmp /tmp/debian-chroot/etc/apt/sources.list -
tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt -

View file

@ -1,6 +1,17 @@
#!/bin/sh
set -eu
export LC_ALL=C.UTF-8
{{ CMD }} --mode=root --variant=apt --verbose {{ DIST }} /tmp/debian-chroot {{ MIRROR }}
tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt -
rm -r /tmp/debian-chroot
export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }}
trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM
# we use variant standard in verbose mode to see the maximum number of packages
# that was chosen in case of USE_HOST_APT_CONFIG=yes
# we use variant important on arches where variant standard is not bit-by-bit
# reproducible due to #1031276
case {{ VARIANT }} in standard|-) : ;; *) exit 1;; esac
{{ CMD }} --variant={{ VARIANT }} --verbose {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }}
cmp ./cache/mmdebstrap-{{ DIST }}-{{ VARIANT }}.tar /tmp/debian-chroot.tar \
|| diffoscope ./cache/mmdebstrap-{{ DIST }}-{{ VARIANT }}.tar /tmp/debian-chroot.tar