Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new(modern_bpf): add support for open family syscalls #503

Merged
merged 20 commits into from
Jul 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
b1bf0f8
cleanup(modern_bpf): rename parameter num
Andreagit97 Jul 23, 2022
a22f3d7
fix(modern_bpf): change some wrong definitions
Andreagit97 Jul 24, 2022
0dd61d9
new(modern_bpf): add `open` syscall
Andreagit97 Jul 24, 2022
d78961b
new(modern_bpf): add `openat` syscall
Andreagit97 Jul 24, 2022
1fbccc7
new(modern_bpf): add `openat2` syscall
Andreagit97 Jul 24, 2022
98ebe10
update(modern_bpf): add some arm64 specific flags
Andreagit97 Jul 24, 2022
a1229a2
update(test/modern_bpf): update some functions in `openat2` calls
Andreagit97 Jul 24, 2022
6d4670d
cleanup(modern_bpf): clean some code paths
Andreagit97 Jul 26, 2022
fbb7ed7
new(modern_bpf): add `open_by_handle_at` syscall
Andreagit97 Jul 26, 2022
2100b9b
update(test/modern_bpf): manage test fatal failures
Andreagit97 Jul 26, 2022
2935a5f
fix(modern_bpf): retrieve the right param if there is only 1 path com…
Andreagit97 Jul 27, 2022
3d4c099
update(modern_bpf): simplify a `open_by_handle_at` test
Andreagit97 Jul 27, 2022
7f8a489
update(modern_bpf): enable the kernel/user read logic
Andreagit97 Jul 27, 2022
4a7b42a
update(modern_bpf): flag definitions for `s390x`
Andreagit97 Jul 27, 2022
1cdfb88
update(modern_bpf): working version supporting mount points
Andreagit97 Jul 27, 2022
a66a720
update(modern_bpf): workaround to manage mount points
Andreagit97 Jul 27, 2022
540a68a
fix(modern_bpf): some minor fixes
Andreagit97 Jul 27, 2022
f234fb6
update(modern_bpf): add `open_by_handle_at` mount point test
hbrueckner Jul 28, 2022
9d7458d
update(test/modern_bpf): fix the ARM64 build
Andreagit97 Jul 28, 2022
4296c71
fix(modern_bpf): final version of `auxmap__store_path_from_fd`
Andreagit97 Jul 29, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion driver/modern_bpf/definitions/events_dimensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@
/// TODO: We have to move these in the event_table.c. Right now we don't
/// want to touch scap tables.
#define MKDIR_E_SIZE HEADER_LEN + sizeof(uint32_t) + PARAM_LEN
#define OPEN_BY_HANDLE_AT_E_SIZE HEADER_LEN

#endif /* __EVENT_DIMENSIONS_H__ */
#endif /* __EVENT_DIMENSIONS_H__ */
39 changes: 28 additions & 11 deletions driver/modern_bpf/definitions/missing_definitions.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,28 @@
#define O_TRUNC 00001000 /* not fcntl */
#define O_APPEND 00002000
#define O_NONBLOCK 00004000
#define O_DSYNC 00010000 /* used to be O_SYNC, see below */
#define FASYNC 00020000 /* fcntl, for BSD compatibility */
#define O_NDELAY O_NONBLOCK
#define O_DSYNC 00010000 /* used to be O_SYNC, see below */
#define FASYNC 00020000 /* fcntl, for BSD compatibility */

#if defined(__TARGET_ARCH_x86) || defined(__TARGET_ARCH_s390)

#define O_DIRECT 00040000 /* direct disk access hint */
#define O_LARGEFILE 00100000
#define O_DIRECTORY 00200000 /* must be a directory */
#define O_NOFOLLOW 00400000 /* don't follow links */

#elif defined(__TARGET_ARCH_arm64)

/* `/arch/arm64/include/uapi/asm/fcntl.h` from kernel source tree. */

#define O_DIRECTORY 040000 /* must be a directory */
#define O_NOFOLLOW 0100000 /* don't follow links */
#define O_DIRECT 0200000 /* direct disk access hint - currently ignored */
#define O_LARGEFILE 0400000

#endif

#define O_NOATIME 01000000
#define O_CLOEXEC 02000000 /* set close_on_exec */
#define __O_SYNC 04000000
Expand All @@ -113,8 +129,6 @@
#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY)
#define O_TMPFILE_MASK (__O_TMPFILE | O_DIRECTORY | O_CREAT)

#define O_NDELAY O_NONBLOCK

//////////////////////////
// openat2 flags
//////////////////////////
Expand Down Expand Up @@ -1170,13 +1184,16 @@
/*=============================== DIRECTORY_NOTIFICATIONS ===========================*/

/*=============================== DEVICE_VERSIONS ===========================*/
/*
Some programs want their definitions of MAJOR and MINOR and MKDEV
from the kernel sources. These must be the externally visible ones.
*/
#define MAJOR(dev) ((dev) >> 8)
#define MINOR(dev) ((dev)&0xff)
#define MKDEV(ma, mi) ((ma) << 8 | (mi))

/* `/include/linux/kdev_t.h` from kernel source tree. */

#define MINORBITS 20
#define MINORMASK ((1U << MINORBITS) - 1)

#define MAJOR(dev) ((unsigned int)((dev) >> MINORBITS))
#define MINOR(dev) ((unsigned int)((dev)&MINORMASK))
#define MKDEV(ma, mi) (((ma) << MINORBITS) | (mi))

/*=============================== DEVICE_VERSIONS ===========================*/

/*=============================== RLIMIT_ID ===========================*/
Expand Down
74 changes: 55 additions & 19 deletions driver/modern_bpf/helpers/base/push_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,15 @@
* event_len
*/

/* This enum is used to tell our helpers if they have to
* read from kernel or user memory.
*/
enum read_memory
{
USER = 0,
KERNEL = 1,
};

/* Event maximum size */
#define MAX_EVENT_SIZE 64 * 1024

Expand All @@ -99,7 +108,7 @@
* @param lengths_pos pointer to the first empty slot into the `lengths_arr`.
* @param len length to store inside the array (16 bit).
*/
static __always_inline void push__param_len(u8* data, u8 *lengths_pos, u16 len)
static __always_inline void push__param_len(u8 *data, u8 *lengths_pos, u16 len)
{
*((u16 *)&data[SAFE_ACCESS(*lengths_pos)]) = len;
*lengths_pos += sizeof(u16);
Expand All @@ -125,49 +134,49 @@ static __always_inline void push__param_len(u8* data, u8 *lengths_pos, u16 len)
// PUSH FIXED DIMENSIONS
///////////////////////////

static __always_inline void push__u8(u8* data, u64 *payload_pos, u8 param)
static __always_inline void push__u8(u8 *data, u64 *payload_pos, u8 param)
{
*((u8 *)&data[SAFE_ACCESS(*payload_pos)]) = param;
*payload_pos += sizeof(u8);
}

static __always_inline void push__u16(u8* data, u64 *payload_pos, u16 param)
static __always_inline void push__u16(u8 *data, u64 *payload_pos, u16 param)
{
*((u16 *)&data[SAFE_ACCESS(*payload_pos)]) = param;
*payload_pos += sizeof(u16);
}

static __always_inline void push__u32(u8* data, u64 *payload_pos, u32 param)
static __always_inline void push__u32(u8 *data, u64 *payload_pos, u32 param)
{
*((u32 *)&data[SAFE_ACCESS(*payload_pos)]) = param;
*payload_pos += sizeof(u32);
}

static __always_inline void push__u64(u8* data, u64 *payload_pos, u64 param)
static __always_inline void push__u64(u8 *data, u64 *payload_pos, u64 param)
{
*((u64 *)&data[SAFE_ACCESS(*payload_pos)]) = param;
*payload_pos += sizeof(u64);
}

static __always_inline void push__s32(u8* data, u64 *payload_pos, s32 param)
static __always_inline void push__s32(u8 *data, u64 *payload_pos, s32 param)
{
*((s32 *)&data[SAFE_ACCESS(*payload_pos)]) = param;
*payload_pos += sizeof(s32);
}

static __always_inline void push__s64(u8* data, u64 *payload_pos, s64 param)
static __always_inline void push__s64(u8 *data, u64 *payload_pos, s64 param)
{
*((s64 *)&data[SAFE_ACCESS(*payload_pos)]) = param;
*payload_pos += sizeof(s64);
}

static __always_inline void push__ipv6(u8* data, u64 *payload_pos, u32 ipv6[4])
static __always_inline void push__ipv6(u8 *data, u64 *payload_pos, u32 ipv6[4])
{
__builtin_memcpy(&data[SAFE_ACCESS(*payload_pos)], ipv6, 16);
*payload_pos += 16;
}

static __always_inline void push__new_character(u8* data, u64 *payload_pos, char character)
static __always_inline void push__new_character(u8 *data, u64 *payload_pos, char character)
{
*((char *)&data[SAFE_ACCESS(*payload_pos)]) = character;
*payload_pos += sizeof(char);
Expand All @@ -177,7 +186,7 @@ static __always_inline void push__new_character(u8* data, u64 *payload_pos, char
* a previous character. Since we overwrite it we don't need to update
* `payload_pos`.
*/
static __always_inline void push__previous_character(u8* data, u64 *payload_pos, char character)
static __always_inline void push__previous_character(u8 *data, u64 *payload_pos, char character)
{
*((char *)&data[SAFE_ACCESS(*payload_pos - 1)]) = character;
}
Expand All @@ -197,14 +206,27 @@ static __always_inline void push__previous_character(u8* data, u64 *payload_pos,
* @param payload_pos pointer to the first empty byte after the last "push" operation.
* @param charbuf_pointer pointer to the charbuf.
* @param limit maximum number of bytes that we read in case we don't find a `\0`
* @param mem tell where it must read: user-space or kernel-space.
* @return (u16) the number of bytes written in the buffer. Could be '0' if the passed pointer is not valid.
*/
static __always_inline u16 push__charbuf(u8* data, u64 *payload_pos, unsigned long charbuf_pointer, u16 limit)
static __always_inline u16 push__charbuf(u8 *data, u64 *payload_pos, unsigned long charbuf_pointer, u16 limit, enum read_memory mem)
{
int written_bytes = bpf_probe_read_str(&data[SAFE_ACCESS(*payload_pos)],
limit,
(char *)charbuf_pointer);
if(written_bytes < 0)
int written_bytes = 0;

if(mem == KERNEL)
{
written_bytes = bpf_probe_read_kernel_str(&data[SAFE_ACCESS(*payload_pos)],
limit,
(char *)charbuf_pointer);
}
else
{
written_bytes = bpf_probe_read_user_str(&data[SAFE_ACCESS(*payload_pos)],
limit,
(char *)charbuf_pointer);
}

if(written_bytes <= 0)
{
return 0;
}
Expand All @@ -226,13 +248,27 @@ static __always_inline u16 push__charbuf(u8* data, u64 *payload_pos, unsigned lo
* @param payload_pos pointer to the first empty byte after the last "push" operation.
* @param bytebuf_pointer pointer to the bytebuf.
* @param len_to_read bytes that we need to read from the pointer.
* @param mem from which memory we need to read: user-space or kernel-space.
* @return (u16) the number of bytes written in the buffer. Could be '0' if the passed pointer is not valid.
*/
static __always_inline u16 push__bytebuf(u8* data, u64 *payload_pos, unsigned long bytebuf_pointer, u16 len_to_read)
static __always_inline u16 push__bytebuf(u8 *data, u64 *payload_pos, unsigned long bytebuf_pointer, u16 len_to_read, enum read_memory mem)
{
int written_bytes = bpf_probe_read(&data[SAFE_ACCESS(*payload_pos)],
len_to_read,
(char *)bytebuf_pointer);

int written_bytes = 0;

if(mem == KERNEL)
{
written_bytes = bpf_probe_read_kernel(&data[SAFE_ACCESS(*payload_pos)],
len_to_read,
(char *)bytebuf_pointer);
}
else
{
written_bytes = bpf_probe_read_user(&data[SAFE_ACCESS(*payload_pos)],
len_to_read,
(char *)bytebuf_pointer);
}

if(written_bytes != 0)
{
return 0;
Expand Down
81 changes: 81 additions & 0 deletions driver/modern_bpf/helpers/extract/extract_from_kernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,84 @@ static __always_inline unsigned long extract__syscall_argument(struct pt_regs *r

return arg;
}

///////////////////////////
// ENCODE DEVICE NUMBER
///////////////////////////

/**
* @brief Encode device number with `MAJOR` and `MINOR` MACRO.
*
* Please note: **Used only inside this file**.
*
* @param dev device number extracted directly from the kernel.
* @return encoded device number.
*/
static __always_inline dev_t encode_dev(dev_t dev)
{
unsigned int major = MAJOR(dev);
unsigned int minor = MINOR(dev);

return (minor & 0xff) | (major << 8) | ((minor & ~0xff) << 12);
}

///////////////////////////
// FILE EXTRACTION
///////////////////////////

/**
* @brief Return `file` struct from a file descriptor.
*
* @param file_descriptor generic file descriptor.
* @return struct file* pointer to the `struct file` associated with the
* file descriptor. Return a NULL pointer in case of failure.
*/
static __always_inline struct file *extract__file_struct_from_fd(s32 file_descriptor)
{
struct file *f = NULL;
if(file_descriptor >= 0)
{
struct file **fds;
struct task_struct *task = get_current_task();
READ_TASK_FIELD_INTO(&fds, task, files, fdt, fd);
bpf_probe_read_kernel(&f, sizeof(struct file *), &fds[file_descriptor]);
}
return f;
}

/**
* \brief Extract the inode number from a file descriptor.
*
* @param fd generic file descriptor.
* @param ino pointer to the inode number we have to fill.
*/
static __always_inline void extract__ino_from_fd(s32 fd, u64 *ino)
{
struct file *f = extract__file_struct_from_fd(fd);
if(!f)
{
return;
}

BPF_CORE_READ_INTO(ino, f, f_inode, i_ino);
}

/**
* \brief Extract the device number and the inode number from a file descriptor.
*
* @param fd generic file descriptor.
* @param dev pointer to the device number we have to fill.
* @param ino pointer to the inode number we have to fill.
*/
static __always_inline void extract__dev_and_ino_from_fd(s32 fd, dev_t *dev, u64 *ino)
{
struct file *f = extract__file_struct_from_fd(fd);
if(!f)
{
return;
}

BPF_CORE_READ_INTO(dev, f, f_inode, i_sb, s_dev);
*dev = encode_dev(*dev);
BPF_CORE_READ_INTO(ino, f, f_inode, i_ino);
}
Loading