bpf(2): return EPERM for unsupported BPF commands without CAP_SYS_ADMIN.

Matches Linux more closely.

PiperOrigin-RevId: 958490279
This commit is contained in:
Ryan El Kochta
2026-08-03 11:39:54 -07:00
committed by gVisor bot
parent 86be803f8a
commit 9f46059b08
2 changed files with 31 additions and 11 deletions
+14 -9
View File
@@ -334,27 +334,32 @@ func Bpf(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *k
return 0, nil, err
}
switch cmd {
case linux.BPF_PROG_LOAD:
fd, err := bpfProgLoad(t, attr.(*linux.BPFAttrProgLoad))
switch attr := attr.(type) {
case *linux.BPFAttrProgLoad:
fd, err := bpfProgLoad(t, attr)
return fd, nil, err
case linux.BPF_PROG_QUERY:
attr := attr.(*linux.BPFAttrProgQuery)
case *linux.BPFAttrProgQuery:
size := min(int(size), attr.SizeBytes())
ret, err := bpfProgQuery(t, attr, attrAddr, size)
return ret, nil, err
case linux.BPF_PROG_ATTACH:
ret, err := bpfProgAttach(t, attr.(*linux.BPFAttrProgAttach))
case *linux.BPFAttrProgAttach:
ret, err := bpfProgAttach(t, attr)
return ret, nil, err
default:
// Unsupported command
// Unsupported command.
if !t.HasRootCapability(linux.CAP_SYS_ADMIN) {
return 0, nil, linuxerr.EPERM
}
return 0, nil, linuxerr.EINVAL
}
}
// copyInBPFAttr fetches and returns a BPFAttr of the type specified by cmd from userspace.
//
// If cmd is invalid or unsupported, the nil BPFAttr is returned (along with no error).
func copyInBPFAttr(t *kernel.Task, cmd int32, addr hostarch.Addr, size int) (linux.BPFAttr, error) {
// Invalid size. Negative size here would indicate overflow
if size < 0 || size > hostarch.PageSize {
@@ -370,7 +375,7 @@ func copyInBPFAttr(t *kernel.Task, cmd int32, addr hostarch.Addr, size int) (lin
case linux.BPF_PROG_ATTACH:
bpfAttr = &linux.BPFAttrProgAttach{}
default:
return nil, linuxerr.EINVAL
return nil, nil
}
// Copy in the valid fields of the BPFAttr structure
+17 -2
View File
@@ -623,12 +623,27 @@ TEST_F(EbpfTest, QueryRequiresCapability) {
// bpf(2) argument handling
TEST_F(EbpfTest, InvalidCommandFails) {
TEST_F(EbpfTest, UnimplementedCommandWithCapFails) {
SKIP_IF(!IsRunningOnGvisor());
// Unimplemented cmd with capabilities should give EINVAL.
BpfAttrProgAttach attr = {};
EXPECT_THAT(bpf(0x7fffffff, &attr, sizeof(attr)),
EXPECT_THAT(bpf(BPF_MAP_CREATE, &attr, sizeof(attr)),
SyscallFailsWithErrno(EINVAL));
}
TEST_F(EbpfTest, UnimplementedCommandWithoutCapFails) {
SKIP_IF(!IsRunningOnGvisor());
AutoCapability cap_sys_admin(CAP_SYS_ADMIN, false);
AutoCapability cap_bpf(CAP_BPF, false);
// Unimplemented cmd without capabilities should give EPERM.
BpfAttrProgAttach attr = {};
EXPECT_THAT(bpf(BPF_MAP_CREATE, &attr, sizeof(attr)),
SyscallFailsWithErrno(EPERM));
}
TEST_F(EbpfTest, AttrSizeTooLargeFails) {
BpfAttrProgAttach attr = {};
EXPECT_THAT(bpf(BPF_PROG_ATTACH, &attr, 1 << 20),