Skip to content

Commit

Permalink
fill field offset from userspace, fix loop
Browse files Browse the repository at this point in the history
  • Loading branch information
mmat11 committed Oct 3, 2023
1 parent ec6acd6 commit 1ee399b
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 28 deletions.
3 changes: 3 additions & 0 deletions GPL/Events/Helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ const volatile int consumer_pid = 0;
#define DECL_FUNC_ARG_EXISTS(func, arg) const volatile bool exists__##func##__##arg##__ = false;
#define FUNC_ARG_EXISTS(func, arg) exists__##func##__##arg##__

#define DECL_FIELD_OFFSET(struct, field) const volatile int off__##struct##__##field##__ = 0;
#define FIELD_OFFSET(struct, field) off__##struct##__##field##__

// From linux/err.h
#define MAX_ERRNO 4095

Expand Down
42 changes: 15 additions & 27 deletions GPL/Events/Process/Probe.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
#include "PathResolver.h"
#include "Varlen.h"

/* tty_write */
DECL_FIELD_OFFSET(iov_iter, __iov);

// Limits on large things we send up as variable length parameters.
//
// These should be kept _well_ under half the size of the event_buffer_map or
Expand Down Expand Up @@ -332,22 +335,6 @@ static int output_tty_event(struct ebpf_tty_dev *slave, const void *base, size_t
return ret;
}

struct iov_iter____new {
union {
struct iovec __ubuf_iovec;
struct {
union {
const struct iovec *__iov;
const struct kvec *kvec;
const struct bio_vec *bvec;
struct xarray *xarray;
void *ubuf;
};
size_t count;
};
};
} __attribute__((preserve_access_index));

static int tty_write__enter(struct kiocb *iocb, struct iov_iter *from)
{
if (is_consumer()) {
Expand Down Expand Up @@ -384,27 +371,28 @@ static int tty_write__enter(struct kiocb *iocb, struct iov_iter *from)
goto out;
}

u64 nr_segs = BPF_CORE_READ(from, nr_segs);
nr_segs = nr_segs > MAX_NR_SEGS ? MAX_NR_SEGS : nr_segs;

const struct iovec *iov;
if (bpf_core_field_exists(struct iov_iter____new, __iov)) {
u64 iov_off = offsetof(struct iov_iter____new, __iov);
bpf_core_read(&iov, bpf_core_type_size(struct iov_iter), (void *)from + iov_off);
} else if (bpf_core_field_exists(from->iov)) {
iov = BPF_CORE_READ(from, iov);
if (FIELD_OFFSET(iov_iter, __iov)) {
iov = (const struct iovec *)((char *)from + FIELD_OFFSET(iov_iter, __iov));
} else {
bpf_printk("tty_write__enter: error reading iov\n");
goto out;
iov = BPF_CORE_READ(from, iov);
}

u64 nr_segs = BPF_CORE_READ(from, nr_segs);
nr_segs = nr_segs > MAX_NR_SEGS ? MAX_NR_SEGS : nr_segs;

if (nr_segs == 0) {
u64 count = BPF_CORE_READ(from, count);
(void)output_tty_event(&slave, (void *)iov, count);
goto out;
}

for (u8 seg = 0; seg < nr_segs; seg++) {
for (int seg = 0; seg < nr_segs; seg++) {
// NOTE(matt): this check needs to be here because the verifier
// detects an infinite loop otherwise.
if (seg >= MAX_NR_SEGS)
goto out;

struct iovec *cur_iov = (struct iovec *)&iov[seg];
const char *base = BPF_CORE_READ(cur_iov, iov_base);
size_t len = BPF_CORE_READ(cur_iov, iov_len);
Expand Down
1 change: 0 additions & 1 deletion non-GPL/Events/EventsTrace/EventsTrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -794,7 +794,6 @@ int main(int argc, char **argv)
ebpf_set_verbose_logging();

err = ebpf_event_ctx__new(&ctx, event_ctx_callback, g_events_env);

if (err < 0) {
fprintf(stderr, "Could not create event context: %d %s\n", err, strerror(-err));
goto out;
Expand Down
76 changes: 76 additions & 0 deletions non-GPL/Events/Lib/EbpfEvents.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,57 @@ static int ring_buf_cb(void *ctx, void *data, size_t size)
return 0;
}

/* https://www.kernel.org/doc/html/latest/bpf/btf.html#btf-kind-union */
static int resolve_btf_field_off_recur(struct btf *btf,
int base_off,
const struct btf_type *t,
const char *field)
{
struct btf_member *m = btf_members(t);

for (int i = 0; i < btf_vlen(t); i++, m++) {
const char *name = btf__name_by_offset(btf, m->name_off);
if (name == NULL)
continue;

if (strcmp(name, field) == 0)
return (base_off + m->offset) / 8;

const struct btf_type *m_type = btf__type_by_id(btf, m->type);
if (!btf_is_struct(m_type) && !btf_is_union(m_type))
continue;

// Recursively traverse structs and unions
int ret = resolve_btf_field_off_recur(btf, base_off + m->offset, m_type, field);
if (ret == -1)
continue;

return ret;
}

return -1;
}

/* Find the BTF field relocation offset for a named field of a kernel struct */
static int resolve_btf_field_off(struct btf *btf, const char *struct_name, const char *field)
{
int ret = -1;

__s32 btf_id = btf__find_by_name_kind(btf, struct_name, BTF_KIND_STRUCT);
if (btf_id <= 0)
goto out;

const struct btf_type *t = btf__type_by_id(btf, btf_id);
if (t == NULL)
goto out;
if (!btf_is_struct(t))
goto out;

return resolve_btf_field_off_recur(btf, 0, t, field);
out:
return ret;
}

const struct btf_type *resolve_btf_type_by_func(struct btf *btf, const char *func)
{
if (func == NULL) {
Expand Down Expand Up @@ -176,9 +227,31 @@ static int resolve_btf_func_ret_idx(struct btf *btf, const char *func)
__r; \
})

/* Given a struct name and a field name, returns the field offset
* within the struct.
*/
#define FILL_FIELD_OFFSET(obj, btf, struct, field) \
({ \
int __r = -1; \
int r = resolve_btf_field_off(btf, #struct, #field); \
if (r >= 0) \
__r = 0; \
obj->rodata->off__##struct##__##field##__ = r; \
__r; \
})

/* Given a function name, returns whether it exists in the provided BTF. */
#define BTF_FUNC_EXISTS(btf, func) ({ (bool)resolve_btf_type_by_func(btf, #func); })

/* Given a struct name and a field name, returns whether the field exists within the struct. */
#define BTF_FIELD_EXISTS(btf, struct, field) \
({ \
bool __r = false; \
if (resolve_btf_field_off(btf, #struct, #field) >= 0) \
__r = true; \
__r; \
})

/* Fill context relocations for kernel functions
* You can add additional functions here by using the macros defined above.
*
Expand All @@ -198,6 +271,9 @@ static int probe_fill_relos(struct btf *btf, struct EventProbe_bpf *obj)
}
err = err ?: FILL_FUNC_RET_IDX(obj, btf, vfs_rename);

if (BTF_FIELD_EXISTS(btf, iov_iter, __iov))
err = err ?: FILL_FIELD_OFFSET(obj, btf, iov_iter, __iov);

return err;
}

Expand Down

0 comments on commit 1ee399b

Please sign in to comment.