Package: dpkg
Version: 1.21.7
Severity: wishlist
Tags: patch
X-Debbugs-Cc: jo...@debian.org

Hi,

when cross compiling, one property of the build system that can
influence the contents of the generate binary packages is whether or not
the host architecture can be executed. While some platforms can natively
execute others (like amd64 can execute i386), other combinations are
more surprising. When installing the qemu-user-static package on a
system with binfmt-support, then foreign architecture binaries for all
architectures qemu supports will suddenly become executable. This is
especially tricky because this will also transparently affect chroot
builds with sbuild and neither schroot nor unshare isolation can prevent
the emulation from happening. The only ways to stop automatic emulation
are uninstalling qemu-user-static on the outside of the build chroot,
writing 0 to /proc/sys/fs/binfmt_misc/qemu-$arch or running the build
with QEMU_VERSION=1 (unreliable). Since transparent foreign architecture
emulation is easily present on a developer's machine and thus
influencing the build (even when done inside a chroot) it would be
useful to record whether or not foreign architecture binaries can be
executed in the buildinfo file.

I attached a proof-of-concept patch that does exactly that. Since we
cannot rely on arch-test being installed in the build environment, this
approach cross compiles a small true.c executable for the host
architecture. This should always work because gcc is build-essential.
The binary outputs a small string instead of just relying on the exit
code to guard against QEMU_VERSION=1 "disabling" of emulation. The field
'Can-Execute-Host-Architecture is only added when cross-compiling, i.e
when host and build architectures mismatch.

Thanks!

cheers, josch
>From 62179358b57d09fc8c6bb7a59deb128c67cbe522 Mon Sep 17 00:00:00 2001
From: Johannes Schauer Marin Rodrigues <jo...@mister-muffin.de>
Date: Wed, 18 May 2022 07:11:39 +0200
Subject: [PATCH] dpkg-genbuildinfo: when cross-compiling add
 Can-Execute-Host-Architecture field

---
 scripts/dpkg-genbuildinfo.pl | 32 +++++++++++++++++++++++++++++++-
 1 file changed, 31 insertions(+), 1 deletion(-)

diff --git a/scripts/dpkg-genbuildinfo.pl b/scripts/dpkg-genbuildinfo.pl
index e05fce048..a296a7314 100755
--- a/scripts/dpkg-genbuildinfo.pl
+++ b/scripts/dpkg-genbuildinfo.pl
@@ -28,13 +28,14 @@ use warnings;
 use List::Util qw(any);
 use Cwd;
 use File::Basename;
+use File::Temp qw(tmpnam);
 use POSIX qw(:fcntl_h :locale_h strftime);
 
 use Dpkg ();
 use Dpkg::Gettext;
 use Dpkg::Checksums;
 use Dpkg::ErrorHandling;
-use Dpkg::Arch qw(get_build_arch get_host_arch debarch_eq);
+use Dpkg::Arch qw(get_build_arch get_host_arch debarch_eq 
debarch_to_gnutriplet);
 use Dpkg::Build::Types;
 use Dpkg::Build::Info qw(get_build_env_allowed);
 use Dpkg::BuildOptions;
@@ -46,6 +47,8 @@ use Dpkg::Control;
 use Dpkg::Changelog::Parse;
 use Dpkg::Deps;
 use Dpkg::Dist::Files;
+use Dpkg::Exit qw(push_exit_handler);
+use Dpkg::IPC;
 use Dpkg::Lock;
 use Dpkg::Version;
 use Dpkg::Vendor qw(get_current_vendor run_vendor_hook);
@@ -455,6 +458,33 @@ $fields->{'Installed-Build-Depends'} = 
collect_installed_builddeps($control);
 
 $fields->{'Environment'} = "\n" . cleansed_environment();
 
+if (get_host_arch() ne $fields->{'Build-Architecture'}) {
+    # if we are cross-compiling, record whether it was possible to execute the
+    # host architecture by cross-compiling and executing a small host-arch
+    # binary
+
+    my $tmpname = tmpnam();
+    push_exit_handler(sub { unlink($tmpname) });
+    my ($stdout, $stderr) = ('', '');
+    my $testprog = 'int main(){write(1,"ok",2);return 0;}';
+    spawn(exec => [ debarch_to_gnutriplet(get_host_arch()) . '-gcc', '-x', 
'c', '-o', $tmpname, '-' ],
+       wait_child => 1, nocheck => 1,
+       to_string => \$stdout,
+       error_to_string => \$stderr,
+       from_string => \$testprog);
+    if ($?) {
+       print { *STDOUT } $stdout;
+       print { *STDERR } $stderr;
+       subprocerr("gcc -x c -");
+    }
+    spawn(exec => [ $tmpname ], error_to_file => '/dev/null', 'to_string' => 
\$stdout, wait_child => 1, nocheck => 1);
+    if ($? == 0 && $stdout eq "ok") {
+       $fields->{'Can-Execute-Host-Architecture'} = "true";
+    } else {
+       $fields->{'Can-Execute-Host-Architecture'} = "false";
+    }
+}
+
 # Generate the buildinfo filename.
 if ($stdout) {
     # Nothing to do.
-- 
2.35.1

Reply via email to