Skip to content

Commit def9b04

Browse files
committed
adding dns preset
Signed-off-by: Shreyas220 <[email protected]>
1 parent bbdc04d commit def9b04

16 files changed

+943
-1
lines changed

KubeArmor/BPF/dnskprobe.bpf.c

+113
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
//go:build ignore
2+
#include "shared.h"
3+
#include <bpf/bpf_helpers.h>
4+
#include <bpf/bpf_core_read.h>
5+
#include <bpf/bpf_tracing.h>
6+
#include <bpf/bpf_endian.h>
7+
8+
char LICENSE[] SEC("license") = "Dual BSD/GPL";
9+
10+
#define AF_INET 2
11+
#define ETH_P_IP 0x0800
12+
13+
static __always_inline u32 get_pid_ns_id(struct nsproxy *ns)
14+
{
15+
// Use BPF_CORE_READ to safely access kernel space memory
16+
struct pid_namespace *pidns = BPF_CORE_READ(ns, pid_ns_for_children);
17+
return BPF_CORE_READ(pidns, ns.inum);
18+
}
19+
20+
static __always_inline u32 get_task_pid_ns_id(struct task_struct *task)
21+
{
22+
return get_pid_ns_id(BPF_CORE_READ(task,nsproxy));
23+
}
24+
25+
static __always_inline u32 get_mnt_ns_id(struct nsproxy *ns)
26+
{
27+
// Use BPF_CORE_READ to safely access kernel space memory
28+
struct mnt_namespace *mntns = BPF_CORE_READ(ns, mnt_ns);
29+
return BPF_CORE_READ(mntns, ns.inum);
30+
}
31+
32+
static __always_inline u32 get_task_mnt_ns_id(struct task_struct *task)
33+
{
34+
return get_mnt_ns_id(BPF_CORE_READ(task,nsproxy));
35+
}
36+
37+
struct outer_key {
38+
u32 pid_ns;
39+
u32 mnt_ns;
40+
};
41+
42+
struct pid_maps{
43+
__uint(type, BPF_MAP_TYPE_HASH);
44+
__uint(max_entries, 256);
45+
__uint(key_size, sizeof(struct outer_key));
46+
__uint(value_size, sizeof(u32));
47+
__uint(pinning, LIBBPF_PIN_BY_NAME);
48+
} ;
49+
50+
struct pid_maps dns_container_maps SEC(".maps");
51+
52+
struct socket_print_key {
53+
__u32 remote_port;
54+
__u32 local_port;
55+
};
56+
57+
struct {
58+
__uint(type, BPF_MAP_TYPE_HASH);
59+
__uint(key_size, sizeof(struct socket_print_key));
60+
__uint(value_size, sizeof(struct __sk_buff));
61+
__uint(max_entries, 128);
62+
} socket_print SEC(".maps");
63+
64+
#define ETH_P_IP 0x0800
65+
66+
SEC("kprobe/udp_sendmsg")
67+
int BPF_KPROBE(ig_udp_sendmsg, struct sock *sk , struct msghdr *msg ,size_t len)
68+
{
69+
struct outer_key key;
70+
u32 *value;
71+
72+
struct task_struct *t = (struct task_struct *)bpf_get_current_task();
73+
74+
key.pid_ns = get_task_pid_ns_id(t);
75+
key.mnt_ns = get_task_mnt_ns_id(t);
76+
77+
value = bpf_map_lookup_elem(&dns_container_maps, &key);
78+
if (!value) {
79+
return 0;
80+
}
81+
bpf_printk("Kprobe container found pid %u and mnt %u", key.pid_ns, key.mnt_ns);
82+
83+
struct sock_common skcom;
84+
85+
bpf_probe_read(&skcom, sizeof(skcom), &sk->__sk_common);
86+
87+
u16 sport = skcom.skc_num;
88+
u16 dport = skcom.skc_dport;
89+
90+
// Processing only packets on port 53.
91+
// 13568 = ntohs(53);
92+
if (sport == 13568 || dport == 13568) {
93+
u32 saddr = skcom.skc_rcv_saddr;
94+
u32 daddr = skcom.skc_daddr;
95+
struct sockets_key socket_key = {0};
96+
BPF_CORE_READ_INTO(&socket_key.netns, sk, __sk_common.skc_net.net,ns.inum);
97+
socket_key.sport = sport;
98+
socket_key.dport = bpf_ntohs(dport);
99+
socket_key.saddr = bpf_ntohs(saddr);
100+
socket_key.daddr = bpf_ntohs(daddr);
101+
102+
struct socket_value socket_value;
103+
104+
socket_value.pid_tgid = bpf_get_current_pid_tgid();
105+
socket_value.uid_gid = bpf_get_current_uid_gid();
106+
bpf_get_current_comm(&socket_value.task, sizeof(socket_value.task));
107+
108+
bpf_map_update_elem(&dns_shared_map, &socket_key, &socket_value, BPF_ANY);
109+
110+
}
111+
112+
return 0;
113+
}

KubeArmor/BPF/dnssocket.bpf.c

+134
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
//go:build ignore
2+
#include "shared.h"
3+
#include <bpf/bpf_helpers.h>
4+
#include <bpf/bpf_core_read.h>
5+
#include <bpf/bpf_tracing.h>
6+
#include <bpf/bpf_endian.h>
7+
8+
char LICENSE[] SEC("license") = "Dual BSD/GPL";
9+
10+
#define ETH_P_IP 0x0800 /* Internet Protocol packet */
11+
#define ETH_HLEN 14
12+
#define PACKET_HOST 0
13+
#define MAX_BUF_SIZE 300
14+
#define DNS_TYPE_A 1 // https://datatracker.ietf.org/doc/html/rfc1035#section-3.2.2
15+
#define MAX_DNS_NAME 255
16+
17+
struct event_t {
18+
__u32 netns;
19+
__u32 saddr_v4;
20+
__u32 daddr_v4;
21+
__u32 af;
22+
__u16 sport;
23+
__u16 dport;
24+
__u32 dns_length;
25+
__u64 pid;
26+
__u64 ppid;
27+
__u8 task[TASK_COMM_LEN];
28+
__u16 payload[MAX_BUF_SIZE];
29+
};
30+
31+
32+
struct {
33+
__uint(type, BPF_MAP_TYPE_RINGBUF);
34+
__uint(max_entries, 1 << 24);
35+
} socket_events SEC(".maps");
36+
37+
# define DNS_OFF (ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr))
38+
39+
static volatile const __u32 current_netns ;
40+
41+
SEC("socket")
42+
int simple_socket_handler(struct __sk_buff *skb){
43+
44+
__u32 h_proto;
45+
__u8 protoc;
46+
__u8 name[MAX_DNS_NAME];
47+
__u16 sport, dport, l4_off, dns_off, id;
48+
//Check if the protocol is Ipv4
49+
bpf_skb_load_bytes(skb, offsetof(struct ethhdr, h_proto), &h_proto, sizeof(h_proto));
50+
51+
if (bpf_ntohs(h_proto) == ETH_P_IP){
52+
bpf_skb_load_bytes(skb, ETH_HLEN + offsetof(struct iphdr, protocol),&protoc, sizeof(protoc));
53+
54+
if (protoc == IPPROTO_UDP){
55+
__u8 ihl_byte;
56+
bpf_skb_load_bytes(skb, ETH_HLEN, &ihl_byte,sizeof(ihl_byte));
57+
struct iphdr *iph = (struct iphdr *)&ihl_byte;
58+
__u8 ip_header_len = iph->ihl * 4;
59+
l4_off = ETH_HLEN + ip_header_len;
60+
61+
int off = l4_off;
62+
63+
if (skb->pkt_type == PACKET_HOST)
64+
off += offsetof(struct udphdr, dest);
65+
else
66+
off += offsetof(struct udphdr, source);
67+
68+
bpf_skb_load_bytes(skb, l4_off + offsetof(struct udphdr, dest),&dport, sizeof(dport));
69+
bpf_skb_load_bytes(skb, l4_off + offsetof(struct udphdr, source),&sport, sizeof(sport));
70+
71+
if (bpf_ntohs(sport) == 53 || bpf_ntohs(dport) == 53 || bpf_ntohs(sport) == 5353 || bpf_ntohs(dport) == 5353 ) {
72+
bpf_printk("currentns is %u",current_netns);
73+
struct sockets_key socket_key = {0,0,0,0};
74+
long err;
75+
__u8 packet_present = 0;
76+
77+
__u32 port;
78+
err = bpf_skb_load_bytes(skb, off, &port , sizeof(port));
79+
if (err < 0)
80+
return 0;
81+
82+
struct event_t *event;
83+
event = bpf_ringbuf_reserve(&socket_events, sizeof(struct event_t), 0);
84+
if (!event) {
85+
return 0;
86+
}
87+
88+
__u16 udp_total_length;
89+
bpf_skb_load_bytes(skb, l4_off + offsetof(struct udphdr, len), &udp_total_length, sizeof(udp_total_length));
90+
91+
__u32 dns_length = bpf_ntohs(udp_total_length) - sizeof(struct udphdr);
92+
event->dns_length = bpf_ntohs(dns_length);
93+
94+
u32 len_payload = 0;
95+
for (len_payload = 0; len_payload < 328; len_payload++) {
96+
if (len_payload == dns_length-1){
97+
break;
98+
}
99+
}
100+
len_payload = len_payload+1;
101+
102+
err = bpf_skb_load_bytes(skb, DNS_OFF, event->payload, len_payload);
103+
if (err != 0) {
104+
bpf_ringbuf_discard(event, 0);
105+
return 0;
106+
}
107+
108+
bpf_skb_load_bytes(skb, ETH_HLEN + offsetof(struct iphdr, saddr),&event->saddr_v4, sizeof(event->saddr_v4));
109+
bpf_skb_load_bytes(skb, ETH_HLEN + offsetof(struct iphdr, daddr),&event->daddr_v4, sizeof(event->daddr_v4));
110+
111+
socket_key.netns = current_netns;
112+
socket_key.saddr = bpf_ntohs(event->saddr_v4);
113+
socket_key.daddr = bpf_ntohs(event->daddr_v4);
114+
socket_key.sport = bpf_ntohs(sport);
115+
socket_key.dport = bpf_ntohs(dport);
116+
117+
struct socket_value *skb_val;
118+
skb_val = bpf_map_lookup_elem(&dns_shared_map, &socket_key);
119+
if (skb_val != NULL){
120+
event->pid = skb_val->uid_gid;
121+
event->ppid = skb_val->pid_tgid;
122+
packet_present = (uint32_t)1;
123+
}
124+
125+
event->sport = bpf_ntohs(sport);
126+
event->dport = bpf_ntohs(dport);
127+
event->netns = current_netns;
128+
129+
bpf_ringbuf_submit(event, 0);
130+
}
131+
}
132+
}
133+
return 0;
134+
}

KubeArmor/BPF/shared.h

+23
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,29 @@ enum network_check_type {
3636
sock_proto
3737
}; // configure to check for network protocol or socket type
3838

39+
struct sockets_key {
40+
__u32 netns;
41+
__u32 saddr;
42+
__u32 daddr;
43+
__u16 sport;
44+
__u16 dport;
45+
46+
};
47+
48+
struct socket_value {
49+
__u8 task[TASK_COMM_LEN];
50+
__u64 pid_tgid;
51+
__u64 uid_gid;
52+
};
53+
54+
struct {
55+
__uint(type, BPF_MAP_TYPE_HASH);
56+
__uint(key_size, sizeof(struct sockets_key));
57+
__uint(value_size, sizeof(struct socket_value));
58+
__uint(max_entries, 128);
59+
__uint(pinning, LIBBPF_PIN_BY_NAME);
60+
} dns_shared_map SEC(".maps");
61+
3962
typedef struct buffers {
4063
char buf[MAX_BUFFER_SIZE];
4164
} bufs_t;

KubeArmor/core/containerdHandler.go

+1
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ func (ch *ContainerdHandler) GetContainerInfo(ctx context.Context, containerID s
192192
}
193193

194194
pid := strconv.Itoa(int(taskRes.Processes[0].Pid))
195+
container.Pid = int(taskRes.Processes[0].Pid)
195196

196197
if data, err := os.Readlink("/proc/" + pid + "/ns/pid"); err == nil {
197198
if _, err := fmt.Sscanf(data, "pid:[%d]\n", &container.PidNS); err != nil {

KubeArmor/core/crioHandler.go

+1
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ func (ch *CrioHandler) GetContainerInfo(ctx context.Context, containerID string,
128128
container.Privileged = containerInfo.Privileged
129129

130130
pid := strconv.Itoa(containerInfo.Pid)
131+
container.Pid = containerInfo.Pid
131132

132133
if data, err := os.Readlink("/proc/" + pid + "/ns/pid"); err == nil {
133134
if _, err := fmt.Sscanf(data, "pid:[%d]\n", &container.PidNS); err != nil {

KubeArmor/core/dockerHandler.go

+1
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ func (dh *DockerHandler) GetContainerInfo(containerID string, OwnerInfo map[stri
143143
// == //
144144

145145
pid := strconv.Itoa(inspect.State.Pid)
146+
container.Pid = inspect.State.Pid
146147

147148
if data, err := os.Readlink("/proc/" + pid + "/ns/pid"); err == nil {
148149
if _, err := fmt.Sscanf(data, "pid:[%d]\n", &container.PidNS); err != nil {

KubeArmor/go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ require (
3636
github.com/kubearmor/KubeArmor/protobuf v0.0.0-20240110164432-c2c1b121cd94
3737
github.com/opencontainers/runtime-spec v1.2.0
3838
github.com/spf13/viper v1.18.2
39+
github.com/vishvananda/netns v0.0.4
3940
go.uber.org/zap v1.26.0
4041
golang.org/x/exp v0.0.0-20240110193028-0dcbfd608b1e
4142
golang.org/x/sys v0.19.0

KubeArmor/presets/basePreset.go

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package presets
2+
3+
import (
4+
fd "github.com/kubearmor/KubeArmor/KubeArmor/feeder"
5+
mon "github.com/kubearmor/KubeArmor/KubeArmor/monitor"
6+
tp "github.com/kubearmor/KubeArmor/KubeArmor/types"
7+
)
8+
9+
type BasePreset struct {
10+
Logger *fd.Feeder
11+
Monitor *mon.SystemMonitor
12+
}
13+
14+
type BasePresetInterface interface {
15+
Name() string
16+
Init() error
17+
RegisterPreset(logger *fd.Feeder, monitor *mon.SystemMonitor) (*BasePresetInterface, error)
18+
RegisterContainer(containerID string, pidns, mntns uint32)
19+
UnregisterContainer(containerID string)
20+
UpdateSecurityPolicies(endPoint tp.EndPoint)
21+
Destroy() error
22+
}

0 commit comments

Comments
 (0)