Skip to content

Commit

Permalink
Get correct process time during exec/clone
Browse files Browse the repository at this point in the history
Replace ktime_get_ns with what /proc/<PID>/stat provides (i.e. https://elixir.bootlin.com/linux/v6.1.75/source/fs/proc/array.c#L568).

Signed-off-by: Anastasios Papagiannis <[email protected]>
  • Loading branch information
tpapagian committed Feb 1, 2024
1 parent 2a5d740 commit be64e0b
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 80 deletions.
80 changes: 2 additions & 78 deletions bpf/process/bpf_execve_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include "bpf_process_event.h"
#include "bpf_helpers.h"

#include "time.h"

char _license[] __attribute__((section("license"), used)) = "Dual BSD/GPL";

struct {
Expand Down Expand Up @@ -166,84 +168,6 @@ read_exe(struct task_struct *task, struct heap_exe *exe)
}
#endif

/* Parameters used to convert the timespec values: */
#define MSEC_PER_SEC 1000L
#define USEC_PER_MSEC 1000L
#define NSEC_PER_USEC 1000L
#define NSEC_PER_MSEC 1000000L
#define USEC_PER_SEC 1000000L
#define NSEC_PER_SEC 1000000000L
#define PSEC_PER_SEC 1000000000000LL
#define FSEC_PER_SEC 1000000000000000LL

/* Parameters used to convert the timespec values: */
#define PSEC_PER_NSEC 1000L

/* Located here for timespec[64]_valid_strict */
#define TIME64_MAX ((s64) ~((u64)1 << 63))
#define TIME64_MIN (-TIME64_MAX - 1)

#define KTIME_MAX ((s64) ~((u64)1 << 63))
#define KTIME_MIN (-KTIME_MAX - 1)
#define KTIME_SEC_MAX (KTIME_MAX / NSEC_PER_SEC)
#define KTIME_SEC_MIN (KTIME_MIN / NSEC_PER_SEC)

#define USER_HZ 100 /* some user interfaces are */

static __attribute__((always_inline)) inline s64 timespec64_to_ns(struct timespec64 *ts)
{
__s64 tv_sec = BPF_CORE_READ(ts, tv_sec);
long tv_nsec = BPF_CORE_READ(ts, tv_nsec);

/* Prevent multiplication overflow / underflow */
if (tv_sec >= KTIME_SEC_MAX)
return KTIME_MAX;

if (tv_sec <= KTIME_SEC_MIN)
return KTIME_MIN;

return ((s64)tv_sec * NSEC_PER_SEC) + tv_nsec;
}

static __attribute__((always_inline)) inline u64 timens_add_boottime_ns(u64 nsec)
{
struct task_struct *task = (struct task_struct *)get_current_task();
struct time_namespace *time_ns = BPF_CORE_READ(task, nsproxy, time_ns);
struct timens_offsets ns_offsets;

probe_read(&ns_offsets, sizeof(struct timens_offsets), _(&time_ns->offsets));

return nsec + timespec64_to_ns(&ns_offsets.boottime);
}

static __attribute__((always_inline)) inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
{
*remainder = dividend % divisor;
return dividend / divisor;
}

static __attribute__((always_inline)) inline u64 div_u64(u64 dividend, u32 divisor)
{
u32 remainder;
return div_u64_rem(dividend, divisor, &remainder);
}

static __attribute__((always_inline)) inline u64 nsec_to_clock_t(u64 x)
{
#if (NSEC_PER_SEC % USER_HZ) == 0
return div_u64(x, NSEC_PER_SEC / USER_HZ);
#elif (USER_HZ % 512) == 0
return div_u64(x * USER_HZ / 512, NSEC_PER_SEC / 512);
#else
/*
* max relative error 5.7e-8 (1.8s per year) for USER_HZ <= 1024,
* overflow after 64.99 years.
* exact for HZ=60, 72, 90, 120, 144, 180, 300, 600, 900, ...
*/
return div_u64(x * 9, (9ull * NSEC_PER_SEC + (USER_HZ / 2)) / USER_HZ);
#endif
}

__attribute__((section("tracepoint/sys_execve"), used)) int
event_execve(struct sched_execve_args *ctx)
{
Expand Down
7 changes: 5 additions & 2 deletions bpf/process/bpf_fork.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include "environ_conf.h"
#include "bpf_process_event.h"

#include "time.h"

char _license[] __attribute__((section("license"), used)) = "Dual BSD/GPL";
#ifdef VMLINUX_KERNEL_VERSION
int _version __attribute__((section(("version")), used)) =
Expand All @@ -22,7 +24,7 @@ BPF_KPROBE(event_wake_up_new_task, struct task_struct *task)
{
struct execve_map_value *curr, *parent;
struct msg_clone_event msg;
u64 msg_size = sizeof(struct msg_clone_event);
u64 start_boottime, msg_size = sizeof(struct msg_clone_event);
u32 flags, tgid = 0;

if (!task)
Expand Down Expand Up @@ -56,7 +58,8 @@ BPF_KPROBE(event_wake_up_new_task, struct task_struct *task)
/* Setup the execve_map entry. */
curr->flags = EVENT_COMMON_FLAG_CLONE;
curr->key.pid = tgid;
curr->key.ktime = ktime_get_ns();
start_boottime = BPF_CORE_READ(task, start_boottime);
curr->key.ktime = nsec_to_clock_t(timens_add_boottime_ns(start_boottime)) * 10000000LLU; // similarly to what /proc/<PID>/stat provides (i.e. https://elixir.bootlin.com/linux/v6.1.75/source/fs/proc/array.c#L568)
curr->nspid = get_task_pid_vnr();
memcpy(&curr->bin, &parent->bin, sizeof(curr->bin));
curr->pkey = parent->key;
Expand Down
60 changes: 60 additions & 0 deletions bpf/process/time.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
/* Copyright Authors of Cilium */

#ifndef __TIME_H__
#define __TIME_H__

/* Parameters used to convert the timespec values: */
#define NSEC_PER_SEC 1000000000L

#define KTIME_MAX ((s64) ~((u64)1 << 63))
#define KTIME_MIN (-KTIME_MAX - 1)
#define KTIME_SEC_MAX (KTIME_MAX / NSEC_PER_SEC)
#define KTIME_SEC_MIN (KTIME_MIN / NSEC_PER_SEC)

#define USER_HZ 100 /* some user interfaces are */

static __attribute__((always_inline)) inline s64 timespec64_to_ns(struct timespec64 *ts)
{
__s64 tv_sec = BPF_CORE_READ(ts, tv_sec);
long tv_nsec = BPF_CORE_READ(ts, tv_nsec);

/* Prevent multiplication overflow / underflow */
if (tv_sec >= KTIME_SEC_MAX)
return KTIME_MAX;

if (tv_sec <= KTIME_SEC_MIN)
return KTIME_MIN;

return ((s64)tv_sec * NSEC_PER_SEC) + tv_nsec;
}

static __attribute__((always_inline)) inline u64 timens_add_boottime_ns(u64 nsec)
{
struct task_struct *task = (struct task_struct *)get_current_task();
struct time_namespace *time_ns = BPF_CORE_READ(task, nsproxy, time_ns);
struct timens_offsets ns_offsets;

probe_read(&ns_offsets, sizeof(struct timens_offsets), _(&time_ns->offsets));

return nsec + timespec64_to_ns(&ns_offsets.boottime);
}

static __attribute__((always_inline)) inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
{
*remainder = dividend % divisor;
return dividend / divisor;
}

static __attribute__((always_inline)) inline u64 div_u64(u64 dividend, u32 divisor)
{
u32 remainder;
return div_u64_rem(dividend, divisor, &remainder);
}

static __attribute__((always_inline)) inline u64 nsec_to_clock_t(u64 x)
{
return div_u64(x, NSEC_PER_SEC / USER_HZ);
}

#endif /* __TIME_H__ */

0 comments on commit be64e0b

Please sign in to comment.