-
Notifications
You must be signed in to change notification settings - Fork 174
/
Copy pathextract_from_kernel.h
503 lines (450 loc) · 12.5 KB
/
extract_from_kernel.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
/*
* Copyright (C) 2022 The Falco Authors.
*
* This file is dual licensed under either the MIT or GPL 2. See MIT.txt
* or GPL2.txt for full copies of the license.
*/
#pragma once
#include <helpers/base/maps_getters.h>
#include <helpers/base/read_from_task.h>
#include <driver/ppm_flag_helpers.h>
/* Used to convert from page number to KB. */
#define DO_PAGE_SHIFT(x) (x) << (IOC_PAGE_SHIFT - 10)
/* This enum should simplify the capabilities extraction. */
enum capability_type
{
CAP_INHERITABLE = 0,
CAP_PERMITTED = 1,
CAP_EFFECTIVE = 2,
};
/* All the functions that are called in bpf to extract parameters
* start with the `extract` prefix.
*/
/////////////////////////
// SYSCALL ARGUMENTS EXTRACION
////////////////////////
/**
* @brief Extact a specific syscall argument
*
* @param regs pointer to the strcut where we find the arguments
* @param idx index of the argument to extract
* @return generic unsigned long value that can be a pointer to the arg
* or directly the value, it depends on the type of arg.
*/
static __always_inline unsigned long extract__syscall_argument(struct pt_regs *regs, int idx)
{
unsigned long arg;
switch(idx)
{
case 0:
arg = PT_REGS_PARM1_CORE_SYSCALL(regs);
break;
case 1:
arg = PT_REGS_PARM2_CORE_SYSCALL(regs);
break;
case 2:
arg = PT_REGS_PARM3_CORE_SYSCALL(regs);
break;
case 3:
arg = PT_REGS_PARM4_CORE_SYSCALL(regs);
break;
case 4:
arg = PT_REGS_PARM5_CORE_SYSCALL(regs);
break;
case 5:
/* Not defined in libbpf, look at `definitions_helpers.h` */
arg = PT_REGS_PARM6_CORE_SYSCALL(regs);
break;
default:
arg = 0;
}
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);
}
/**
* @brief Extract the fd rlimit
*
* @param task pointer to the task struct.
* @param fdlimit return value passed by reference.
*/
static __always_inline void extract__fdlimit(struct task_struct *task, unsigned long *fdlimit)
{
READ_TASK_FIELD_INTO(fdlimit, task, signal, rlim[RLIMIT_NOFILE].rlim_cur);
}
/////////////////////////
// CAPABILITIES EXTRACTION
////////////////////////
/**
* @brief Extract capabilities
*
* Right now we support only 3 types of capabilities:
* - cap_inheritable
* - cap_permitted
* - cap_effective
*
* To extract the specific capabilities use the enum defined by us
* at the beginning of this file:
* - CAP_INHERITABLE
* - CAP_PERMITTED
* - CAP_EFFECTIVE
*
* @param task pointer to task struct.
* @param capability_type type of capability to extract defined by us.
* @return PPM encoded capability value
*/
static __always_inline u64 extract__capability(struct task_struct *task, enum capability_type capability_type)
{
kernel_cap_t cap_struct;
unsigned long capability;
switch(capability_type)
{
case CAP_INHERITABLE:
READ_TASK_FIELD_INTO(&cap_struct, task, cred, cap_inheritable);
break;
case CAP_PERMITTED:
READ_TASK_FIELD_INTO(&cap_struct, task, cred, cap_permitted);
break;
case CAP_EFFECTIVE:
READ_TASK_FIELD_INTO(&cap_struct, task, cred, cap_effective);
break;
default:
return 0;
break;
}
return capabilities_to_scap(((unsigned long)cap_struct.cap[1] << 32) | cap_struct.cap[0]);
}
/////////////////////////
// PIDS EXTRACION
////////////////////////
/**
* @brief Return the pid struct according to the pid type chosen.
*
* @param task pointer to the task struct.
* @param type pid type.
* @return struct pid * pointer to the right pid struct.
*/
static __always_inline struct pid *extract__task_pid_struct(struct task_struct *task, enum pid_type type)
{
struct pid *task_pid = NULL;
switch(type)
{
/* we cannot take this info from signal struct. */
case PIDTYPE_PID:
READ_TASK_FIELD_INTO(&task_pid, task, thread_pid);
break;
default:
READ_TASK_FIELD_INTO(&task_pid, task, signal, pids[type]);
break;
}
return task_pid;
}
/**
* @brief Returns the pid namespace in which the specified pid was allocated.
*
* @param pid pointer to the task pid struct.
* @return struct pid_namespace* in which the specified pid was allocated.
*/
static __always_inline struct pid_namespace *extract__namespace_of_pid(struct pid *pid)
{
u32 level = 0;
struct pid_namespace *ns = NULL;
if(pid)
{
BPF_CORE_READ_INTO(&level, pid, level);
BPF_CORE_READ_INTO(&ns, pid, numbers[level].ns);
}
return ns;
}
/**
* @brief extract the `xid` (where x can be 'p', 't', ...) according to the
* `pid struct` passed as parameter.
*
* @param pid pointer to the pid struct.
* @param ns pointer to the namespace struct.
* @return pid_t id seen from the pid namespace 'ns'.
*/
static __always_inline pid_t extract__xid_nr_seen_by_namespace(struct pid *pid, struct pid_namespace *ns)
{
struct upid upid = {0};
pid_t nr = 0;
unsigned int pid_level = 0;
unsigned int ns_level = 0;
BPF_CORE_READ_INTO(&pid_level, pid, level);
BPF_CORE_READ_INTO(&ns_level, ns, level);
if(pid && ns_level <= pid_level)
{
BPF_CORE_READ_INTO(&upid, pid, numbers[ns_level]);
if(upid.ns == ns)
{
nr = upid.nr;
}
}
return nr;
}
/*
* Definitions taken from `/include/linux/sched.h`.
*
* the helpers to get the task's different pids as they are seen
* from various namespaces. In all these methods 'nr' stands for 'numeric'.
*
* extract_task_(X)id_nr() : global id, i.e. the id seen from the init namespace;
* extract_task_(X)id_vnr() : virtual id, i.e. the id seen from the pid namespace of current.
*
*/
/**
* @brief Return the `xid` (where x can be `p`, `tg`, `pp` ...) seen from the
* init namespace.
*
* @param task pointer to task struct.
* @param type pid type.
* @return `xid` seen from the init namespace.
*/
static __always_inline pid_t extract__task_xid_nr(struct task_struct *task, enum pid_type type)
{
switch(type)
{
case PIDTYPE_PID:
return READ_TASK_FIELD(task, pid);
case PIDTYPE_TGID:
return READ_TASK_FIELD(task, tgid);
case PIDTYPE_PGID:
return READ_TASK_FIELD(task, real_parent, pid);
default:
return 0;
}
}
/**
* @brief Return the `xid` (where x can be `p`, `tg`, `pp` ...) seen from the
* pid namespace of the current task.
*
* @param task pointer to task struct.
* @param type pid type.
* @return `xid` seen from the current task pid namespace.
*/
static __always_inline pid_t extract__task_xid_vnr(struct task_struct *task, enum pid_type type)
{
struct pid *pid_struct = extract__task_pid_struct(task, type);
struct pid_namespace *pid_namespace_struct = extract__namespace_of_pid(pid_struct);
return extract__xid_nr_seen_by_namespace(pid_struct, pid_namespace_struct);
}
/////////////////////////
// PAGE INFO EXTRACION
////////////////////////
/**
* @brief Extract major page fault number
*
* @param task pointer to task struct.
* @param pgft_maj return value passed by reference.
*/
static __always_inline void extract__pgft_maj(struct task_struct *task, unsigned long *pgft_maj)
{
READ_TASK_FIELD_INTO(pgft_maj, task, maj_flt);
}
/**
* @brief Extract minor page fault number
*
* @param task pointer to task struct.
* @param pgft_min return value passed by reference.
*/
static __always_inline void extract__pgft_min(struct task_struct *task, unsigned long *pgft_min)
{
READ_TASK_FIELD_INTO(pgft_min, task, min_flt);
}
/**
* @brief Extract total page size
*
* @param mm pointer to mm_struct.
* @return number in KB
*/
static __always_inline unsigned long extract__vm_size(struct mm_struct *mm)
{
unsigned long vm_pages = 0;
BPF_CORE_READ_INTO(&vm_pages, mm, total_vm);
return DO_PAGE_SHIFT(vm_pages);
}
/**
* @brief Extract resident page size
*
* @param mm pointer to mm_struct.
* @return number in KB
*/
static __always_inline unsigned long extract__vm_rss(struct mm_struct *mm)
{
unsigned long file_pages = 0;
unsigned long anon_pages = 0;
unsigned long shmem_pages = 0;
BPF_CORE_READ_INTO(&file_pages, mm, rss_stat.count[MM_FILEPAGES].counter);
BPF_CORE_READ_INTO(&anon_pages, mm, rss_stat.count[MM_ANONPAGES].counter);
BPF_CORE_READ_INTO(&shmem_pages, mm, rss_stat.count[MM_SHMEMPAGES].counter);
return DO_PAGE_SHIFT(file_pages + anon_pages + shmem_pages);
}
/**
* @brief Extract swap page size
*
* @param mm pointer to mm_struct.
* @return number in KB
*/
static __always_inline unsigned long extract__vm_swap(struct mm_struct *mm)
{
unsigned long swap_entries = 0;
BPF_CORE_READ_INTO(&swap_entries, mm, rss_stat.count[MM_SWAPENTS].counter);
return DO_PAGE_SHIFT(swap_entries);
}
/////////////////////////
// TTY EXTRACTION
////////////////////////
/**
* @brief Extract encoded tty
*
* @param task pointer to task_struct.
* @return encoded tty number
*/
static __always_inline u32 exctract__tty(struct task_struct *task)
{
int index;
int major;
int minor_start;
READ_TASK_FIELD_INTO(&index, task, signal, tty, index);
READ_TASK_FIELD_INTO(&major, task, signal, tty, driver, major);
READ_TASK_FIELD_INTO(&minor_start, task, signal, tty, driver, minor_start);
return encode_dev(MKDEV(major, minor_start) + index);
}
/////////////////////////
// LOGINUID EXTRACTION
////////////////////////
/**
* @brief Extract loginuid
*
* @param task pointer to task struct
* @param loginuid return value by reference
*/
static __always_inline void extract__loginuid(struct task_struct *task, u32 *loginuid)
{
READ_TASK_FIELD_INTO(loginuid, task, loginuid.val);
}
/////////////////////////
// EXTRACT CLONE FLAGS
////////////////////////
/**
* @brief To extract clone flags we need to read some info in the kernel
*
* @param task pointer to the task struct.
* @param flags internal flag representation.
* @return scap flag representation.
*/
static __always_inline unsigned long extract__clone_flags(struct task_struct *task, unsigned long flags)
{
unsigned long ppm_flags = clone_flags_to_scap(flags);
struct pid *pid = extract__task_pid_struct(task, PIDTYPE_PID);
struct pid_namespace *ns = extract__namespace_of_pid(pid);
unsigned int ns_level;
BPF_CORE_READ_INTO(&ns_level, ns, level);
if(ns_level != 0)
{
flags |= PPM_CL_CHILD_IN_PIDNS;
}
else
{
struct pid_namespace *ns_children;
READ_TASK_FIELD_INTO(&ns_children, task, nsproxy, pid_ns_for_children);
if(ns_children != ns)
{
flags |= PPM_CL_CHILD_IN_PIDNS;
}
}
return ppm_flags;
}
/////////////////////////
// UID EXTRACTION
////////////////////////
/**
* @brief Extract euid
*
* @param task pointer to task struct
* @param euid return value by reference
*/
static __always_inline void extract__euid(struct task_struct *task, u32 *euid)
{
READ_TASK_FIELD_INTO(euid, task, cred, euid.val);
}
/**
* @brief Extract egid
*
* @param task pointer to task struct
* @param egid return value by reference
*/
static __always_inline void extract__egid(struct task_struct *task, u32 *egid)
{
READ_TASK_FIELD_INTO(egid, task, cred, egid.val);
}