Program type BPF_PROG_TYPE_CGROUP_DEVICE
cGroup device programs are executed when a process in the cGroup to which the program is attached wishes to utilize a device. The program can then decide whether or not to allow the process to allow that operation.
Usage
This program type is the cGroup v2 variant of the device whitelist controller. This program type is typically located in a cgroup/dev
ELF section. It is called with a context describing the access attempt, if the program returns 0
, the attempt fails with -EPERM
, otherwise it succeeds.
Context
The program takes a pointer to the bpf_cgroup_dev_ctx
structure, which describes the device access attempt: access type (mknod/read/write) and device (type, major and minor numbers). If the program returns 0, the attempt fails with -EPERM
, otherwise it succeeds.
struct bpf_cgroup_dev_ctx {
/* access_type encoded as (BPF_DEVCG_ACC_* << 16) | BPF_DEVCG_DEV_* */
__u32 access_type;
__u32 major;
__u32 minor;
};
enum {
BPF_DEVCG_ACC_MKNOD = (1ULL << 0),
BPF_DEVCG_ACC_READ = (1ULL << 1),
BPF_DEVCG_ACC_WRITE = (1ULL << 2),
};
enum {
BPF_DEVCG_DEV_BLOCK = (1ULL << 0),
BPF_DEVCG_DEV_CHAR = (1ULL << 1),
};
Attachment
cGroup socket buffer programs are attached to cGroups via the BPF_PROG_ATTACH
syscall or via BPF link.
Example
Example BPF program:
/* Copyright (c) 2017 Facebook
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*/
#include <linux/bpf.h>
#include <linux/version.h>
#include <bpf/bpf_helpers.h>
SEC("cgroup/dev")
int bpf_prog1(struct bpf_cgroup_dev_ctx *ctx)
{
short type = ctx->access_type & 0xFFFF;
#ifdef DEBUG
short access = ctx->access_type >> 16;
char fmt[] = " %d:%d \n";
switch (type) {
case BPF_DEVCG_DEV_BLOCK:
fmt[0] = 'b';
break;
case BPF_DEVCG_DEV_CHAR:
fmt[0] = 'c';
break;
default:
fmt[0] = '?';
break;
}
if (access & BPF_DEVCG_ACC_READ)
fmt[8] = 'r';
if (access & BPF_DEVCG_ACC_WRITE)
fmt[9] = 'w';
if (access & BPF_DEVCG_ACC_MKNOD)
fmt[10] = 'm';
bpf_trace_printk(fmt, sizeof(fmt), ctx->major, ctx->minor);
#endif
/* Allow access to /dev/zero and /dev/random.
* Forbid everything else.
*/
if (ctx->major != 1 || type != BPF_DEVCG_DEV_CHAR)
return 0;
switch (ctx->minor) {
case 5: /* 1:5 /dev/zero */
case 9: /* 1:9 /dev/urandom */
return 1;
}
return 0;
}
char _license[] SEC("license") = "GPL";
Helper functions
Supported helper functions
bpf_cgrp_storage_delete
bpf_cgrp_storage_get
bpf_dynptr_data
bpf_dynptr_from_mem
bpf_dynptr_read
bpf_dynptr_write
bpf_for_each_map_elem
bpf_get_current_cgroup_id
bpf_get_current_task
bpf_get_current_task_btf
bpf_get_current_uid_gid
bpf_get_local_storage
bpf_get_numa_node_id
bpf_get_prandom_u32
bpf_get_retval
bpf_get_smp_processor_id
bpf_jiffies64
bpf_kptr_xchg
bpf_ktime_get_boot_ns
bpf_ktime_get_ns
bpf_ktime_get_tai_ns
bpf_loop
bpf_map_delete_elem
bpf_map_lookup_elem
bpf_map_lookup_percpu_elem
bpf_map_peek_elem
bpf_map_pop_elem
bpf_map_push_elem
bpf_map_update_elem
bpf_per_cpu_ptr
bpf_perf_event_output
bpf_probe_read_kernel
bpf_probe_read_kernel_str
bpf_probe_read_user
bpf_probe_read_user_str
bpf_ringbuf_discard
bpf_ringbuf_discard_dynptr
bpf_ringbuf_output
bpf_ringbuf_query
bpf_ringbuf_reserve
bpf_ringbuf_reserve_dynptr
bpf_ringbuf_submit
bpf_ringbuf_submit_dynptr
bpf_set_retval
bpf_snprintf
bpf_snprintf_btf
bpf_spin_lock
bpf_spin_unlock
bpf_strncmp
bpf_tail_call
bpf_task_pt_regs
bpf_this_cpu_ptr
bpf_timer_cancel
bpf_timer_init
bpf_timer_set_callback
bpf_timer_start
bpf_trace_printk
bpf_trace_vprintk
bpf_user_ringbuf_drain
KFuncs
There are currently no kfuncs supported for this program type