Skip to content

Commit 050b84f

Browse files
Merge branch 'main' into tesla/non-k8s/dynamic-config
2 parents 6306430 + 6bd41e2 commit 050b84f

File tree

70 files changed

+1375
-295
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+1375
-295
lines changed

.github/workflows/ci-latest-release.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ jobs:
4747
runs-on: ubuntu-latest-16-cores
4848
permissions:
4949
id-token: write
50-
timeout-minutes: 120
50+
timeout-minutes: 150
5151
steps:
5252
- uses: actions/checkout@v3
5353
with:
@@ -109,7 +109,7 @@ jobs:
109109
- name: Test KubeArmor using Ginkgo
110110
run: |
111111
go install -mod=mod github.com/onsi/ginkgo/v2/ginkgo
112-
make
112+
ginkgo --vv --flake-attempts=10 --timeout=10m smoke/
113113
working-directory: ./tests/k8s_env
114114
timeout-minutes: 30
115115

.github/workflows/ci-test-ginkgo.yml

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ on:
1717
- "tests/**"
1818
- "protobuf/**"
1919
- ".github/workflows/ci-test-ginkgo.yml"
20+
- "examples/multiubuntu/build/**"
2021
- "pkg/KubeArmorOperator/**"
2122
- "deployments/helm/**"
2223

.github/workflows/ci-test-ubi-image.yml

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ on:
1717
- "tests/**"
1818
- "protobuf/**"
1919
- ".github/workflows/ci-test-ginkgo.yml"
20+
- "examples/multiubuntu/build/**"
2021
- "pkg/KubeArmorOperator/**"
2122
- "deployments/helm/**"
2223

.github/workflows/scorecard.yml

-5
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,6 @@ jobs:
4141
with:
4242
results_file: results.sarif
4343
results_format: sarif
44-
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
45-
# - you want to enable the Branch-Protection check on a *public* repository, or
46-
# - you are installing Scorecard on a *private* repository
47-
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat.
48-
repo_token: ${{ secrets.SCORECARD_TOKEN }}
4944

5045
# Public repositories:
5146
# - Publish results to OpenSSF REST API for easy access by consumers

Dockerfile

+2
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ ENV KUBEARMOR_UBI=true
8383

8484
LABEL name="kubearmor" \
8585
vendor="Accuknox" \
86+
maintainer="Barun Acharya, Ramakant Sharma" \
8687
version=${VERSION} \
8788
release=${VERSION} \
8889
summary="kubearmor container image based on redhat ubi" \
@@ -119,6 +120,7 @@ ENV KUBEARMOR_UBI=true
119120

120121
LABEL name="kubearmor" \
121122
vendor="Accuknox" \
123+
maintainer="Barun Acharya, Ramakant Sharma" \
122124
version=${VERSION} \
123125
release=${VERSION} \
124126
summary="kubearmor container image based on redhat ubi" \

Dockerfile.init

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ ARG VERSION=latest
88

99
LABEL name="kubearmor-init" \
1010
vendor="Accuknox" \
11+
maintainer="Barun Acharya, Ramakant Sharma" \
1112
version=${VERSION} \
1213
release=${VERSION} \
1314
summary="kubearmor-init container image based on redhat ubi" \

KubeArmor/BPF/enforcer.bpf.c

+5-3
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,10 @@ int BPF_PROG(enforce_proc, struct linux_binprm *bprm, int ret) {
7575
if (src_offset == NULL)
7676
fromSourceCheck = false;
7777

78-
void *src_ptr = &src_buf->buf[*src_offset];
78+
void *src_ptr;
79+
if (src_buf->buf[*src_offset]) {
80+
src_ptr = &src_buf->buf[*src_offset];
81+
}
7982
if (src_ptr == NULL)
8083
fromSourceCheck = false;
8184

@@ -152,10 +155,9 @@ int BPF_PROG(enforce_proc, struct linux_binprm *bprm, int ret) {
152155
goto decision;
153156
}
154157

155-
156158
// match exec name
157159
struct qstr d_name;
158-
d_name = BPF_CORE_READ(f_path.dentry,d_name);
160+
d_name = BPF_CORE_READ(f_path.dentry, d_name);
159161
bpf_map_update_elem(&bufk, &two, z, BPF_ANY);
160162
bpf_probe_read_str(pk->path, MAX_STRING_SIZE, d_name.name);
161163

KubeArmor/BPF/shared.h

+16-15
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,9 @@ static inline void get_outer_key(struct outer_key *pokey,
272272
struct task_struct *t) {
273273
pokey->pid_ns = get_task_pid_ns_id(t);
274274
pokey->mnt_ns = get_task_mnt_ns_id(t);
275+
// TODO: Use cgroup ns as well for host process identification to support enforcement on deployments using hostpidns
276+
// u32 cg_ns = BPF_CORE_READ(t, nsproxy, cgroup_ns, ns).inum;
277+
// if (pokey->pid_ns == PROC_PID_INIT_INO && cg_ns == PROC_CGROUP_INIT_INO) {
275278
if (pokey->pid_ns == PROC_PID_INIT_INO) {
276279
pokey->pid_ns = 0;
277280
pokey->mnt_ns = 0;
@@ -288,20 +291,13 @@ static __always_inline u32 init_context(event *event_data) {
288291
event_data->host_ppid = get_task_ppid(task);
289292
event_data->host_pid = bpf_get_current_pid_tgid() >> 32;
290293

291-
u32 pid = get_task_ns_tgid(task);
292-
if (event_data->host_pid == pid) { // host
293-
event_data->pid_id = 0;
294-
event_data->mnt_id = 0;
295-
296-
event_data->ppid = get_task_ppid(task);
297-
event_data->pid = bpf_get_current_pid_tgid() >> 32;
298-
} else { // container
299-
event_data->pid_id = get_task_pid_ns_id(task);
300-
event_data->mnt_id = get_task_mnt_ns_id(task);
294+
struct outer_key okey;
295+
get_outer_key(&okey, task);
296+
event_data->pid_id = okey.pid_ns;
297+
event_data->mnt_id = okey.mnt_ns;
301298

302-
event_data->ppid = get_task_ns_ppid(task);
303-
event_data->pid = pid;
304-
}
299+
event_data->ppid = get_task_ppid(task);
300+
event_data->pid = get_task_ns_tgid(task);
305301

306302
event_data->uid = bpf_get_current_uid_gid();
307303

@@ -487,10 +483,15 @@ static inline int match_and_enforce_path_hooks(struct path *f_path, u32 id,
487483
if (src_offset == NULL)
488484
fromSourceCheck = false;
489485

490-
void *ptr = &src_buf->buf[*src_offset];
486+
void *src_ptr;
487+
if (src_buf->buf[*src_offset]) {
488+
src_ptr = &src_buf->buf[*src_offset];
489+
}
490+
if (src_ptr == NULL)
491+
fromSourceCheck = false;
491492

492493
if (fromSourceCheck) {
493-
bpf_probe_read_str(store->source, MAX_STRING_SIZE, ptr);
494+
bpf_probe_read_str(store->source, MAX_STRING_SIZE, src_ptr);
494495

495496
val = bpf_map_lookup_elem(inner, store);
496497

KubeArmor/BPF/system_monitor.c

+56-28
Original file line numberDiff line numberDiff line change
@@ -609,48 +609,68 @@ static __always_inline int save_context_to_buffer(bufs_t *bufs_p, void *ptr)
609609
return 0;
610610
}
611611

612-
static __always_inline int save_str_to_buffer(bufs_t *bufs_p, void *ptr)
613-
{
614-
612+
static __always_inline int save_str_to_buffer(bufs_t *bufs_p, void *ptr) {
615613
u32 *off = get_buffer_offset(DATA_BUF_TYPE);
616-
617-
if (off == NULL)
618-
{
614+
if (off == NULL) {
619615
return -1;
620616
}
621617

622-
if (*off > MAX_BUFFER_SIZE - MAX_STRING_SIZE - sizeof(int))
623-
{
624-
return 0; // no enough space
618+
if (*off >= MAX_BUFFER_SIZE) {
619+
return 0;
625620
}
626621

627-
u8 type = STR_T;
628-
bpf_probe_read(&(bufs_p->buf[*off & (MAX_BUFFER_SIZE - 1)]), 1, &type);
622+
u32 type_pos = *off;
623+
if (type_pos >= MAX_BUFFER_SIZE || type_pos + 1 > MAX_BUFFER_SIZE) {
624+
return 0;
625+
}
629626

630-
*off += 1;
627+
if (MAX_BUFFER_SIZE - type_pos < (1 + sizeof(int) + 1)) {
628+
return 0;
629+
}
631630

632-
if (*off > MAX_BUFFER_SIZE - MAX_STRING_SIZE - sizeof(int))
633-
{
634-
return 0; // no enough space
631+
u32 size_pos = type_pos + 1;
632+
if (size_pos >= MAX_BUFFER_SIZE ||
633+
size_pos + sizeof(int) > MAX_BUFFER_SIZE) {
634+
return 0;
635635
}
636636

637-
int sz = bpf_probe_read_str(&(bufs_p->buf[*off + sizeof(int)]), MAX_STRING_SIZE, ptr);
638-
if (sz > 0)
639-
{
640-
if (*off > MAX_BUFFER_SIZE - sizeof(int))
641-
{
642-
return 0; // no enough space
643-
}
637+
u8 type_val = STR_T;
638+
if (bpf_probe_read(&(bufs_p->buf[type_pos]), sizeof(u8), &type_val) < 0) {
639+
return 0;
640+
}
641+
642+
u32 str_pos = size_pos + sizeof(int);
643+
if (str_pos >= MAX_BUFFER_SIZE || str_pos + MAX_STRING_SIZE > MAX_BUFFER_SIZE) {
644+
return 0;
645+
}
644646

645-
bpf_probe_read(&(bufs_p->buf[*off]), sizeof(int), &sz);
647+
u32 remaining_space = MAX_BUFFER_SIZE - str_pos;
648+
u32 read_size = remaining_space;
649+
if (read_size > MAX_STRING_SIZE) {
650+
read_size = MAX_STRING_SIZE;
651+
}
646652

647-
*off += sz + sizeof(int);
648-
set_buffer_offset(DATA_BUF_TYPE, *off);
653+
if (read_size < MAX_STRING_SIZE) {
654+
return 0;
655+
}
649656

650-
return sz + sizeof(int);
657+
int sz = bpf_probe_read_str(&(bufs_p->buf[str_pos]), read_size, ptr);
658+
if (sz <= 0) {
659+
return 0;
651660
}
652661

653-
return 0;
662+
if (bpf_probe_read(&(bufs_p->buf[size_pos]), sizeof(int), &sz) < 0) {
663+
return 0;
664+
}
665+
666+
u32 new_off = str_pos + sz;
667+
if (new_off > MAX_BUFFER_SIZE) {
668+
return 0;
669+
}
670+
671+
set_buffer_offset(DATA_BUF_TYPE, new_off);
672+
673+
return sz + sizeof(int);
654674
}
655675

656676
static __always_inline bool prepend_path(struct path *path, bufs_t *string_p, int buf_type)
@@ -1019,7 +1039,7 @@ static __always_inline u32 init_context(sys_context_t *context)
10191039
}
10201040
}
10211041

1022-
#if (defined(BTF_SUPPORTED))
1042+
#if LINUX_VERSION_CODE > KERNEL_VERSION(5, 2, 0) // min version that supports 1 million instructions
10231043
struct fs_struct *fs;
10241044
fs = READ_KERN(task->fs);
10251045
struct path path = READ_KERN(fs->pwd);
@@ -1046,6 +1066,13 @@ static __always_inline u32 init_context(sys_context_t *context)
10461066

10471067
// To check if subsequent alerts should be dropped per container
10481068
static __always_inline bool should_drop_alerts_per_container(sys_context_t *context, struct pt_regs *ctx, u32 types, args_t *args) {
1069+
#if LINUX_VERSION_CODE > KERNEL_VERSION(5, 2, 0)
1070+
1071+
// throttling for host in case of apparmor is handled in userspace
1072+
if (context->pid_id == 0 && context->mnt_id == 0) {
1073+
return false;
1074+
}
1075+
10491076
u64 current_timestamp = bpf_ktime_get_ns();
10501077

10511078
struct outer_key key = {
@@ -1112,6 +1139,7 @@ static __always_inline bool should_drop_alerts_per_container(sys_context_t *cont
11121139
}
11131140

11141141
bpf_map_update_elem(&kubearmor_alert_throttle, &key, state, BPF_ANY);
1142+
#endif
11151143
return false;
11161144
}
11171145

KubeArmor/common/common.go

+8
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"sort"
1919
"strconv"
2020
"strings"
21+
"sync"
2122
"time"
2223

2324
kc "github.com/kubearmor/KubeArmor/KubeArmor/config"
@@ -291,7 +292,11 @@ func GetCommandOutputWithoutErr(cmd string, args []string) string {
291292
return ""
292293
}
293294

295+
var wg sync.WaitGroup
296+
wg.Add(1)
297+
294298
go func() {
299+
defer wg.Done()
295300
defer func() {
296301
if err = stdin.Close(); err != nil {
297302
kg.Warnf("Error closing stdin %s\n", err)
@@ -300,6 +305,9 @@ func GetCommandOutputWithoutErr(cmd string, args []string) string {
300305
_, _ = io.WriteString(stdin, "values written to stdin are passed to cmd's standard input")
301306
}()
302307

308+
// Wait for the stdin writing to complete
309+
wg.Wait()
310+
303311
out, err := res.CombinedOutput()
304312
if err != nil {
305313
return ""

KubeArmor/config/config.go

+15-6
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,12 @@ type KubearmorConfig struct {
5656

5757
StateAgent bool // enable KubeArmor state agent
5858

59-
AlertThrottling bool // Enable/Disable Alert Throttling
60-
MaxAlertPerSec int // Maximum alerts allowed per second
61-
ThrottleSec int // Number of seconds for which subsequent alerts will be dropped
62-
AnnotateResources bool // enable annotations by kubearmor if kubearmor-controller is not present
59+
AlertThrottling bool // Enable/Disable Alert Throttling
60+
MaxAlertPerSec int32 // Maximum alerts allowed per second
61+
ThrottleSec int32 // Number of seconds for which subsequent alerts will be dropped
62+
AnnotateResources bool // enable annotations by kubearmor if kubearmor-controller is not present
63+
64+
ProcFsMount string // path where procfs is hosted
6365
}
6466

6567
// GlobalCfg Global configuration for Kubearmor
@@ -105,6 +107,7 @@ const (
105107
ConfigMaxAlertPerSec string = "maxAlertPerSec"
106108
ConfigThrottleSec string = "throttleSec"
107109
ConfigAnnotateResources string = "annotateResources"
110+
ConfigProcFsMount string = "procfsMount"
108111
)
109112

110113
func readCmdLineParams() {
@@ -161,6 +164,8 @@ func readCmdLineParams() {
161164

162165
annotateResources := flag.Bool(ConfigAnnotateResources, false, "for kubearmor deployment without kubearmor-controller")
163166

167+
procFsMount := flag.String(ConfigProcFsMount, "/proc", "Path to the BPF filesystem to use for storing maps")
168+
164169
flags := []string{}
165170
flag.VisitAll(func(f *flag.Flag) {
166171
kv := fmt.Sprintf("%s:%v", f.Name, f.Value)
@@ -222,6 +227,8 @@ func readCmdLineParams() {
222227
viper.SetDefault(ConfigThrottleSec, *throttleSec)
223228

224229
viper.SetDefault(ConfigAnnotateResources, *annotateResources)
230+
231+
viper.SetDefault(ConfigProcFsMount, *procFsMount)
225232
}
226233

227234
// LoadConfig Load configuration
@@ -296,6 +303,8 @@ func LoadConfig() error {
296303
GlobalCfg.StateAgent = viper.GetBool(ConfigStateAgent)
297304

298305
GlobalCfg.AnnotateResources = viper.GetBool(ConfigAnnotateResources)
306+
307+
GlobalCfg.ProcFsMount = viper.GetString(ConfigProcFsMount)
299308

300309
LoadDynamicConfig()
301310

@@ -329,6 +338,6 @@ func LoadDynamicConfig() {
329338
GlobalCfg.DefaultPostureLogs = viper.GetBool(ConfigDefaultPostureLogs)
330339

331340
GlobalCfg.AlertThrottling = viper.GetBool(ConfigAlertThrottling)
332-
GlobalCfg.MaxAlertPerSec = viper.GetInt(ConfigMaxAlertPerSec)
333-
GlobalCfg.ThrottleSec = viper.GetInt(ConfigThrottleSec)
341+
GlobalCfg.MaxAlertPerSec = int32(viper.GetInt(ConfigMaxAlertPerSec))
342+
GlobalCfg.ThrottleSec = int32(viper.GetInt(ConfigThrottleSec))
334343
}

0 commit comments

Comments
 (0)