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 adding capabilities #156

Draft
wants to merge 26 commits into
base: master
Choose a base branch
from

Conversation

ulrikstrid
Copy link

@ulrikstrid ulrikstrid commented Nov 13, 2024

This is very hacky, just wanted to push before I close for the day. It needs a lot of cleanup when it finally works.

I'm not a Go programmer at all so excuse the quality. I tried basing the changes on the perms feature which seems like it's quite similar in use.

This doesn't seem to work as expected as when it's untared it doesn't have the correct capabilities. But I do have a small Go program to test that the bytes seems to be generated correctly, so I assume it's a question of trying to figure out what format the string should be in.

package main

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"os"
	"syscall"
)

func main() {
    if len(os.Args) != 2 {
        fmt.Printf("Usage: %s <filepath>\n", os.Args[0])
        os.Exit(1)
    }
    filepath := os.Args[1]

    // Version 3 capability format
    // struct vfs_cap_data {
    //     __le32 magic_etc;            /* magic, version and flags */
    //     struct {
    //         __le32 permitted;        /* permitted capabilities */
    //         __le32 inheritable;      /* inheritable capabilities */
    //     } data[2];                   /* realistically, one is enough */
    //     __le32 effective;            /* effective capabilities */
    // };
		type vfsNsCapData struct {
			MagicEtc uint32
			Data     [2]struct {
				Permitted   uint32
				Inheritable uint32
			}
			Effective uint32
		}

		const vfsCapRevision3 = 0x03000000

		data := vfsNsCapData{MagicEtc: vfsCapRevision3 | uint32(0)}

		data.Data[0].Permitted = uint32(10)
		data.Data[0].Inheritable = uint32(10)
		data.Data[1].Permitted = uint32(10 >> 32)
		data.Data[1].Inheritable = uint32(10 >> 32)
		data.Effective = uint32(10)

		fmt.Printf("Failed to write buffer: %v\n", data)


    buf := &bytes.Buffer{}
		if err := binary.Write(buf, binary.LittleEndian, data); err != nil {
			fmt.Printf("Failed to write buffer: %v\n", err)
			os.Exit(1)
		}

    capBytes := buf.Bytes()

		fmt.Printf("capBytes: %v\n", capBytes)

    // Set the extended attribute
    err := syscall.Setxattr(filepath, "security.capability", capBytes, 0)
    if err != nil {
        fmt.Printf("Failed to set capability: %v\n", err)
        os.Exit(1)
    }

    fmt.Printf("Successfully set CAP_NET_BIND_SERVICE capability on %s\n", filepath)
}

@ulrikstrid
Copy link
Author

This is now technically working for my use case. It would have to become generic and probably a lot of cleanup before we can merge it. But I'm now unblocked from shipping my container.

@ulrikstrid
Copy link
Author

I ended up not needing this because I could solve it at another level. If you want to close this that's fine, otherwise I'll try to get back to it when I have some more time and do the clean-up and generalisation.

@nlewo
Copy link
Owner

nlewo commented Nov 15, 2024

@ulrikstrid oh, that's unfortunate you no longer need this because this is pretty interesting!
But if someone else is interested in, this dratf will be pretty useful since 80% of the job is implemented.

Excepting supporting user specified capabilities (not only CAP_NET_BIND_SERVICE), only tests are missing I think.

@ulrikstrid
Copy link
Author

If you're open to keeping the PR around I'm willing to fix it, just at a slower pace 😊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants