Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update patches loading to support v6.1.0 and cpu-max #58

Merged
merged 3 commits into from
Sep 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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