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

Container: BPF token support #15009

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

mihalicyn
Copy link
Member

@mihalicyn mihalicyn commented Feb 17, 2025

Good description at https://docs.ebpf.io/linux/concepts/token/

Linux kernel 6.9+ is required for testing

Manual test scenario:

lxc launch ubuntu:oracular o
lxc config set o security.delegate_bpf=true
lxc config set o security.delegate_bpf.progs=socket_filter
lxc shell o
git clone https://github.com/libbpf/libbpf-bootstrap.git
cd libbpf-bootstrap/examples/c
make
./sockfilter
# in another terminal
ping -c 4 localhost

@github-actions github-actions bot added Documentation Documentation needs updating API Changes to the REST API labels Feb 17, 2025
@mihalicyn mihalicyn requested a review from tomponline February 17, 2025 15:48
@mihalicyn mihalicyn marked this pull request as ready for review February 18, 2025 17:03

```

```{config:option} security.delegate_bpf.attachs instance-security
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```{config:option} security.delegate_bpf.attachs instance-security
```{config:option} security.delegate_bpf.attaches instance-security

Not sure about this one but I think it needs an e in the plural form.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I'm just following the naming from the kernel https://github.com/torvalds/linux/blob/2408a807bfc3f738850ef5ad5e3fd59d66168996/kernel/bpf/inode.c#L813

But I agree that attaches looks better :) So let's decide what we want to do here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following the kernel convention feels like less friction, thanks for sharing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or "attach_types"?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

attach_types seems best!

@@ -1071,6 +1071,13 @@ func (d *lxc) initLXC(config bool) (*liblxc.Container, error) {
}
}

if shared.IsTrue(d.expandedConfig["security.delegate_bpf"]) {
err = lxcSetConfigItem(cc, "lxc.hook.start-host", fmt.Sprintf("%s callhook %s %s %s starthost", d.state.OS.ExecPath, shared.VarPath(""), strconv.Quote(d.Project().Name), strconv.Quote(d.Name())))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like that fmt.Sprintf() to be replaced by string concatenation but I understand you might want to leave it as-is as there are other similar line in that file ;)

// IsBpfDelegateOption validates a BPF Token delegation option.
func IsBpfDelegateOption(delegateOption string) func(value string) error {
return func(value string) error {
cdelegateOption := C.CString(fmt.Sprintf("delegate_%s", delegateOption))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
cdelegateOption := C.CString(fmt.Sprintf("delegate_%s", delegateOption))
cdelegateOption := C.CString("delegate_"+delegateOption)

@@ -73,6 +73,15 @@ func HandleContainerHook(lxdPath string, projectName string, instanceRef string,
u := api.NewURL().Path("internal", "containers", instanceRef, "on"+hook)
u.WithQuery("target", target)

if hook == "starthost" {
lxcPID := os.Getenv("LXC_PID")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we lose this validation and instead still call the starthost URL with a missing or blank lxc_pid query parameter, then let LXD validate that its missing, as the error will then be more accessible in the LXD logs rather than in the lxc debug log.

// mountBpfFs mounts bpffs inside the container.
func (d *lxc) mountBpfFs(pid int, bpffsParams map[string]string) error {
if !d.state.OS.BPFToken {
return fmt.Errorf("BPF Token mechanism is not supported by kernel running.")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No full stops on log messages or errors please

bpffsParams["delegate_progs"],
bpffsParams["delegate_attachs"])
if err != nil {
d.logger.Error("bpffs mount helper has failed", logger.Ctx{"err": err, "stdout": stdout})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there potentially useful info in stdout we should be collecting and passing to the end user in err?

// onStartHost implements the LXC start-host hook.
func (d *lxc) onStartHost(args map[string]string) error {
if shared.IsFalseOrEmpty(d.expandedConfig["security.delegate_bpf"]) {
return nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets move the contents of his function from line 2580 into its own function, suggest d.onStartHostBPFDelegate() or similar, and then reverse this if statement's logic to call that function if shared.IsTrue(d.expandedConfig["security.delegate_bpf"]).

That way we nicely structure the general onStartHost function with the BPF delegation logic, allowing for easier future expansion for other purposes.

@@ -866,6 +866,10 @@ func isContainerLowLevelOptionForbidden(key string) bool {
return true
}

if strings.HasPrefix(key, "security.delegate_bpf") {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good thinking!

)

// IsBpfDelegateOption validates a BPF Token delegation option.
func IsBpfDelegateOption(delegateOption string) func(value string) error {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Go's style guide recommends using upper case acronyms in exported functions, so suggest calling this IsBPFDelegationOption - there may be other places in this PR where the same change should occur too.

// IsBpfDelegateOption validates a BPF Token delegation option.
func IsBpfDelegateOption(delegateOption string) func(value string) error {
return func(value string) error {
return fmt.Errorf("This should never be called.")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no full stop in error

Copy link
Member

@tomponline tomponline left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, a few minor suggestions though.

Thanks!

@tomponline
Copy link
Member

@mihalicyn we should also expand our docs to explain this feature and give an example of how to use it.

@tomponline tomponline changed the title bpf token support Container: BPF token support Feb 28, 2025
@@ -2618,3 +2618,7 @@ Note that the `openid` and `email` scopes are always required.
## `project_default_network_and_storage`

Adds flags --network and --storage. The --network flag adds a network device connected to the specified network to the default profile. The --storage flag adds a root disk device using the specified storage pool to the default profile.

## `bpf_delegation`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this is container specific, suggest container_bpf_delegation, similar to container_syscall_intercept_bpf_devices that exists today.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API Changes to the REST API Documentation Documentation needs updating
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants