Skip to content

Commit

Permalink
sched/ghost: add BPF helpers for get_affinity and get_comm
Browse files Browse the repository at this point in the history
These are analogous to syscalls like sched_getaffinity() and
prctl(PR_GET_NAME).

Change-Id: If96baf46c7362f3846883e34cd06dbf0450b16e0
  • Loading branch information
Barret Rhoden authored and dohyunkim-dev committed Nov 8, 2023
1 parent 74a1c8f commit edd5f94
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 1 deletion.
18 changes: 18 additions & 0 deletions include/uapi/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -4079,6 +4079,22 @@ enum bpf_func_id {
*
* Return
* 0 on success, < 0 on error.
*
* long bpf_ghost_get_affinity(s64 gtid, u8 *mask, u32 size)
* Description
* Copies the gtid's cpu_mask (a.k.a. cpus_allowed) into mask.
*
* Return
* Number of valid cpu bits in the mask (a.k.a. nr_cpu_ids), < 0 on
* error. If the user-provided mask is smaller than the cpu_mask,
* returns -E2BIG.
*
* long bpf_ghost_get_comm(s64 gtid, char *buf, u32 size)
* Description
* Copies up to size bytes of the gtid's comm into buf.
*
* Return
* 0 on success, < 0 on error.
*/
enum {
__BPF_FUNC_GHOST_BASE = 3000,
Expand All @@ -4087,6 +4103,8 @@ enum {
BPF_FUNC_ghost_resched_cpu,
BPF_FUNC_ghost_resched_cpu2,
BPF_FUNC_ghost_sync_commit,
BPF_FUNC_ghost_get_affinity,
BPF_FUNC_ghost_get_comm,
__BPF_FUNC_GHOST_MAX_ID,
};

Expand Down
2 changes: 1 addition & 1 deletion include/uapi/linux/ghost.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
* process are the same version as each other. Each successive version changes
* values in this header file, assumptions about operations in the kernel, etc.
*/
#define GHOST_VERSION 90
#define GHOST_VERSION 91

/*
* Define SCHED_GHOST via the ghost uapi unless it has already been defined
Expand Down
68 changes: 68 additions & 0 deletions kernel/sched/ghost.c
Original file line number Diff line number Diff line change
Expand Up @@ -8741,6 +8741,72 @@ static int bpf_resched_cpu2(int cpu, int flags)
return 0;
}

static int bpf_get_affinity(gtid_t gtid, u8 *mask, u32 size)
{
struct task_struct *p;
size_t nr_bytes;
int err;

rcu_read_lock();
p = find_task_by_gtid(gtid);
if (!p) {
rcu_read_unlock();
err = -ENOENT;
goto err_clear;
}

/* cpumask_copy() is essentially a memcpy of nr_cpumask_bits */
nr_bytes = BITS_TO_BYTES(nr_cpumask_bits);
if (nr_bytes > size) {
rcu_read_unlock();
err = -E2BIG;
goto err_clear;
}
/*
* Note this is a racy read. It's up to our caller to provide
* synchronization or to deal with concurrent modifications. Typically,
* the caller will be from bpf-msg which often holds the pi_lock
* already (part of task_rq_lock()), and sched_getaffinity() grabs the
* pi_lock.
*/
memcpy(mask, cpumask_bits(p->cpus_ptr), nr_bytes);
memset(mask + nr_bytes, 0, size - nr_bytes);
rcu_read_unlock();

/*
* Recall that nr_cpu_ids is the number of valid bits in the mask, i.e.
* you shouldn't look at the bits in the mask beyond nr_cpu_ids. If
* !CONFIG_CPUMASK_OFFSTACK, nr_cpumask_bits is NR_CPUS, which may be
* more than nr_cpu_ids.
*/
return nr_cpu_ids;

err_clear:
memset(mask, 0, size);
return err;
}

static int bpf_get_comm(gtid_t gtid, char *buf, u32 size)
{
struct task_struct *p;
char comm[TASK_COMM_LEN];

rcu_read_lock();
p = find_task_by_gtid(gtid);
if (!p) {
rcu_read_unlock();
goto err_clear;
}
get_task_comm(comm, p);
rcu_read_unlock();
strscpy_pad(buf, comm, size);
return 0;

err_clear:
memset(buf, 0, size);
return -ENOENT;
}

static bool ghost_sched_is_valid_access(int off, int size,
enum bpf_access_type type,
const struct bpf_prog *prog,
Expand Down Expand Up @@ -9173,6 +9239,8 @@ DEFINE_GHOST_ABI(current_abi) = {
.bpf_wake_agent = bpf_wake_agent,
.bpf_run_gtid = bpf_run_gtid,
.bpf_resched_cpu2 = bpf_resched_cpu2,
.bpf_get_affinity = bpf_get_affinity,
.bpf_get_comm = bpf_get_comm,
.ghost_sched_is_valid_access = ghost_sched_is_valid_access,
.ghost_msg_is_valid_access = ghost_msg_is_valid_access,
.ghost_select_rq_is_valid_access = ghost_select_rq_is_valid_access,
Expand Down
70 changes: 70 additions & 0 deletions kernel/sched/ghost_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1354,6 +1354,72 @@ static const struct bpf_func_proto bpf_ghost_resched_cpu2_proto = {
.arg2_type = ARG_ANYTHING,
};

BPF_CALL_3(bpf_ghost_get_affinity, s64, gtid, u8 *, mask, u32, size)
{
struct ghost_enclave *e;

VM_BUG_ON(preemptible());

BUILD_BUG_ON(BPF_FUNC_ghost_get_affinity != 3005);

e = get_target_enclave();

/* Paranoia: this is not expected */
if (WARN_ON_ONCE(!e))
return -ENODEV;

if (!e->abi->bpf_get_affinity)
return -ENOSYS;

return e->abi->bpf_get_affinity(gtid, mask, size);
}

static const struct bpf_func_proto bpf_ghost_get_affinity_proto = {
.func = bpf_ghost_get_affinity,
.gpl_only = true,
.ret_type = RET_INTEGER,
.arg1_type = ARG_ANYTHING,
/*
* The verifier enforces that the arg pointer (arg2) is at least size
* bytes (arg3), and it is our job to ensure all bytes are set.
*/
.arg2_type = ARG_PTR_TO_UNINIT_MEM,
.arg3_type = ARG_CONST_SIZE,
};

BPF_CALL_3(bpf_ghost_get_comm, s64, gtid, char *, buf, u32, size)
{
struct ghost_enclave *e;

VM_BUG_ON(preemptible());

BUILD_BUG_ON(BPF_FUNC_ghost_get_comm != 3006);

e = get_target_enclave();

/* Paranoia: this is not expected */
if (WARN_ON_ONCE(!e))
return -ENODEV;

if (!e->abi->bpf_get_comm)
return -ENOSYS;

return e->abi->bpf_get_comm(gtid, buf, size);
}

static const struct bpf_func_proto bpf_ghost_get_comm_proto = {
.func = bpf_ghost_get_comm,
.gpl_only = true,
.ret_type = RET_INTEGER,
.arg1_type = ARG_ANYTHING,
/*
* The verifier enforces that the arg pointer (arg2) is at least size
* bytes (arg3), and it is our job to ensure all bytes are set.
*/
.arg2_type = ARG_PTR_TO_UNINIT_MEM,
.arg3_type = ARG_CONST_SIZE,
};

/*
* Each ghost BPF program type can only be attached at a single point, so we can
* use the same func_proto for all program types and switch on the expected
Expand Down Expand Up @@ -1387,6 +1453,10 @@ ghost_bpf_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
* checked in.
*/
return NULL;
case BPF_FUNC_ghost_get_affinity:
return &bpf_ghost_get_affinity_proto;
case BPF_FUNC_ghost_get_comm:
return &bpf_ghost_get_comm_proto;
default:
return bpf_base_func_proto(func_id);
}
Expand Down
2 changes: 2 additions & 0 deletions kernel/sched/sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -2270,6 +2270,8 @@ struct ghost_abi {
int (*bpf_run_gtid)(s64 gtid, u32 task_barrier, int run_flags, int cpu);
int (*bpf_resched_cpu)(int cpu, u64 seqnum); /* DEPRECATED as of ABI 79. */
int (*bpf_resched_cpu2)(int cpu, int flags);
int (*bpf_get_affinity)(s64 gtid, u8 *mask, u32 size);
int (*bpf_get_comm)(s64 gtid, char *buf, u32 size);
bool (*ghost_sched_is_valid_access)(int off, int size,
enum bpf_access_type type,
const struct bpf_prog *prog,
Expand Down
18 changes: 18 additions & 0 deletions tools/include/uapi/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -4078,6 +4078,22 @@ enum bpf_func_id {
* 'args' points to struct bpf_sync_commit_args.
*
* Return
* 0 on success, < 0 on error
*
* long bpf_ghost_get_affinity(s64 gtid, u8 *mask, u32 size)
* Description
* Copies the gtid's cpu_mask (a.k.a. cpus_allowed) into mask.
*
* Return
* Number of valid cpu bits in the mask (a.k.a. nr_cpu_ids), < 0 on
* error. If the user-provided mask is smaller than the cpu_mask,
* returns -E2BIG.
*
* long bpf_ghost_get_comm(s64 gtid, char *buf, u32 size)
* Description
* Copies up to size bytes of the gtid's comm into buf.
*
* Return
* 0 on success, < 0 on error.
*/
enum {
Expand All @@ -4087,6 +4103,8 @@ enum {
BPF_FUNC_ghost_resched_cpu,
BPF_FUNC_ghost_resched_cpu2,
BPF_FUNC_ghost_sync_commit,
BPF_FUNC_ghost_get_affinity,
BPF_FUNC_ghost_get_comm,
__BPF_FUNC_GHOST_MAX_ID,
};

Expand Down

0 comments on commit edd5f94

Please sign in to comment.