반응형

-reference-

https://github.com/google/buzzer

 

GitHub - google/buzzer

Contribute to google/buzzer development by creating an account on GitHub.

github.com

 

 

 

1. Install bazel

https://bazel.build/install/ubuntu?hl=ko 

 

Ubuntu에 Bazel 설치

날짜 비워 두기: BazelCon 2023이 10월 24~25일에 Google 뮌헨에서 열립니다. 등록이 시작되었습니다. 자세히 알아보기 이 페이지는 Cloud Translation API를 통해 번역되었습니다. Switch to English Ubuntu에 Bazel 설

bazel.build

2. Install clang & dependency

sudo apt install default-jdk
sudo apt install bc bison flex build-essential
sudo apt install cmake clang llvm
sudo apt install g++ g++-12

● Trouble shooting

if you encounter such as these errors you should check that you installed all of dependencies

3. Set env

export CC=clang
export CXX=clang++

4. Git clone repository

git clone https://github.com/google/buzzer
cd buzzer
bazel build :buzzer

5. Run buzzer as a root with CAP_BPF

sudo setcap CAP_BPF=eip bazel-bin/buzzer_/buzzer
./bazel-bin/buzzer_/buzzer

if you want to check log, view /tmp directory

 

6. Run with coverage

mkdir image

cd image

wget https://github.com/google/syzkaller/blob/master/tools/create-image.sh -o create-image.sh

chmod +x create-image.sh

./create-image.sh

If you want to customize your .img , check ref below

https://github.com/google/syzkaller/blob/master/tools/create-image.sh

 

 

7. Make boot_buzzer.sh in ~/ directory

qemu-system-x86_64 \
        -m 24G \
        -smp 12 \
        -cpu host \
        -kernel /home/username/linux-repository/arch/x86/boot/bzImage \
        -append "comsole=ttyS0 root=/dev/sda nokaslr earlyprintk=serial net.ifnames=0" \
        -drive file=/home/username/image/bullseye.img,format=raw\
        -net user,host=10.0.2.10,hostfwd=tcp:127.0.0.1:10022-:22\
        -enable-kvm \
        -nographic \
        -pidfile vm.pid \
        2>&1 | tee vm.log

If you have error about portfowarding, check your ports.

netstat -tnlp 

sudo fuser -k 8080/tcp

sudo kill -9 pid

 

8. Run .sh file

sudo -s ./boot_buzzer.sh

now you can see "syzkaller login: "

login with root

9. Send files with command "scp"

 

Before sending data, I Permitted to login with root

-ref-

https://www.leafcats.com/176

 

ssh-keygen -r 127.0.0.1
ssh-keygen -f "/home/username/.ssh/known_hosts" -R "[localhost]:10022"

 

Come back to host pc & send vmlinux

mkdir sourcefiles
cd sourcefiles

- For verifier.c and other files

After, you can see the file

10. Run buzzer

Send buzzer to syzkaller

Run on Qemu

HAPPY FUZZING!!!

 

cf. run buzzer on local

반응형

'ebpf' 카테고리의 다른 글

JIT for BPF  (0) 2023.09.21
JIT(Just In Time) Compiler - Verifier - SAT/SMT solver  (0) 2023.09.17
eBPF references - Blackhat  (0) 2023.08.06
O’Reilly Report What is eBPF? - tutorial 4  (0) 2023.07.21
O’Reilly Report What is eBPF? - tutorial 3  (0) 2023.07.21
반응형

언젠가 이해하는 날이 오길 바라며..

 

Blackhat USA 2022

1.

US-22-Johnson-eBPF-ELFs-JMPing-Through-the-Windows.pdf
4.35MB

2.

US-22-Fournier-Return-To-Sender.pdf
1.05MB

 

 

Blackhat ASIA 2023

1.

AS-23-Palmiotti-Alice-In-Kernel-Land.pdf
4.61MB

반응형
반응형

간만에 쉬운문제다 

 

처음에 window에서 풀려고 했으나, code를 실행해본 결과 alarm()에 대한 error가 발생하였다.

그리하여 검색해보니 아래와 같이 SIGALARM은 window OS에서 사용할 수 없다고 나왔다.

https://stackoverflow.com/questions/52779920/why-is-signal-sigalrm-not-working-in-python-on-windows

 

 

그리하여 ubuntu로 넘어가서 문제를 풀기로 하였다.

우선 go to gamble을 위해서는 robot인증을 먼저 수행해야 한다. 그러므로, 수행해보려했으나.. 3초만에 인증해야한다.

허허..

복사 붙여넣기로 인증은 성공했다.

그럼 요로코롬 나온다.

 

위와 같은 기능들이 있는데 flag를 사기 위해선 $10,000,000,000가 있어야하지만 현재는 $500밖에 없는 상황이다.

그리고 go to gamble에서는 [1] ~[5] 중에서 골라 맞히는 게임이다.

 

현실적으로 맞히기는 힘들다.

but, code상에 오류가 존재한다. 틀린 경우 돈을 다시 더해주는 매커니즘이므로 음수의 돈을 배팅한다면 배팅한 만큼 다시

내돈이 된다.

이를 이용하여 -10000000000 을 배팅하면 된다.

잘나온다 ㅋㅋ

반응형

'wargame' 카테고리의 다른 글

type confusion  (0) 2023.08.27
tmitter  (0) 2023.08.26
file-csp-1  (0) 2023.07.02
error based sql injection  (0) 2023.07.01
flask-dev  (0) 2023.06.30
반응형

본 게시글은 개인적으로 공부하기 위해 작성된 글입니다.

 

eBPF program은 tracing messages를 debugging 목적으로 작성할 수 있다./sys/kernel/debug/tracing/trace_pipe에서 읽을 수 있는 trace_pipe를 통해 일반적으로 수행되는 간단한 예이다.그러나 몇가지 제약사항들이 있따. 3 arg가 max이며, trace_pipe는 전역적으로 공유(동시출력되는 프로그램은 충돌 발생가능)되어야한다. 그렇기에 productive eBPF code를 사용하면 안된다고 한다. 

===============================

productive code가 무엇을 의미하는 바인지는 잘 모르겠다..글의 맥락상 trace_pipe를 활용하면 안되는 것 같다.혹여 비슷한 뜻일까 하여 production code의 의미를 찾아보니 프로그램 구현을 담당하는 부분으로 사용자가 실제로 사용하는 code를 의미한다고 한다.

===============================BPF_PERF_OUTPUT() 인터페이스를 통해 수행해야 한다.본 실습에서는 실플함을 위해 trace_pipe를 통해 이를 수행하고 opensnoop에 자체 메시지를 추가한다.

 

기존의 opensnoop.bpf.c에 아래의 명령어가 line 119에 추가되어야한다. 

    bpf_printk("Hello world");

추가된 code의 snippet은 아래와 같다.

   /* emit event */
   bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU,
                 &event, sizeof(event));

   bpf_printk("Hello world");

cleanup:
   bpf_map_delete_elem(&start, &pid);
   return 0;
}

이후에 다시 build하고 실행해준다.

make opensnoop

다른 터미널에서는 아래의 명령을 수행한다.

cat /sys/kernel/debug/tracing/trace_pipe

 

이제 make opensnoop했던 터미널에서 아래의 명령을 수행한다.

 

./opensnoop

이후에 editor로 아무 파일이나 접근해본다. editor에서 file을 load하는 것은 많은 이벤트들을 생성하고 이는 아래에서 확인가능하다.

 

다시 원래의 터미널에서 보면 출력의 결과로 엄청난 양의 파일들에 접근된 것을 볼 수 있다.

덧붙여 정의한 메시지 외에도 trace 출력문에는 다른 유용한 정보들(실행 파일 이름, 프로그램을 실행한 이벤트를 trigger한 process ID)이 포함되어 있다. 본 실습의 경우 PID: 1781로 실행되는 sandbox-agent이다.

이후에 다른 터미널에서 즉 cat명령 process가 여전히 수행되고 있는 터미널에서 tracing메시지가 출력되는 것을 확인할 수 있다.

 

반응형

'ebpf' 카테고리의 다른 글

Buzzer(eBPF fuzzer) build  (0) 2023.08.11
eBPF references - Blackhat  (0) 2023.08.06
O’Reilly Report What is eBPF? - tutorial 3  (0) 2023.07.21
O’Reilly Report What is eBPF? - tutorial 2  (0) 2023.07.20
O’Reilly Report What is eBPF? - tutorial  (0) 2023.07.20
반응형

본 게시글은 개인적으로 공부하기 위해 작성된 글입니다.

 

현재 머신에서는 opensnoop이 실행되고 있지 않다. 이제 bpftool을 활용하여 eBPF 프로그램들이 machine에서 동작하는 것을 관찰해보자.

우선 아래의 명령어를 실행한다.

bpftool prog list

출력 결과는 아래와 같다.

 출력 결과에는 상기와 같이 cgroup_skb 및 cgroup_device의 두 가지 항목이 표시되어 있어야 한다. 둘다 Systemd의 구성요소인 systemd.resource-control에 의해 관리되며 네트워크장치 및 파일 시스템에 대한 Systemd 장치의 엑세스를 관리하는데에 사용된다고 한다.

 그리고 현재는 tracepoint 종류의 항목이 없어야 한다.

 

이번엔 다른 터미널에서 아래의 명령을 수행한 이후에 다시 bpftool prog list를 원래의 터미널에서 실행해본다.

./opensnoop

출력 결과는 아까 처럼 82번까지 나오고, 이후의 출력 결과가 다르다.

 4개의 BPF program이 적재된 것을 확인할 수 있다. 상기의 4개의 program은 이전의 tutorial 2에서 언급된 4가지 opensnoop BPF program에 해당된다. 이것은 모두 tracepoint유형이다. 그러나, 이름이 짤려 있어서 entry point와 exit point를 구별할 수 없다.

 그리고 두세개의 숫자로 이뤄진 map_ids를 확인할 수 있다.(숫자는 실행마다 다를 수 있다.)

 

이제 기존에 실행해둔 ./opensnoop을 그대로 두고, 아래의 명령어를 수행한다.

bpftool map list

그리고 출력의 결과로 현재 존재하는 BPF map들을 볼 수 있다.

 

- 이름이 start인 hash table과 이름이 events인 perf 이벤트 배열을 확인할 수 있다.

그리고 이는 ~/bcc/libbpf-tools/opensnoop.bpf.c 의 line 13~24 의 source code에 정의 되어 있다.

// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019 Facebook
// Copyright (c) 2020 Netflix
#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
#include "opensnoop.h"

const volatile pid_t targ_pid = 0;
const volatile pid_t targ_tgid = 0;
const volatile uid_t targ_uid = 0;
const volatile bool targ_failed = false;

struct {
	__uint(type, BPF_MAP_TYPE_HASH);
	__uint(max_entries, 10240);
	__type(key, u32);
	__type(value, struct args_t);
} start SEC(".maps");

struct {
	__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
	__uint(key_size, sizeof(u32));
	__uint(value_size, sizeof(u32));
} events SEC(".maps");

static __always_inline bool valid_uid(uid_t uid) {
	return uid != INVALID_UID;
}

static __always_inline
bool trace_allowed(u32 tgid, u32 pid)
{
	u32 uid;

	/* filters */
	if (targ_tgid && targ_tgid != tgid)
		return false;
	if (targ_pid && targ_pid != pid)
		return false;
	if (valid_uid(targ_uid)) {
		uid = (u32)bpf_get_current_uid_gid();
		if (targ_uid != uid) {
			return false;
		}
	}
	return true;
}

SEC("tracepoint/syscalls/sys_enter_open")
int tracepoint__syscalls__sys_enter_open(struct trace_event_raw_sys_enter* ctx)
{
	u64 id = bpf_get_current_pid_tgid();
	/* use kernel terminology here for tgid/pid: */
	u32 tgid = id >> 32;
	u32 pid = id;

	/* store arg info for later lookup */
	if (trace_allowed(tgid, pid)) {
		struct args_t args = {};
		args.fname = (const char *)ctx->args[0];
		args.flags = (int)ctx->args[1];
		bpf_map_update_elem(&start, &pid, &args, 0);
	}
	return 0;
}

SEC("tracepoint/syscalls/sys_enter_openat")
int tracepoint__syscalls__sys_enter_openat(struct trace_event_raw_sys_enter* ctx)
{
	u64 id = bpf_get_current_pid_tgid();
	/* use kernel terminology here for tgid/pid: */
	u32 tgid = id >> 32;
	u32 pid = id;

	/* store arg info for later lookup */
	if (trace_allowed(tgid, pid)) {
		struct args_t args = {};
		args.fname = (const char *)ctx->args[1];
		args.flags = (int)ctx->args[2];
		bpf_map_update_elem(&start, &pid, &args, 0);
	}
	return 0;
}

static __always_inline
int trace_exit(struct trace_event_raw_sys_exit* ctx)
{
	struct event event = {};
	struct args_t *ap;
	uintptr_t stack[3];
	int ret;
	u32 pid = bpf_get_current_pid_tgid();

	ap = bpf_map_lookup_elem(&start, &pid);
	if (!ap)
		return 0;	/* missed entry */
	ret = ctx->ret;
	if (targ_failed && ret >= 0)
		goto cleanup;	/* want failed only */

	/* event data */
	event.pid = bpf_get_current_pid_tgid() >> 32;
	event.uid = bpf_get_current_uid_gid();
	bpf_get_current_comm(&event.comm, sizeof(event.comm));
	bpf_probe_read_user_str(&event.fname, sizeof(event.fname), ap->fname);
	event.flags = ap->flags;
	event.ret = ret;

	bpf_get_stack(ctx, &stack, sizeof(stack),
		      BPF_F_USER_STACK);
	/* Skip the first address that is usually the syscall it-self */
	event.callers[0] = stack[1];
	event.callers[1] = stack[2];

	/* emit event */
	bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU,
			      &event, sizeof(event));

cleanup:
	bpf_map_delete_elem(&start, &pid);
	return 0;
}

SEC("tracepoint/syscalls/sys_exit_open")
int tracepoint__syscalls__sys_exit_open(struct trace_event_raw_sys_exit* ctx)
{
	return trace_exit(ctx);
}

SEC("tracepoint/syscalls/sys_exit_openat")
int tracepoint__syscalls__sys_exit_openat(struct trace_event_raw_sys_exit* ctx)
{
	return trace_exit(ctx);
}

char LICENSE[] SEC("license") = "GPL";

 

- opensnoop 의 read only data를 위한 배열도 있다.(array name opensnoo.rodata)

-마지막으로 각 행의 시작에 있는 map ID가 이전의 bpftool prog list 에서 참조한 ID인지도 대응해보아야한다.

 

이제 program 중 하나의 bytecode를 볼 것이다.

다시 bpftool prog list를 수행해본다.( 사진은 앞서 있는 것을 참고한다)

각 줄의 시작부분에 ID와 대응되는 BPF program들이 나온다.

ID 중에 tracepoint program의 ID를 참고하여 아래의 명령어를 입력한다.

bpftool prog dump xlated id 110 linum

출력 결과는 아래와 같다.( 깔끔하게 보여야될거같아서 code block를 썼다.)

int tracepoint__syscalls__sys_enter_open(struct trace_event_raw_sys_enter * ctx):
; int tracepoint__syscalls__sys_enter_open(struct trace_event_raw_sys_enter* ctx) [file:/opt/ebpf/bcc/libbpf-tools/opensnoop.bpf.c line_num:50 line_col:0]
   0: (bf) r6 = r1
; u64 id = bpf_get_current_pid_tgid(); [file:/opt/ebpf/bcc/libbpf-tools/opensnoop.bpf.c line_num:52 line_col:11]
   1: (85) call bpf_get_current_pid_tgid#186208
; u32 pid = id; [file:/opt/ebpf/bcc/libbpf-tools/opensnoop.bpf.c line_num:55 line_col:6]
   2: (63) *(u32 *)(r10 -4) = r0
; if (targ_tgid && targ_tgid != tgid) [file:/opt/ebpf/bcc/libbpf-tools/opensnoop.bpf.c line_num:36 line_col:6]
   3: (18) r1 = map[id:15][0]+4
   5: (61) r2 = *(u32 *)(r1 +0)
; if (targ_pid && targ_pid != pid) [file:/opt/ebpf/bcc/libbpf-tools/opensnoop.bpf.c line_num:38 line_col:6]
   6: (18) r1 = map[id:15][0]+0
   8: (61) r2 = *(u32 *)(r1 +0)
; if (valid_uid(targ_uid)) { [file:/opt/ebpf/bcc/libbpf-tools/opensnoop.bpf.c line_num:40 line_col:16]
   9: (18) r7 = map[id:15][0]+8
  11: (61) r1 = *(u32 *)(r7 +0)
  12: (18) r2 = 0xffffffff
; if (targ_uid != uid) { [file:/opt/ebpf/bcc/libbpf-tools/opensnoop.bpf.c line_num:42 line_col:7]
  14: (b7) r1 = 0
; struct args_t args = {}; [file:/opt/ebpf/bcc/libbpf-tools/opensnoop.bpf.c line_num:59 line_col:17]
  15: (7b) *(u64 *)(r10 -16) = r1
; args.fname = (const char *)ctx->args[0]; [file:/opt/ebpf/bcc/libbpf-tools/opensnoop.bpf.c line_num:60 line_col:30]
  16: (79) r1 = *(u64 *)(r6 +16)
; args.fname = (const char *)ctx->args[0]; [file:/opt/ebpf/bcc/libbpf-tools/opensnoop.bpf.c line_num:60 line_col:14]
  17: (7b) *(u64 *)(r10 -24) = r1
; args.flags = (int)ctx->args[1]; [file:/opt/ebpf/bcc/libbpf-tools/opensnoop.bpf.c line_num:61 line_col:21]
  18: (79) r1 = *(u64 *)(r6 +24)
; args.flags = (int)ctx->args[1]; [file:/opt/ebpf/bcc/libbpf-tools/opensnoop.bpf.c line_num:61 line_col:14]
  19: (63) *(u32 *)(r10 -16) = r1
  20: (bf) r2 = r10
; struct args_t args = {}; [file:/opt/ebpf/bcc/libbpf-tools/opensnoop.bpf.c line_num:59 line_col:17]
  21: (07) r2 += -4
  22: (bf) r3 = r10
  23: (07) r3 += -24
; bpf_map_update_elem(&start, &pid, &args, 0); [file:/opt/ebpf/bcc/libbpf-tools/opensnoop.bpf.c line_num:62 line_col:3]
  24: (18) r1 = map[id:12]
  26: (b7) r4 = 0
  27: (85) call htab_map_update_elem#220464
; return 0; [file:/opt/ebpf/bcc/libbpf-tools/opensnoop.bpf.c line_num:64 line_col:2]
  28: (b7) r0 = 0
  29: (95) exit

이는 source doce의 정보를 보여준다. 그리고, 상기에 올려둔 opensnoop.bpf.c와 함꼐 대조하며 확인해보면된다.

반응형
반응형

본 게시글은 개인적으로 공부하기 위해 작성된 글입니다.

 

저번과 같은 곳에서 진행된다.

 

terminal 1에서 readelf 명령을 통해 make 명령을 통해 빌드한 일부 BPF object file을 분석한다.

readelf --section-details --headers .output/opensnoop.bpf.o

object file은 ELF형식 중 하나이다. ELF(Executable and Linkable Format)는 executable file, object code, shared library, core dump에 대한 공통 표준 파일 형식을 나타낸다. 또한 x86 processor의 binary file에 대한 표준 파일 형식이기도 하다.

● 중점적으로 봐야할 사항들은 아래와 같다.

- 현재 실습하는 machine은 Linux BPF이다. 하기에 이 binary code는 kernel 내의 BPF 가상머신 내에서 실행되는 것이다.

- 이 파일에는 BTF 정보가 포함되어 있다. BTF란, BPF program/map과 관련된 debug정보를 encoding하는 metadata 형식이다. 이 디버그 정보는 map pretty print나 fuction signatures 등에 사용된다.

- table중 .text section header 뒤에 tracepoint로 시작하는 4개의 실행 가능한 section header가 있다. 이들은 4개의 BPF program에 해당된다.

 

이제 4개의program들을 BPF source code에서 찾아볼 것이다.

두번째 탭에 있는 editor를 통해 opensnoop.bpf.c로 접근한다.

// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019 Facebook
// Copyright (c) 2020 Netflix
#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
#include "opensnoop.h"

const volatile pid_t targ_pid = 0;
const volatile pid_t targ_tgid = 0;
const volatile uid_t targ_uid = 0;
const volatile bool targ_failed = false;

struct {
	__uint(type, BPF_MAP_TYPE_HASH);
	__uint(max_entries, 10240);
	__type(key, u32);
	__type(value, struct args_t);
} start SEC(".maps");

struct {
	__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
	__uint(key_size, sizeof(u32));
	__uint(value_size, sizeof(u32));
} events SEC(".maps");

static __always_inline bool valid_uid(uid_t uid) {
	return uid != INVALID_UID;
}

static __always_inline
bool trace_allowed(u32 tgid, u32 pid)
{
	u32 uid;

	/* filters */
	if (targ_tgid && targ_tgid != tgid)
		return false;
	if (targ_pid && targ_pid != pid)
		return false;
	if (valid_uid(targ_uid)) {
		uid = (u32)bpf_get_current_uid_gid();
		if (targ_uid != uid) {
			return false;
		}
	}
	return true;
}

SEC("tracepoint/syscalls/sys_enter_open")
int tracepoint__syscalls__sys_enter_open(struct trace_event_raw_sys_enter* ctx) //here
{
	u64 id = bpf_get_current_pid_tgid();
	/* use kernel terminology here for tgid/pid: */
	u32 tgid = id >> 32;
	u32 pid = id;

	/* store arg info for later lookup */
	if (trace_allowed(tgid, pid)) {
		struct args_t args = {};
		args.fname = (const char *)ctx->args[0];
		args.flags = (int)ctx->args[1];
		bpf_map_update_elem(&start, &pid, &args, 0);
	}
	return 0;
}

SEC("tracepoint/syscalls/sys_enter_openat")
int tracepoint__syscalls__sys_enter_openat(struct trace_event_raw_sys_enter* ctx) //here
{
	u64 id = bpf_get_current_pid_tgid();
	/* use kernel terminology here for tgid/pid: */
	u32 tgid = id >> 32;
	u32 pid = id;

	/* store arg info for later lookup */
	if (trace_allowed(tgid, pid)) {
		struct args_t args = {};
		args.fname = (const char *)ctx->args[1];
		args.flags = (int)ctx->args[2];
		bpf_map_update_elem(&start, &pid, &args, 0);
	}
	return 0;
}

static __always_inline
int trace_exit(struct trace_event_raw_sys_exit* ctx)
{
	struct event event = {};
	struct args_t *ap;
	uintptr_t stack[3];
	int ret;
	u32 pid = bpf_get_current_pid_tgid();

	ap = bpf_map_lookup_elem(&start, &pid);
	if (!ap)
		return 0;	/* missed entry */
	ret = ctx->ret;
	if (targ_failed && ret >= 0)
		goto cleanup;	/* want failed only */

	/* event data */
	event.pid = bpf_get_current_pid_tgid() >> 32;
	event.uid = bpf_get_current_uid_gid();
	bpf_get_current_comm(&event.comm, sizeof(event.comm));
	bpf_probe_read_user_str(&event.fname, sizeof(event.fname), ap->fname);
	event.flags = ap->flags;
	event.ret = ret;

	bpf_get_stack(ctx, &stack, sizeof(stack),
		      BPF_F_USER_STACK);
	/* Skip the first address that is usually the syscall it-self */
	event.callers[0] = stack[1];
	event.callers[1] = stack[2];

	/* emit event */
	bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU,
			      &event, sizeof(event));

cleanup:
	bpf_map_delete_elem(&start, &pid);
	return 0;
}

SEC("tracepoint/syscalls/sys_exit_open")
int tracepoint__syscalls__sys_exit_open(struct trace_event_raw_sys_exit* ctx) //here
{
	return trace_exit(ctx);
}

SEC("tracepoint/syscalls/sys_exit_openat")
int tracepoint__syscalls__sys_exit_openat(struct trace_event_raw_sys_exit* ctx) //here
{
	return trace_exit(ctx);
}

char LICENSE[] SEC("license") = "GPL";

 상기의 code내에서 int tracepoint__syscalls ....로 시작하는 function들을 4개 찾을 수 있다. 해당되는 부분에 //here을 통해 표기하였다.

 이들은 각각 readelf에 의해 나열된 실행 가능한 section에 해당하는 SEC() macro가 앞에 온다. 그리고 코드를 부착해야하는 eBPF hook를 정의한다SEC("tracepoint/<category>/<name>")). sys_enter_open과 sys_enter_openat에 대한 본 실습의 경우 eBPF code는 open 및 openat syscall이 수행될 때마다 호출되어야한다. Tracepoint들은 실행중인 kernel에서 코드를 부탁하는 데 사용할 수 있는 kernel code의 static marker이다. 이러한 tracepoint는 종종 퍼포먼스(성능)를 측정하기 위해 다양한 위치에 배치될 수 있다.

tracepoint__syscalls__sys_enter_open 및 tracepoint__syscalls__sys_enter_openat 함수는 open()/openat() syscall이 실행될 때마다 실행된다. 이후에 호출의 인자(파일 이름 등)를 parsing하고 이 정보를 BPF map에 기록한다. 기록된 곳에서 여기에서 우리의 compile된 opensnoop.c binary부분인 사용자 공간 프로그램(USP)이 이를 읽고 STDOUT으로 출력할 수 있다.

반응형

'ebpf' 카테고리의 다른 글

O’Reilly Report What is eBPF? - tutorial 4  (0) 2023.07.21
O’Reilly Report What is eBPF? - tutorial 3  (0) 2023.07.21
O’Reilly Report What is eBPF? - tutorial  (0) 2023.07.20
google/ buzzer (eBPF fuzzer toolchain)  (0) 2023.07.19
eBPF-fuzzer  (0) 2023.07.19
반응형

본 게시글은 개인적으로 공부하기 위해 작성된 글입니다.

 

opensnoop : trace open() syscalls system-wide, and prints various details.

-> 리눅스 시스템에서 파일 오픈(open) 시스템 콜을 실시간으로 모니터링하는 도구!

 

eBPF는 아래와 같이 두가지 이상의 부분의 구성딘다.

● A User-space program (USP) that declared the kernel space program and attaches it to the relevant tracepoint/probe

● A kernel-spave program (KSP) is what gets triggerd and runs inside the kernel once the tracepoint/probe is met.

 

상기의 두 프로그램은 직접적으로 communication이 불가능하기에 buffer를 활용하여 data를 주고받습니다.

eBPF의 경우 다른 종류의 BPF map을 통해 구현되는 경우를 예시로 할 수 있다.

 

우선적으로 build를 수행한다.

make opensnoop

 Compile된 opensnoop binary를 실행하기 위해서는 CAP_BPF 권한이 요구된다. 이는 우리가 수행하여는 로직(code)이 권한이 부여된 BPF작업( ex. eBPF code를 kernel에 load)을 수행하고 많은 Linux 배포판들이 eBPF를 허용하지 않기에 필수적이다. CAP_BPF는 Linux kernel 5.8이후부터 사용가능하며 모든 타입의 BPF program 적재, 대부분의 맵 유형 생성, BTF 적재, 프로그램 및 맵의 반복(아마 중복사용을 의미하는 것 같다)을 허용한다. 굳이 권한을 나눈 이유는 overload된 CAP_SYS_ADMIN기능으로부터 BPF의 기능을 독립하기 위해 도입되었다.

 

다시 console로 돌아가서 openscoop을 수행해보자.

./opensnoop

 opensnoop은 file이 열릴때마다 출력을 표시할 것이다. 하지만 현재는 주어진 vm에서 진행되고 있으므로 관찰을 위해 event들을 생성할 것이다. 다른 terminal에서 아래의 명령을 수행한 이후, 다시 원래의 terminal로 돌아가서 다수의 file들이 cat을 수행하기 위해 접근된 것을 확인할 수 있다.

cat /etc/os-release

또한, 마지막 line(systemd)과 같이 vm에서 실행 중인 다른 process에서 생성된 출력 역시 확인가능하다.

 

ref

https://isovalent.com/books/ebpf/

 

Isovalent - O’Reilly Report: What is eBPF?

In this O’Reilly report, you will learn how eBPF's ability to dynamically change the behavior of the kernel can be tremendously useful.

isovalent.com

 

반응형

'ebpf' 카테고리의 다른 글

O’Reilly Report What is eBPF? - tutorial 3  (0) 2023.07.21
O’Reilly Report What is eBPF? - tutorial 2  (0) 2023.07.20
google/ buzzer (eBPF fuzzer toolchain)  (0) 2023.07.19
eBPF-fuzzer  (0) 2023.07.19
BPF JIT spray  (0) 2023.03.06

+ Recent posts