From dfc3851bf86679d300b4d0c9ec2796d70dcf1024 Mon Sep 17 00:00:00 2001 From: maxgio92 Date: Wed, 23 Oct 2024 17:27:38 +0200 Subject: [PATCH] fix(bubblewrap_runner): run as build 1000 by default (#1572) * fix(bubblewrap_runner): map host ns uid/gid to 1000 by default Bubblewrap pipeline is run with same uid of the user that run melange, mapped for the child user namespace, leading to possible consistency problems on the resulting package filesystem, while standardizing uid and gid 1000. Furthermore, passwd database is already set for the uid 1000 with name build, instead of the user that is run as, when not explicitely specified. The same applies to the gid map. Signed-off-by: Massimiliano Giovagnoli * chore(bubblewrap_runner): run as build user 1000 by default By default the build user with id 1000 is setup with Apko, so for reproducibility it makes sense to run as 1000 by default, where not explicitely specified RunAs different uid. When the current user that runs melange is root the userns is not unshared and this logic is skipped. This is due to compatibility we need to ensure where arbitrary capabilities may be needed, while otherwise by unsharing the user namespace they all are dropped. Signed-off-by: Massimiliano Giovagnoli Co-Authored-by: Luca Di Maio --------- Signed-off-by: Massimiliano Giovagnoli Co-authored-by: Luca Di Maio --- pkg/container/bubblewrap_runner.go | 14 ++++++- pkg/container/bubblewrap_runner_test.go | 56 +++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 pkg/container/bubblewrap_runner_test.go diff --git a/pkg/container/bubblewrap_runner.go b/pkg/container/bubblewrap_runner.go index 1e127875a..2cda0690d 100644 --- a/pkg/container/bubblewrap_runner.go +++ b/pkg/container/bubblewrap_runner.go @@ -34,7 +34,10 @@ import ( var _ Debugger = (*bubblewrap)(nil) -const BubblewrapName = "bubblewrap" +const ( + BubblewrapName = "bubblewrap" + buildUserID = "1000" +) type bubblewrap struct { remove bool // if true, clean up temp dirs on close. @@ -87,9 +90,18 @@ func (bw *bubblewrap) cmd(ctx context.Context, cfg *Config, debug bool, envOverr "--chdir", runnerWorkdir, "--clearenv") + // If we need to run as an user, we run as that user. if cfg.RunAs != "" { baseargs = append(baseargs, "--unshare-user") baseargs = append(baseargs, "--uid", cfg.RunAs) + baseargs = append(baseargs, "--gid", cfg.RunAs) + // Else if we're not using melange as root, we force the use of the + // Apko build user. This avoids problems on machines where default + // regular user is NOT 1000. + } else if os.Getuid() > 0 { + baseargs = append(baseargs, "--unshare-user") + baseargs = append(baseargs, "--uid", buildUserID) + baseargs = append(baseargs, "--gid", buildUserID) } if !debug { diff --git a/pkg/container/bubblewrap_runner_test.go b/pkg/container/bubblewrap_runner_test.go new file mode 100644 index 000000000..88432e4cb --- /dev/null +++ b/pkg/container/bubblewrap_runner_test.go @@ -0,0 +1,56 @@ +// Copyright 2024 Chainguard, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package container + +import ( + "fmt" + "strings" + "testing" + + "github.com/chainguard-dev/clog/slogtest" +) + +func TestBubblewrapCmd(t *testing.T) { + tests := []struct { + name string + config *Config + expectedArgs string + }{ + { + name: "With default UID and GID", + config: new(Config), + expectedArgs: fmt.Sprintf("--unshare-user --uid %s --gid %s", buildUserID, buildUserID), + }, + { + name: "With config RunAs", + config: &Config{RunAs: "65535"}, + expectedArgs: fmt.Sprintf("--unshare-user --uid %s --gid %s", "65535", "65535"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx := slogtest.Context(t) + args := make([]string, 0) + + cmd := new(bubblewrap).cmd(ctx, tt.config, false, nil, args...) + if cmd.Args == nil { + t.Fatalf("cmd.Args should not be nil") + } + if !strings.Contains(strings.Join(cmd.Args, " "), tt.expectedArgs) { + t.Fatalf("expected %v, found %v", tt.expectedArgs, cmd.Args) + } + }) + } +}