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

Add support for escaping resolv.conf symlinks #318

Merged
merged 3 commits into from
Aug 17, 2023
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
19 changes: 10 additions & 9 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,22 @@ on:

jobs:
release:
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- uses: docker/setup-buildx-action@v1
- uses: docker/setup-qemu-action@v2
- uses: docker/setup-buildx-action@v2
- name: "Build binaries from Dockerfile.artifact"
run: docker buildx build -o /tmp --platform=amd64,arm64,arm,s390x,ppc64le,riscv64 -f Dockerfile.artifact .
run: docker buildx build -o /tmp/slirpbuilds --platform=amd64,arm64,arm,s390x,ppc64le,riscv64 -f Dockerfile.artifact .
- name: "Create /tmp/artifact"
run: |
mkdir -p /tmp/artifact
mv /tmp/linux_amd64/slirp4netns /tmp/artifact/slirp4netns-x86_64
mv /tmp/linux_arm64/slirp4netns /tmp/artifact/slirp4netns-aarch64
mv /tmp/linux_arm_v7/slirp4netns /tmp/artifact/slirp4netns-armv7l
mv /tmp/linux_s390x/slirp4netns /tmp/artifact/slirp4netns-s390x
mv /tmp/linux_ppc64le/slirp4netns /tmp/artifact/slirp4netns-ppc64le
mv /tmp/linux_riscv64/slirp4netns /tmp/artifact/slirp4netns-riscv64
mv /tmp/slirpbuilds/linux_amd64/slirp4netns /tmp/artifact/slirp4netns-x86_64
mv /tmp/slirpbuilds/linux_arm64/slirp4netns /tmp/artifact/slirp4netns-aarch64
mv /tmp/slirpbuilds/linux_arm_v7/slirp4netns /tmp/artifact/slirp4netns-armv7l
mv /tmp/slirpbuilds/linux_s390x/slirp4netns /tmp/artifact/slirp4netns-s390x
mv /tmp/slirpbuilds/linux_ppc64le/slirp4netns /tmp/artifact/slirp4netns-ppc64le
mv /tmp/slirpbuilds/linux_riscv64/slirp4netns /tmp/artifact/slirp4netns-riscv64
- name: "SHA256SUMS"
run: (cd /tmp/artifact; sha256sum *) | tee /tmp/SHA256SUMS
- name: "The sha256sum of the SHA256SUMS file"
Expand Down
6 changes: 3 additions & 3 deletions Dockerfile.buildtests
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ ARG LIBSLIRP_COMMIT=v4.7.0
# Alpine
FROM alpine:3 AS buildtest-alpine3-static
RUN apk add --no-cache git build-base autoconf automake libtool linux-headers glib-dev glib-static libcap-static libcap-dev libseccomp-dev libseccomp-static git meson
RUN git clone git://git.qemu.org/libslirp.git /libslirp
RUN git clone https://git.qemu.org/libslirp.git /libslirp
WORKDIR /libslirp
ARG LIBSLIRP_COMMIT
RUN git pull && git checkout ${LIBSLIRP_COMMIT} && meson setup --default-library=both build && ninja -C build install
Expand All @@ -16,7 +16,7 @@ FROM ubuntu:18.04 AS buildtest-ubuntu1804-common
ENV DEBIAN_FRONTEND=noninteractive
RUN apt update && apt install -y automake autotools-dev make gcc libglib2.0-dev libcap-dev libseccomp-dev git ninja-build python3-pip
RUN pip3 install meson
RUN git clone git://git.qemu.org/libslirp.git /libslirp
RUN git clone https://git.qemu.org/libslirp.git /libslirp
WORKDIR /libslirp
ARG LIBSLIRP_COMMIT
RUN git pull && git checkout ${LIBSLIRP_COMMIT} && meson setup build && ninja -C build install
Expand All @@ -34,7 +34,7 @@ RUN ./configure && make && cp -f slirp4netns /
FROM opensuse/leap:15 AS buildtest-opensuse15-common
RUN zypper install -y --no-recommends autoconf automake gcc glib2-devel git make libcap-devel libseccomp-devel ninja python3-pip
RUN pip3 install meson
RUN git clone git://git.qemu.org/libslirp.git /libslirp
RUN git clone https://git.qemu.org/libslirp.git /libslirp
WORKDIR /libslirp
ARG LIBSLIRP_COMMIT
RUN git pull && git checkout ${LIBSLIRP_COMMIT} && meson setup --default-library=both build && ninja -C build install
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile.tests
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ FROM ubuntu:22.04 AS build
ENV DEBIAN_FRONTEND=noninteractive
RUN apt update && apt install -y automake autotools-dev make gcc libglib2.0-dev libcap-dev libseccomp-dev git ninja-build python3-pip
RUN pip3 install meson
RUN git clone git://git.qemu.org/libslirp.git /libslirp
RUN git clone https://git.qemu.org/libslirp.git /libslirp
WORKDIR /libslirp
ARG LIBSLIRP_COMMIT
RUN git pull && git checkout ${LIBSLIRP_COMMIT} && meson setup build && ninja -C build install
Expand Down
2 changes: 1 addition & 1 deletion Vagrantfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Vagrant.configure("2") do |config|
git clone --depth=1 --no-checkout https://github.com/seccomp/libseccomp
git -C ./libseccomp fetch --tags --depth=1

git clone --depth=1 --no-checkout git://git.qemu.org/libslirp.git
git clone --depth=1 --no-checkout https://git.qemu.org/libslirp.git
git -C ./libslirp fetch --tags --depth=1

touch ./build-and-test
Expand Down
66 changes: 52 additions & 14 deletions sandbox.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
Expand All @@ -27,7 +28,8 @@ static int add_mount(const char *from, const char *to)
MS_BIND | MS_REC | MS_SLAVE | MS_NOSUID | MS_NODEV | MS_NOEXEC,
NULL);
if (ret < 0) {
fprintf(stderr, "cannot bind mount %s to %s\n", from, to);
fprintf(stderr, "cannot bind mount %s to %s (errno: %d)\n", from, to,
errno);
return ret;
}
ret = mount("", to, "", MS_SLAVE | MS_REC, NULL);
Expand All @@ -46,21 +48,54 @@ static int add_mount(const char *from, const char *to)
return 0;
}

/* Warn (not error) if /etc/resolv.conf is a symlink to a file outside /etc or
/* Bind /etc/resolv.conf if it is a symlink to a file outside /etc or
* /run. */
static void validate_etc_resolv_conf()
static int bind_escaped_resolv_conf(const char *root)
{
char *p = realpath("/etc/resolv.conf", NULL);
if (p == NULL) {
return;
char *real_resolv = realpath("/etc/resolv.conf", NULL);

/* Doesn't exist or is not an escaping symlink */
if (real_resolv == NULL || g_str_has_prefix(real_resolv, "/etc") ||
g_str_has_prefix(real_resolv, "/run")) {
free(real_resolv);
return 0;
}

char *resolv_dest = g_strconcat(root, real_resolv, NULL);
char *resolv_dest_dir = g_path_get_dirname(resolv_dest);
int ret = 0;

fprintf(stderr,
"sandbox: /etc/resolv.conf (-> %s) seems a symlink to a file "
"outside {/etc, /run}, attempting to bind it as well.\n",
real_resolv);

ret = g_mkdir_with_parents(resolv_dest_dir, 0755);
if (ret < 0) {
fprintf(stderr, "cannot create resolve dest dir path: %s\n",
resolv_dest_dir);
goto finish;
}

ret = creat(resolv_dest, 0644);
if (ret < 0) {
fprintf(stderr, "cannot create empty resolv.conf dest file %s\n",
resolv_dest);
goto finish;
}
if (!g_str_has_prefix(p, "/etc") && !g_str_has_prefix(p, "/run")) {
fprintf(stderr,
"sandbox: /etc/resolv.conf (-> %s) seems a symlink to a file "
"outside {/etc, /run}. DNS will not work.\n",
p);
close(ret);

ret = add_mount(real_resolv, resolv_dest);
if (ret < 0) {
fprintf(stderr, "cannot bind mount resolv.conf\n");
}
free(p);

finish:

free(real_resolv);
g_free(resolv_dest);
g_free(resolv_dest_dir);
return ret;
}

/* lock down the process doing the following:
Expand All @@ -75,8 +110,6 @@ int create_sandbox()
struct __user_cap_header_struct hdr = { _LINUX_CAPABILITY_VERSION_3, 0 };
struct __user_cap_data_struct data[2] = { { 0 } };

validate_etc_resolv_conf();

ret = unshare(CLONE_NEWNS);
if (ret < 0) {
fprintf(stderr, "cannot unshare new mount namespace\n");
Expand Down Expand Up @@ -118,6 +151,11 @@ int create_sandbox()
return ret;
}

ret = bind_escaped_resolv_conf("/tmp");
if (ret < 0) {
return ret;
}

ret = add_mount("/run", "/tmp/run");
if (ret < 0) {
return ret;
Expand Down