Skip to content

Commit

Permalink
Merge pull request #58 from tonistiigi/update-v6.1-patches
Browse files Browse the repository at this point in the history
update patches loading to support v6.1.0 and cpu-max
  • Loading branch information
tonistiigi authored Sep 9, 2021
2 parents ae677ab + 39ec624 commit ee79c56
Show file tree
Hide file tree
Showing 16 changed files with 1,212 additions and 37 deletions.
36 changes: 32 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,21 +77,49 @@ jobs:
with:
config: .github/buildkit.toml
-
name: Test
name: Test buildkit
if: matrix.target == 'buildkit'
uses: docker/bake-action@v1
with:
files: |
./docker-bake.hcl
${{ steps.meta.outputs.bake-file }}
targets: buildkit-test
-
name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Load mainline for testing
if: matrix.target == 'mainline'
uses: docker/bake-action@v1
with:
files: |
./docker-bake.hcl
${{ steps.meta.outputs.bake-file }}
targets: mainline
load: true
set: |
*.cache-from=type=local,src=/tmp/.binfmt-cache/${{ matrix.target }}
mainline.tags=tonistiigi/binfmt:test
- name: Test mainline
if: matrix.target == 'mainline'
run: |
docker run --rm --privileged tonistiigi/binfmt:test --uninstall amd64,arm64,arm,ppc64le,s390x,riscv64
docker run --rm --privileged tonistiigi/binfmt:test --install all
docker run --rm arm64v8/alpine uname -a
docker run --rm arm32v7/alpine uname -a
docker run --rm ppc64le/alpine uname -a
docker run --rm s390x/alpine uname -a
docker run --rm tonistiigi/debian:riscv uname -a
docker run --rm --platform=linux/s390x s390x/ubuntu apt update
docker run --rm --platform=linux/ppc64le ppc64le/ubuntu apt update
docker run --rm --platform=linux/arm64 arm64v8/ubuntu apt update
-
name: Login to DockerHub
if: startsWith(github.ref, 'refs/heads/')
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERIO_USERNAME }}
password: ${{ secrets.DOCKERIO_PASSWORD }}
-
name: Set up QEMU
uses: docker/setup-qemu-action@v1
-
name: Build ${{ matrix.target }}
uses: docker/bake-action@v1
Expand Down
51 changes: 33 additions & 18 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,28 +1,44 @@
# syntax=docker/dockerfile:1.2
# syntax=docker/dockerfile:1.3-labs

ARG ALPINE_BASE=alpine:3.14
ARG ALPINE_VERSION=3.14
ARG ALPINE_BASE=alpine:${ALPINE_VERSION}

ARG QEMU_VERSION
ARG QEMU_VERSION=head
ARG QEMU_REPO=https://github.com/qemu/qemu

# xx is a helper for cross-compilation
FROM --platform=$BUILDPLATFORM tonistiigi/xx@sha256:56b19a5fb89b99195ec494d59ad34370d14540858c1f56c560ec1e7f2d1c177f AS xx

FROM --platform=$BUILDPLATFORM ${ALPINE_BASE} AS src
RUN apk add --no-cache git patch

WORKDIR /src
ARG QEMU_VERSION
ARG QEMU_REPO
WORKDIR /src
RUN git clone $QEMU_REPO && \
git clone --depth 1 -b 3.14-stable https://github.com/alpinelinux/aports.git && \
cd qemu && \
git checkout $QEMU_VERSION && \
for f in ../aports/community/qemu/*.patch; do patch -p1 < $f; done && \
scripts/git-submodule.sh update \
ui/keycodemapdb \
tests/fp/berkeley-testfloat-3 \
tests/fp/berkeley-softfloat-3 \
dtc slirp
RUN git clone $QEMU_REPO && cd qemu && git checkout $QEMU_VERSION
COPY patches patches
ARG QEMU_PATCHES=cpu-max
ARG QEMU_PATCHES_ALL=${QEMU_PATCHES},alpine-patches,zero-init-msghdr
RUN <<eof
set -ex
if [ "${QEMU_PATCHES_ALL#*alpine-patches}" != "${QEMU_PATCHES_ALL}" ]; then
ver="$(cat qemu/VERSION)"
for l in $(cat patches/aports.config); do
[ "$(printf "$ver\n$l" | sort -V | head -n 1)" != "$ver" ] && commit=$(echo $l | cut -d, -f2) && break;
done
mkdir -p aports && cd aports && git init
git fetch --depth 1 https://github.com/alpinelinux/aports.git "$commit"
git checkout FETCH_HEAD
mkdir -p ../patches/alpine-patches
cp -a community/qemu/*.patch ../patches/alpine-patches/
cd - && rm -rf aports
fi
cd qemu
for p in $(echo $QEMU_PATCHES_ALL | tr ',' '\n'); do
for f in ../patches/$p/*.patch; do echo "apply $f"; patch -p1 < $f; done
done
scripts/git-submodule.sh update ui/keycodemapdb tests/fp/berkeley-testfloat-3 tests/fp/berkeley-softfloat-3 dtc slirp
eof

FROM --platform=$BUILDPLATFORM ${ALPINE_BASE} AS base
RUN apk add --no-cache git clang lld python3 llvm make ninja pkgconfig glib-dev gcc musl-dev perl bash
Expand All @@ -31,13 +47,12 @@ ENV PATH=/qemu/install-scripts:$PATH
WORKDIR /qemu

ARG TARGETPLATFORM
RUN xx-apk add musl-dev gcc glib-dev glib-static linux-headers zlib-static
RUN xx-apk add --no-cache musl-dev gcc glib-dev glib-static linux-headers zlib-static
RUN set -e; \
[ "$(xx-info arch)" = "ppc64le" ] && XX_CC_PREFER_LINKER=ld xx-clang --setup-target-triple; \
[ "$(xx-info arch)" = "386" ] && XX_CC_PREFER_LINKER=ld xx-clang --setup-target-triple; \
true


FROM base AS build
ARG TARGETPLATFORM
ARG QEMU_VERSION QEMU_TARGETS
Expand All @@ -46,7 +61,7 @@ RUN --mount=target=.,from=src,src=/src/qemu,rw --mount=target=./install-scripts,
TARGETPLATFORM=${TARGETPLATFORM} configure_qemu.sh && \
make -j "$(getconf _NPROCESSORS_ONLN)" && \
make install && \
cd /usr/bin && for f in $(ls qemu-*); do xx-verify $f; done
cd /usr/bin && for f in $(ls qemu-*); do xx-verify --static $f; done

ARG BINARY_PREFIX
RUN cd /usr/bin; [ -z "$BINARY_PREFIX" ] || for f in $(ls qemu-*); do ln -s $f $BINARY_PREFIX$f; done
Expand All @@ -66,7 +81,7 @@ RUN --mount=target=. \
TARGETPLATFORM=$TARGETPLATFORM xx-go build \
-ldflags "-X main.revision=$(git rev-parse --short HEAD) -X main.qemuVersion=${QEMU_VERSION}" \
-o /go/bin/binfmt ./cmd/binfmt && \
xx-verify /go/bin/binfmt
xx-verify --static /go/bin/binfmt

FROM scratch AS binaries
ARG BINARY_PREFIX
Expand Down
21 changes: 6 additions & 15 deletions docker-bake.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,17 @@ variable "REPO" {
default = "tonistiigi/binfmt"
}
variable "QEMU_REPO" {
default = ""
default = "https://github.com/qemu/qemu"
}
variable "QEMU_VERSION" {
default = ""
default = "v6.1.0"
}

// Special target: https://github.com/docker/metadata-action#bake-definition
target "meta-helper" {
tags = ["${REPO}:test"]
}

function "getdef" {
params = [val, default]
result = <<-EOT
%{ if val != "" }${val}%{ else }${default}%{ endif }
EOT
}

group "default" {
targets = ["binaries"]
}
Expand All @@ -45,8 +38,8 @@ target "all-arch" {
target "mainline" {
inherits = ["meta-helper"]
args = {
QEMU_REPO = trimspace(getdef("${QEMU_REPO}", "https://github.com/qemu/qemu"))
QEMU_VERSION = trimspace(getdef("${QEMU_VERSION}", "v6.0.0"))
QEMU_REPO = QEMU_REPO
QEMU_VERSION = QEMU_VERSION
}
cache-to = ["type=inline"]
cache-from = ["${REPO}:master"]
Expand All @@ -57,13 +50,11 @@ target "mainline-all" {
}

target "buildkit" {
inherits = ["meta-helper"]
inherits = ["mainline"]
args = {
QEMU_REPO = trimspace(getdef("${QEMU_REPO}", "https://github.com/crazy-max/qemu"))
QEMU_VERSION = trimspace(getdef("${QEMU_VERSION}", "be9b8cdfb3a8da33657a6df82e66b2601fe8a310"))
BINARY_PREFIX = "buildkit-"
QEMU_PATCHES = "cpu-max,buildkit-direct-execve-v6.1"
}
cache-to = ["type=inline"]
cache-from = ["${REPO}:buildkit-master"]
target = "binaries"
}
Expand Down
6 changes: 6 additions & 0 deletions patches/aports.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
6.1.50,HEAD
6.0.90,5e4ebee7797d3dc39464857886ea239ad4264ce0
5.2.90,da528ad1889bfc924189993463b4ee757d5514b6
5.1.90,29d5522ca4787e49f9c2e69c73f926433606d056
5.0.90,8d80ff4f0f066b5f6a2d02cf2691a0a6e5cc3481
0.0.0,f238bdae4d755f6e7ab6ce0b9a2a71dc833eb106
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
From dc472d34ed686cba2804f254e3d803904791eaf6 Mon Sep 17 00:00:00 2001
From: Tibor Vass <[email protected]>
Date: Mon, 1 Jun 2020 23:08:25 +0000
Subject: [PATCH 1/5] linux-user: have execve call qemu via /proc/self/exe to
not rely on binfmt_misc

It is assumed that when a guest program calls execve syscall it wants to
execute a program on the same guest architecture and not the host architecture.

Previously, such a guest program would have execve syscall error out with:
"exec format error".

A common solution is to register the qemu binary in binfmt_misc but that is not a
userland-friendly solution, requiring to modify kernel state.

This patch injects /proc/self/exe as the first parameter and the qemu program name
as argv[0] to execve.

Signed-off-by: Tibor Vass <[email protected]>
(cherry picked from commit bc8e2fdae6cd4f9ff1d487056ca3bc598a3187bc)
Signed-off-by: Tibor Vass <[email protected]>
---
linux-user/syscall.c | 35 ++++++++++++++++++++++++++++++-----
1 file changed, 30 insertions(+), 5 deletions(-)

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 95d79ddc43..409686fdca 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -8498,10 +8498,37 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
envc++;
}

- argp = g_new0(char *, argc + 1);
+ argp = g_new0(char *, argc + 4);
envp = g_new0(char *, envc + 1);

- for (gp = guest_argp, q = argp; gp;
+ if (!(p = lock_user_string(arg1)))
+ goto execve_efault;
+
+ /* if pathname is /proc/self/exe then retrieve the path passed to qemu via command line */
+ if (is_proc_myself(p, "exe")) {
+ CPUState *cpu = env_cpu((CPUArchState *)cpu_env);
+ TaskState *ts = cpu->opaque;
+ p = ts->bprm->filename;
+ }
+
+ /* retrieve guest argv0 */
+ if (get_user_ual(addr, guest_argp))
+ goto execve_efault;
+
+ /*
+ * From the guest, the call
+ * execve(pathname, [argv0, argv1], envp)
+ * on the host, becomes:
+ * execve("/proc/self/exe", [qemu_progname, "-0", argv0, pathname, argv1], envp)
+ * where qemu_progname is the error message prefix for qemu
+ */
+ argp[0] = (char*)error_get_progname();
+ argp[1] = (char*)"-0";
+ argp[2] = (char*)lock_user_string(addr);
+ argp[3] = p;
+
+ /* copy guest argv1 onwards to host argv4 onwards */
+ for (gp = guest_argp + 1*sizeof(abi_ulong), q = argp + 4; gp;
gp += sizeof(abi_ulong), q++) {
if (get_user_ual(addr, gp))
goto execve_efault;
@@ -8525,8 +8552,6 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
}
*q = NULL;

- if (!(p = lock_user_string(arg1)))
- goto execve_efault;
/* Although execve() is not an interruptible syscall it is
* a special case where we must use the safe_syscall wrapper:
* if we allow a signal to happen before we make the host
@@ -8537,7 +8562,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
* before the execve completes and makes it the other
* program's problem.
*/
- ret = get_errno(safe_execve(p, argp, envp));
+ ret = get_errno(safe_execve("/proc/self/exe", argp, envp));
unlock_user(p, arg1, 0);

goto execve_end;
--
2.29.2

Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
From 945c7a9e623d915c2e1535894aa90362ed114c08 Mon Sep 17 00:00:00 2001
From: Tibor Vass <[email protected]>
Date: Tue, 2 Jun 2020 10:39:48 +0000
Subject: [PATCH 2/5] linux-user: lookup user program in PATH

Signed-off-by: Tibor Vass <[email protected]>
(cherry picked from commit 1102f3dc7a4db75e72d25b2eab8503f52c44a542)
Signed-off-by: Tibor Vass <[email protected]>
---
linux-user/main.c | 45 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 44 insertions(+), 1 deletion(-)

diff --git a/linux-user/main.c b/linux-user/main.c
index f956afccab..36f0c85957 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -551,6 +551,45 @@ static void usage(int exitcode)
exit(exitcode);
}

+/*
+ * path_lookup searches for an executable filename in the directories named by the PATH environment variable.
+ * Returns a copy of filename if it is an absolute path or could not find a match.
+ * Caller is responsible to free returned string.
+ * Adapted from musl's execvp implementation.
+ */
+static char *path_lookup(char *filename) {
+ const char *p, *z, *path = getenv("PATH");
+ size_t l, k;
+ struct stat buf;
+
+ /* if PATH is not set or filename is absolute path return filename */
+ if (!path || !filename || filename[0] == '/')
+ return strndup(filename, NAME_MAX+1);
+
+ k = strnlen(filename, NAME_MAX+1);
+ if (k > NAME_MAX) {
+ errno = ENAMETOOLONG;
+ return NULL;
+ }
+ l = strnlen(path, PATH_MAX-1)+1;
+
+ for (p = path; ; p = z) {
+ char *b = calloc(l+k+1, sizeof(char));
+ z = strchrnul(p, ':');
+ if (z-p >= l) {
+ if (!*z++) break;
+ continue;
+ }
+ memcpy(b, p, z-p);
+ b[z-p] = '/';
+ memcpy(b+(z-p)+(z>p), filename, k+1);
+ if (!stat(b, &buf) && !(buf.st_mode & S_IFDIR) && (buf.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))
+ return b;
+ if (!*z++) break;
+ }
+ return strndup(filename, NAME_MAX+1);
+}
+
static int parse_args(int argc, char **argv)
{
const char *r;
@@ -616,7 +655,11 @@ static int parse_args(int argc, char **argv)
exit(EXIT_FAILURE);
}

- exec_path = argv[optind];
+ /* not freeing exec_path as it is needed for the lifetime of the process */
+ if (!(exec_path = path_lookup(argv[optind]))) {
+ (void) fprintf(stderr, "qemu: could not find user program %s: %s\n", exec_path, strerror(errno));
+ exit(EXIT_FAILURE);
+ }

return optind;
}
--
2.29.2

Loading

0 comments on commit ee79c56

Please sign in to comment.