// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019 Facebook
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <linux/filter.h>
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include <bpf/bpf_endian.h>
#include "bpf_util.h"
#include "cgroup_helpers.h"
#include "testing_helpers.h"
#define CG_PATH "/foo"
#define MAX_INSNS 512
#define FIXUP_SYSCTL_VALUE 0
char bpf_log_buf[BPF_LOG_BUF_SIZE];
struct sysctl_test {
const char *descr;
size_t fixup_value_insn;
struct bpf_insn insns[MAX_INSNS];
const char *prog_file;
enum bpf_attach_type attach_type;
const char *sysctl;
int open_flags;
int seek;
const char *newval;
const char *oldval;
enum {
LOAD_REJECT,
ATTACH_REJECT,
OP_EPERM,
SUCCESS,
} result;
};
static struct sysctl_test tests[] = {
{
.descr = "sysctl wrong attach_type",
.insns = {
BPF_MOV64_IMM(BPF_REG_0, 1),
BPF_EXIT_INSN(),
},
.attach_type = 0,
.sysctl = "kernel/ostype",
.open_flags = O_RDONLY,
.result = ATTACH_REJECT,
},
{
.descr = "sysctl:read allow all",
.insns = {
BPF_MOV64_IMM(BPF_REG_0, 1),
BPF_EXIT_INSN(),
},
.attach_type = BPF_CGROUP_SYSCTL,
.sysctl = "kernel/ostype",
.open_flags = O_RDONLY,
.result = SUCCESS,
},
{
.descr = "sysctl:read deny all",
.insns = {
BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_EXIT_INSN(),
},
.attach_type = BPF_CGROUP_SYSCTL,
.sysctl = "kernel/ostype",
.open_flags = O_RDONLY,
.result = OP_EPERM,
},
{
.descr = "ctx:write sysctl:read read ok",
.insns = {
/* If (write) */
BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_1,
offsetof(struct bpf_sysctl, write)),
BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 1, 2),
/* return DENY; */
BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_JMP_A(1),
/* else return ALLOW; */
BPF_MOV64_IMM(BPF_REG_0, 1),
BPF_EXIT_INSN(),
},
.attach_type = BPF_CGROUP_SYSCTL,
.sysctl = "kernel/ostype",
.open_flags = O_RDONLY,
.result = SUCCESS,
},
{
.descr = "ctx:write sysctl:write read ok",
.insns = {
/* If (write) */
BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_1,
offsetof(struct bpf_sysctl, write)),
BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 1, 2),
/* return DENY; */
BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_JMP_A(1),
/* else return ALLOW; */
BPF_MOV64_IMM(BPF_REG_0, 1),
BPF_EXIT_INSN(),
},
.attach_type = BPF_CGROUP_SYSCTL,
.sysctl = "kernel/domainname",
.open_flags = O_WRONLY,
.newval = "(none)", /* same as default, should fail anyway */
.result = OP_EPERM,
},
{
.descr = "ctx:write sysctl:write read ok narrow",
.insns = {
/* u64 w = (u16)write & 1; */
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
BPF_LDX_MEM(BPF_H, BPF_REG_7, BPF_REG_1,
offsetof(struct bpf_sysctl, write)),
#else
BPF_LDX_MEM(BPF_H, BPF_REG_7, BPF_REG_1,
offsetof(struct bpf_sysctl, write) + 2),
#endif
BPF_ALU64_IMM(BPF_AND, BPF_REG_7, 1),
/* return 1 - w; */
BPF_MOV64_IMM(BPF_REG_0, 1),
BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_7),
BPF_EXIT_INSN(),
},
.attach_type = BPF_CGROUP_SYSCTL,
.sysctl = "kernel/domainname",
.open_flags = O_WRONLY,
.newval = "(none)", /* same as default, should fail anyway */
.result = OP_EPERM,
},
{
.descr = "ctx:write sysctl:read write reject",
.insns = {
/* write = X */
BPF_MO
|