-
Notifications
You must be signed in to change notification settings - Fork 6
feat: Add namespace isolation support for proxy processes #7
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
Changes from 19 commits
b56d626
c8f0026
670e0a4
d57170c
3736da6
aad47da
9649e44
f46b9d3
9c568d3
bb81f30
e6e1e51
b1cc94f
6fb1977
8f01ce8
f534a7f
827a7ac
654d472
34c5ff1
a4bf97d
bee0dcf
6663003
959ee9e
4b743a2
e0838bb
b39e1ea
3800ba8
379ef50
2974a96
913f822
f7bb9d7
3429464
fe5a97d
f96f1ad
a31f40c
5d5b162
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,17 +11,19 @@ BINARIES=() | |
|
|
||
| usage() { | ||
| echo "Usage: $0 <template> <mount-dir> <build-context> <binary1> [binary2] ..." >&2 | ||
| echo " template: Lima template to use (docker or podman)" >&2 | ||
| echo " template: Lima template to use (docker, podman, or alpine)" >&2 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is quite confusing as docker and podman is a linux package while alpine is a linux distribution. It make the concept 'template' very broad and as a result vague. I think we need two separate
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I kind of agree, but at the same time that would involve us redefining a template; which I would definitely not want to do for a test. The templates are called 'docker', 'podman', or 'alpine', by lima. I think adding extra abstraction on top here might be excessive YAGNI, IMO. |
||
| echo " mount-dir: Directory attached in the vm" >&2 | ||
| echo " build-context: Build context directory for test-image build" >&2 | ||
| echo " binary1...N: Path to binaries to install in /usr/local/bin" >&2 | ||
| exit 1 | ||
| } | ||
|
|
||
| validate_inputs() { | ||
| if [ ! -d "$BUILD_CONTEXT" ]; then | ||
| echo "Error: Build context directory not found: $BUILD_CONTEXT" >&2 | ||
| exit 1 | ||
| if [ "$TEMPLATE" = "docker" ] || [ "$TEMPLATE" = "podman" ]; then | ||
| if [ ! -d "$BUILD_CONTEXT" ]; then | ||
| echo "Error: Build context directory not found: $BUILD_CONTEXT" >&2 | ||
| exit 1 | ||
| fi | ||
| fi | ||
|
|
||
| for binary in "${BINARIES[@]}"; do | ||
|
|
@@ -58,7 +60,13 @@ start_vm() { | |
| install_binary() { | ||
| local source_path="$1" | ||
| local binary_name="$2" | ||
| local dest_path="/usr/local/bin/$binary_name" | ||
| local dest_dir="/usr/local/bin" | ||
|
|
||
| if [ "$TEMPLATE" = "alpine" ]; then | ||
| dest_dir="/usr/bin" | ||
| fi | ||
|
|
||
| local dest_path="$dest_dir/$binary_name" | ||
|
|
||
| echo "Installing $binary_name..." >&2 | ||
|
|
||
|
|
@@ -115,6 +123,12 @@ build_image() { | |
| exit 1 | ||
| fi | ||
| ;; | ||
| ""|none) | ||
| echo "Skipping image build (no build context provided)" >&2 | ||
| ;; | ||
| alpine) | ||
| echo "Skipping image build for alpine template" >&2 | ||
| ;; | ||
| *) | ||
| echo "Error: Unsupported template '$TEMPLATE'. Only 'docker' and 'podman' are supported." >&2 | ||
| cleanup_on_failure | ||
|
|
@@ -149,7 +163,9 @@ main() { | |
| install_binary "$binary_path" "$binary_name" | ||
| done | ||
|
|
||
| build_image | ||
| if [ -n "$BUILD_CONTEXT" ] || [ "$TEMPLATE" = "docker" ] || [ "$TEMPLATE" = "podman" ]; then | ||
| build_image | ||
| fi | ||
|
|
||
| echo "VM setup completed successfully" >&2 | ||
|
|
||
|
|
||
|
Luke-Parkin marked this conversation as resolved.
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| package proxy | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "log/slog" | ||
|
|
||
| "github.com/opencontainers/runtime-spec/specs-go" | ||
| "golang.org/x/sys/unix" | ||
| ) | ||
|
|
||
| var specNamespacesToUnixCloneFlags = map[specs.LinuxNamespaceType]uintptr{ | ||
| specs.CgroupNamespace: unix.CLONE_NEWCGROUP, | ||
| specs.IPCNamespace: unix.CLONE_NEWIPC, | ||
| specs.MountNamespace: unix.CLONE_NEWNS, | ||
| specs.NetworkNamespace: unix.CLONE_NEWNET, | ||
| specs.PIDNamespace: unix.CLONE_NEWPID, | ||
| specs.TimeNamespace: unix.CLONE_NEWTIME, | ||
| specs.UserNamespace: unix.CLONE_NEWUSER, | ||
| specs.UTSNamespace: unix.CLONE_NEWUTS, | ||
| } | ||
|
|
||
| func ParseNamespaceFlags(namespaces []specs.LinuxNamespace) (uintptr, error) { | ||
| if namespaces == nil { | ||
| return 0, nil | ||
| } | ||
|
|
||
| var flags uintptr | ||
| for _, ns := range namespaces { | ||
| if ns.Path != "" { | ||
| continue | ||
| } | ||
| flag, ok := specNamespacesToUnixCloneFlags[ns.Type] | ||
| if !ok { | ||
| err := fmt.Errorf("unknown namespace type %q", ns.Type) | ||
| return 0, err | ||
| } | ||
| flags |= flag | ||
| } | ||
| return flags, nil | ||
| } | ||
|
|
||
| func LinuxCloneFlags(logger *slog.Logger, isRoot bool, namespaces []specs.LinuxNamespace) (uintptr, error) { | ||
| flags, err := ParseNamespaceFlags(namespaces) | ||
| if err != nil { | ||
| return 0, err | ||
| } | ||
|
|
||
| if !isRoot && flags != 0 { | ||
|
Luke-Parkin marked this conversation as resolved.
|
||
| logger.Warn("running non-root; namespace isolation disabled") | ||
|
yejseo01 marked this conversation as resolved.
|
||
| return 0, nil | ||
| } | ||
|
|
||
| return flags, nil | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| package proxy_test | ||
|
muchzill4 marked this conversation as resolved.
|
||
|
|
||
| import ( | ||
| "io" | ||
| "log/slog" | ||
| "testing" | ||
|
|
||
| proxy "github.com/arm/remoteproc-runtime/internal/proxy" | ||
| "github.com/opencontainers/runtime-spec/specs-go" | ||
| "github.com/stretchr/testify/require" | ||
| "golang.org/x/sys/unix" | ||
| ) | ||
|
|
||
| func TestLinuxCloneFlags(t *testing.T) { | ||
| t.Run("converts known linux namespace flags to unix", func(t *testing.T) { | ||
| isRoot := true | ||
| namespaces := []specs.LinuxNamespace{ | ||
| {Type: specs.CgroupNamespace}, | ||
| {Type: specs.UserNamespace}, | ||
| } | ||
|
|
||
|
Luke-Parkin marked this conversation as resolved.
Outdated
|
||
| logger := slog.New(slog.NewTextHandler(io.Discard, nil)) | ||
|
|
||
| got, err := proxy.LinuxCloneFlags(logger, isRoot, namespaces) | ||
|
|
||
| require.NoError(t, err) | ||
| want := uintptr(unix.CLONE_NEWCGROUP | unix.CLONE_NEWUSER) | ||
| require.Equal(t, want, got) | ||
| }) | ||
|
|
||
| t.Run("non-root disables cloning", func(t *testing.T) { | ||
| isRoot := false | ||
| namespaces := []specs.LinuxNamespace{ | ||
| {Type: specs.CgroupNamespace}, | ||
| {Type: specs.UserNamespace}, | ||
| } | ||
|
|
||
| logger := slog.New(slog.NewTextHandler(io.Discard, nil)) | ||
|
|
||
| got, err := proxy.LinuxCloneFlags(logger, isRoot, namespaces) | ||
|
|
||
| require.NoError(t, err) | ||
| require.Equal(t, uintptr(0), got) | ||
| }) | ||
|
|
||
| t.Run("errors given unknown namespace", func(t *testing.T) { | ||
| isRoot := true | ||
| namespaces := []specs.LinuxNamespace{ | ||
| {Type: specs.LinuxNamespaceType("weird-name")}, | ||
| } | ||
|
|
||
| logger := slog.New(slog.NewTextHandler(io.Discard, nil)) | ||
|
|
||
| _, err := proxy.LinuxCloneFlags(logger, isRoot, namespaces) | ||
|
|
||
| require.Error(t, err) | ||
| }) | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.