From 762aa723dc11778b154fc9ddf0c96022b1e26992 Mon Sep 17 00:00:00 2001 From: Shubham Chaudhary Date: Fri, 17 May 2024 11:26:21 +0530 Subject: [PATCH] add mount ns support to nsutil Signed-off-by: Shubham Chaudhary --- .github/workflows/release.yml | 28 +++++++++++++++--- custom/hardened-alpine/experiment/Dockerfile | 3 ++ custom/nsutil/Dockerfile | 13 ++++++++ custom/nsutil/cmd/root.go | 17 +++++++---- custom/nsutil/nsutil.c | 31 ++++++++++++++++++++ go.mod | 1 + go.sum | 3 +- 7 files changed, 86 insertions(+), 10 deletions(-) create mode 100644 custom/nsutil/Dockerfile create mode 100644 custom/nsutil/nsutil.c diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 42934ac1..31cea5d2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,7 +3,7 @@ name: release on: workflow_dispatch: - inputs: + inputs: release_tag: description: 'release tag' required: true @@ -11,7 +11,7 @@ on: description: 'release title' required: false release_notes: - description: 'release notes' + description: 'release notes' required: false default: '' @@ -22,6 +22,11 @@ jobs: steps: - uses: actions/checkout@v2 + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + with: + qemu-version: '6.0.0' + - name: Build go binary for pause run : ./../../build/go-multiarch-build.sh "go build -o ./../../build/_output/pause-linux" working-directory: custom/pause @@ -30,15 +35,30 @@ jobs: run : ./../../build/go-multiarch-build.sh "go build -o ./../../build/_output/nsutil-linux" working-directory: custom/nsutil + - name: Build shared libraries for nsutil amd64 + run: gcc -shared -fPIC nsutil.c -o ./../../build/_output/nsutil_amd64.so + working-directory: custom/nsutil + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + + - name: Build arm64 Docker image + run: docker buildx build --platform linux/arm64 -t myapp-arm64 --load . + working-directory: custom/nsutil + + - name: Extract compiled binary + run: docker create --name myapp-arm64-container myapp-arm64 && docker cp myapp-arm64-container:/app/nsutil.so ./../../build/_output/nsutil_arm64.so + working-directory: custom/nsutil + - name: Build go binary for promql-cli run : | cp custom/promql-cli/promql-linux-amd64 build/_output/ cp custom/promql-cli/promql-linux-arm64 build/_output/ - + - name: Build go binary for dns_interceptor run : go build -o ./../../build/_output/dns_interceptor working-directory: custom/dns_interceptor - + - name: create release along with artifact uses: ncipollo/release-action@v1 with: diff --git a/custom/hardened-alpine/experiment/Dockerfile b/custom/hardened-alpine/experiment/Dockerfile index 2cda60a4..1c8779c6 100644 --- a/custom/hardened-alpine/experiment/Dockerfile +++ b/custom/hardened-alpine/experiment/Dockerfile @@ -60,6 +60,9 @@ RUN curl -L https://github.com/chaosnative/promql-cli/releases/download/3.0.0/pr #Installing nsutil cli binaries RUN curl -L https://github.com/litmuschaos/test-tools/releases/download/${LITMUS_VERSION}/nsutil-linux-${TARGETARCH} --output /usr/local/bin/nsutil && chmod +x /usr/local/bin/nsutil +#Installing nsutil shared lib +RUN curl -L https://github.com/litmuschaos/test-tools/releases/download/${LITMUS_VERSION}/nsutil-${TARGETARCH}.so --output /usr/local/lib/nsutil.so && chmod +x /usr/local/lib/nsutil.so + #Installing pause cli binaries RUN curl -L https://github.com/litmuschaos/test-tools/releases/download/${LITMUS_VERSION}/pause-linux-${TARGETARCH} --output /usr/local/bin/pause && chmod +x /usr/local/bin/pause diff --git a/custom/nsutil/Dockerfile b/custom/nsutil/Dockerfile new file mode 100644 index 00000000..7168ed69 --- /dev/null +++ b/custom/nsutil/Dockerfile @@ -0,0 +1,13 @@ +FROM arm64v8/ubuntu:latest + +# Install gcc for compiling C code +RUN apt-get update && apt-get install -y gcc + +# Set the working directory +WORKDIR /app + +# Copy your C code into the container +COPY nsutil.c /app + +# Compile the C code +RUN gcc -shared -fPIC nsutil.c -o nsutil.so diff --git a/custom/nsutil/cmd/root.go b/custom/nsutil/cmd/root.go index 5c92649f..643feac6 100644 --- a/custom/nsutil/cmd/root.go +++ b/custom/nsutil/cmd/root.go @@ -15,10 +15,12 @@ import ( ) // user and mnt ns not supported -var ns = []string{"net", "pid", "cgroup", "uts", "ipc"} -var nsSelected = make([]bool, 6) - -var t int // target pid +var ( + ns = []string{"net", "pid", "cgroup", "uts", "ipc", "mnt"} + nsSelected = make([]bool, 7) + t int // target pid + libPath string +) // rootCmd represents the base command var rootCmd = &cobra.Command{ @@ -41,7 +43,9 @@ func init() { rootCmd.PersistentFlags().BoolVarP(&nsSelected[2], "cgroup", "c", false, "cgroup namespace to enter") rootCmd.PersistentFlags().BoolVarP(&nsSelected[3], "uts", "u", false, "uts namespace to enter") rootCmd.PersistentFlags().BoolVarP(&nsSelected[4], "ipc", "i", false, "ipc namespace to enter") + rootCmd.PersistentFlags().BoolVarP(&nsSelected[5], "mnt", "m", false, "mnt namespace to enter") rootCmd.PersistentFlags().IntVarP(&t, "target", "t", 0, "target process id (required)") + rootCmd.PersistentFlags().StringVar(&libPath, "lib-path", "/usr/local/lib/nsutil.so", "shared library path to be preloaded") err := rootCmd.MarkPersistentFlagRequired("target") if err != nil { log.WithError(err).Fatal("Failed to mark required flag") @@ -55,6 +59,9 @@ func nsutil(cmd *cobra.Command, args []string) { // target command nCmd := exec.Command(args[0], args[1:]...) nCmd.Env = os.Environ() + if nsSelected[5] { + nCmd.Env = append(nCmd.Env, fmt.Sprintf("LD_PRELOAD=%s", libPath), fmt.Sprintf("MNT_PATH=%s", fmt.Sprintf("/proc/"+strconv.Itoa(t)+"/ns/mnt"))) + } nCmd.Stdin = os.Stdin nCmd.Stdout = os.Stdout nCmd.Stderr = os.Stderr @@ -97,7 +104,7 @@ func nsutil(cmd *cobra.Command, args []string) { func getNSFiles() map[string]*os.File { nsMap := map[string]*os.File{} for i, n := range ns { - if !nsSelected[i] { + if !nsSelected[i] || n == "mnt" { continue } file, err := getFileFromNS("/proc/" + strconv.Itoa(t) + "/ns/" + n) diff --git a/custom/nsutil/nsutil.c b/custom/nsutil/nsutil.c new file mode 100644 index 00000000..5c084304 --- /dev/null +++ b/custom/nsutil/nsutil.c @@ -0,0 +1,31 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +void nsenter() { + char *mnt_path = getenv("MNT_PATH"); + if (mnt_path != NULL) { + int fd = open(mnt_path, O_RDONLY); + if (fd == -1) { + perror("open"); + exit(EXIT_FAILURE); + } + + int ns = setns(fd, 0); + if (ns == -1) { + perror("setns"); + exit(EXIT_FAILURE); + } + } + + unsetenv("LD_PRELOAD"); +} + +__attribute__((constructor)) void ctor() { + nsenter(); +} diff --git a/go.mod b/go.mod index 7ff7be8b..ac959dae 100644 --- a/go.mod +++ b/go.mod @@ -12,4 +12,5 @@ require ( golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 // indirect golang.org/x/text v0.3.7 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 3d894085..dc4dd7d1 100644 --- a/go.sum +++ b/go.sum @@ -20,5 +20,6 @@ golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=