[pve-devel] [PATCH container v2] Create: fix architecture detection in restore_archive
Thomas Lamprecht
t.lamprecht at proxmox.com
Thu Dec 15 16:24:01 CET 2016
For detecting a CT templates architecture we used the `file -b -L`
output from the PVE host side.
If the container has a link:
/bin/sh -> /bin/bash
(Alpine Linux does that) the '-L' flag from file resolves the
$rootfs/bin/sh to /bin/bash and thus checks the architecture of
bash on the PVE system, which is always 64 bit.
Add a helper which chroots in the rootfs to avoid problems with
absolute symlinks and use 'open' to avoid relative symlink problems
read the first 5 bytes from /bin/sh, 4 bytes for the ELF magic number
and the fifth for the ELF class, which tells us if we have a 32
(class 1) or 64 (class 2) bit ELF binary.
Return this information as an exit code to the parent.
Signed-off-by: Thomas Lamprecht <t.lamprecht at proxmox.com>
---
changes since v1:
* check errors from chroot and read
* use POSIX::_exit so that the child exits directly and does no cleanups
* use 0 exit code to notify parent of problems
* add more comments
src/PVE/LXC/Create.pm | 77 +++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 62 insertions(+), 15 deletions(-)
diff --git a/src/PVE/LXC/Create.pm b/src/PVE/LXC/Create.pm
index 11bc00d..fbcdf17 100644
--- a/src/PVE/LXC/Create.pm
+++ b/src/PVE/LXC/Create.pm
@@ -11,6 +11,7 @@ use PVE::LXC;
use PVE::LXC::Setup;
use PVE::VZDump::ConvertOVZ;
use PVE::Tools;
+use POSIX;
sub next_free_nbd_dev {
@@ -23,6 +24,55 @@ sub next_free_nbd_dev {
die "unable to find free nbd device\n";
}
+sub get_elf_class {
+ my ($rootfs, $binary_fn) = @_;
+
+ my $child = fork();
+
+ if (!defined($child)) {
+ die "get_elf_class - fork failed: $!\n";
+ } elsif ($child == 0) {
+ eval {
+ # chroot avoids a problem where we check the binary of the host system
+ # if $binary_fn is an absolut symlink (e.g. $rootfs/bin/sh -> /bin/bash)
+ chroot($rootfs) or die "chroot '$rootfs' failed: $!\n";
+
+ my $fh;
+ open($fh, "<", $binary_fn) or die "open '$binary_fn' failed: $!\n";
+ binmode($fh);
+
+ my $data;
+
+ my $length = read($fh, $data, 5);
+ die "read failed: $!\n" if !defined($length);
+
+ # 4 bytes ELF magic number and 1 byte ELF class
+ my ($magic, $class) = unpack("A4C", $data);
+
+ die "'$binary_fn' does not resolve to an ELF!\n"
+ if ((!defined($magic) || !defined($class)) && $magic ne "\177ELF");
+
+ die "'$binary_fn' has unknown ELF class '$class'!\n"
+ if ($class != 1 && $class != 2);
+
+ POSIX::_exit($class) # tell parent the elf class via exit code
+ };
+ warn $@;
+ *STDERR->flush(); # just to be sure, _exit doesn't flush
+ POSIX::_exit(0);
+ }
+
+ waitpid($child, 0);
+ my $exit_code = $?;
+ if (my $sig = ($exit_code & 127)) {
+ die "got signal $sig\n";
+ } else {
+ $exit_code = ($exit_code >> 8);
+ }
+
+ return $exit_code;
+}
+
sub restore_archive {
my ($archive, $rootdir, $conf, $no_unpack_error) = @_;
@@ -53,21 +103,18 @@ sub restore_archive {
# if arch is set, we do not try to autodetect it
return if defined($conf->{arch});
- # determine file type of /usr/bin/file itself to get guests' architecture
- $cmd = [@$userns_cmd, '/usr/bin/file', '-b', '-L', "$rootdir/bin/sh"];
- PVE::Tools::run_command($cmd, outfunc => sub {
- shift =~ /^ELF (\d{2}-bit)/; # safely assumes x86 linux
- my $arch_str = $1;
- $conf->{'arch'} = 'amd64'; # defaults to 64bit
- if(defined($arch_str)) {
- $conf->{'arch'} = 'i386' if $arch_str =~ /32/;
- print "Detected container architecture: $conf->{'arch'}\n";
- } else {
- print "CT architecture detection failed, falling back to amd64.\n" .
- "Edit the config in /etc/pve/nodes/{node}/lxc/{vmid}.conf " .
- "to set another architecture.\n";
- }
- });
+
+ my $elf_class = get_elf_class($rootdir, '/bin/sh'); # /bin/sh is POSIX mandatory
+
+ $conf->{'arch'} = 'amd64'; # defaults to 64bit
+ if ($elf_class == 1 || $elf_class == 2) {
+ $conf->{'arch'} = 'i386' if $elf_class == 1;
+ print "Detected container architecture: $conf->{'arch'}\n";
+ } else {
+ print "CT architecture detection failed, falling back to amd64.\n" .
+ "Edit the config in /etc/pve/nodes/{node}/lxc/{vmid}.conf " .
+ "to set another architecture.\n";
+ }
}
sub recover_config {
--
2.1.4
More information about the pve-devel
mailing list