1# Copyright 2020 Kinvolk GmbH 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15def _cgroup_filter_func_writer(cgroupmap): 16 if not cgroupmap: 17 return """ 18 static inline int _cgroup_filter() { 19 return 0; 20 } 21 """ 22 23 text = """ 24 BPF_TABLE_PINNED("hash", u64, u64, cgroupset, 1024, "CGROUP_PATH"); 25 26 static inline int _cgroup_filter() { 27 u64 cgroupid = bpf_get_current_cgroup_id(); 28 return cgroupset.lookup(&cgroupid) == NULL; 29 } 30 """ 31 32 return text.replace('CGROUP_PATH', cgroupmap) 33 34def _mntns_filter_func_writer(mntnsmap): 35 if not mntnsmap: 36 return """ 37 static inline int _mntns_filter() { 38 return 0; 39 } 40 """ 41 text = """ 42 #include <linux/nsproxy.h> 43 #include <linux/mount.h> 44 #include <linux/ns_common.h> 45 46 /* see mountsnoop.py: 47 * XXX: struct mnt_namespace is defined in fs/mount.h, which is private 48 * to the VFS and not installed in any kernel-devel packages. So, let's 49 * duplicate the important part of the definition. There are actually 50 * more members in the real struct, but we don't need them, and they're 51 * more likely to change. 52 */ 53 struct mnt_namespace { 54 // This field was removed in https://github.com/torvalds/linux/commit/1a7b8969e664d6af328f00fe6eb7aabd61a71d13 55 #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 11, 0) 56 atomic_t count; 57 #endif 58 struct ns_common ns; 59 }; 60 /* 61 * To add mountsnoop support for --selector option, we need to call 62 * filter_by_containers(). 63 * This function adds code which defines struct mnt_namespace. 64 * The problem is that this struct is also defined in mountsnoop BPF code. 65 * To avoid redefining it in mountnsoop code, we define 66 * MNT_NAMESPACE_DEFINED here. 67 * Then, in mountsnoop code, the struct mnt_namespace definition is guarded 68 * by: 69 * #ifndef MNT_NAMESPACE_DEFINED 70 * // ... 71 * #endif 72 */ 73 #define MNT_NAMESPACE_DEFINED 74 75 BPF_TABLE_PINNED("hash", u64, u32, mount_ns_set, 1024, "MOUNT_NS_PATH"); 76 77 static inline int _mntns_filter() { 78 struct task_struct *current_task; 79 struct nsproxy *nsproxy; 80 struct mnt_namespace *mnt_ns; 81 unsigned int inum; 82 u64 ns_id; 83 84 current_task = (struct task_struct *)bpf_get_current_task(); 85 86 if (bpf_probe_read_kernel(&nsproxy, sizeof(nsproxy), ¤t_task->nsproxy)) 87 return 0; 88 89 if (bpf_probe_read_kernel(&mnt_ns, sizeof(mnt_ns), &nsproxy->mnt_ns)) 90 return 0; 91 92 if (bpf_probe_read_kernel(&inum, sizeof(inum), &mnt_ns->ns.inum)) 93 return 0; 94 95 ns_id = (u64) inum; 96 97 return mount_ns_set.lookup(&ns_id) == NULL; 98 } 99 """ 100 101 return text.replace('MOUNT_NS_PATH', mntnsmap) 102 103def filter_by_containers(args): 104 filter_by_containers_text = """ 105 static inline int container_should_be_filtered() { 106 return _cgroup_filter() || _mntns_filter(); 107 } 108 """ 109 110 cgroupmap_text = _cgroup_filter_func_writer(args.cgroupmap) 111 mntnsmap_text = _mntns_filter_func_writer(args.mntnsmap) 112 113 return cgroupmap_text + mntnsmap_text + filter_by_containers_text 114