
Linux seccomp与安全模块一、seccomp核心结构----------------c#include#include// seccomp过滤模式#define SECCOMP_MODE_DISABLED 0 // 禁用#define SECCOMP_MODE_STRICT 1 // 严格模式只允许read/write/_exit/sigreturn#define SECCOMP_MODE_FILTER 2 // 过滤模式BPF规则// seccomp过滤结构struct seccomp_filter {struct seccomp_filter *prev; // 上一级过滤器struct bpf_prog *prog; // BPF程序struct notification *notif; // 用户态通知bool log;struct seccomp_filter *parent;};// 进程seccomp状态struct seccomp {int mode; // 当前模式struct seccomp_filter *filter; // 过滤器链};// BPF指令结构struct sock_filter {__u16 code; // 操作码__u8 jt; // 跳转真__u8 jf; // 跳转假__u32 k; // 通用字段};// BPF程序struct sock_fprog {unsigned short len;struct sock_filter *filter;};二、seccomp过滤规则---------------c#include#include#include// seccomp BPF辅助宏#define SECCOMP_RET_KILL_PROCESS 0x80000000#define SECCOMP_RET_KILL_THREAD 0x00000000#define SECCOMP_RET_TRAP 0x00030000#define SECCOMP_RET_ERRNO 0x00050000#define SECCOMP_RET_TRACE 0x7ff00000#define SECCOMP_RET_ALLOW 0x7fff0000// BPF加载器struct sock_fprog_kern {unsigned short len;struct sock_filter *filter;};// 加载seccomp过滤器static long seccomp_attach_filter(struct seccomp_filter *filter) {struct task_struct *task current;struct seccomp_filter *orig task-seccomp.filter;// 将过滤器放入链表头部filter-prev orig;task-seccomp.filter filter;// 更新模式task-seccomp.mode SECCOMP_MODE_FILTER;return 0;}// 系统调用过滤检查static int seccomp_check_syscall(int nr,struct pt_regs *regs) {struct seccomp_filter *filter;int ret SECCOMP_RET_ALLOW;// 遍历过滤器链for (filter current-seccomp.filter;filter;filter filter-prev) {// 执行BPF过滤ret BPF_PROG_RUN(filter-prog, regs);if (ret ! SECCOMP_RET_ALLOW)break;}return ret;}// 严格的系统调用白名单static int seccomp_strict_check(struct seccomp_data *sd) {// 只允许基本的系统调用switch (sd-nr) {case __NR_read:case __NR_write:case __NR_exit:case __NR_exit_group:case __NR_sigreturn:case __NR_rt_sigreturn:return SECCOMP_RET_ALLOW;default:// 记录违规pr_warn(seccomp: pid%d blocked syscall %d\n,task_pid_nr(current), sd-nr);return SECCOMP_RET_KILL_THREAD;}}// 参数过滤基于参数值的过滤static int seccomp_arg_filter(struct seccomp_data *sd) {// 限制open只读模式if (sd-nr __NR_open ||sd-nr __NR_openat) {int flags (int)sd-args[1];// 只允许O_RDONLYif (flags O_WRONLY || flags O_RDWR) {return SECCOMP_RET_ERRNO | EACCES;}}// 限制网络socket类型if (sd-nr __NR_socket) {int domain (int)sd-args[0];int type (int)sd-args[1];// 只允许AF_UNIX和AF_INETif (domain ! AF_UNIX domain ! AF_INET) {return SECCOMP_RET_ERRNO | EAFNOSUPPORT;}// 只允许SOCK_STREAMif (type ! SOCK_STREAM) {return SECCOMP_RET_ERRNO | EPROTONOSUPPORT;}}return SECCOMP_RET_ALLOW;}三、seccomp用户态通知----------------c#include#include// seccomp通知结构struct seccomp_notif {__u64 id;__u32 pid;__u32 flags;struct seccomp_data data;};struct seccomp_notif_resp {__u64 id;__s64 val;__s32 error;__u32 flags;};// 通知文件操作static int seccomp_notify_open(struct inode *inode,struct file *file) {struct seccomp_filter *filter inode-i_private;file-private_data filter;return 0;}static ssize_t seccomp_notify_read(struct file *file,char __user *buf,size_t count,loff_t *ppos) {struct seccomp_filter *filter file-private_data;struct seccomp_notif unotif;struct seccomp_data *sd;int ret;// 等待过滤事件ret wait_event_interruptible(filter-notif-wq,!list_empty(filter-notif-ready));if (ret) return ret;// 读取通知数据sd seccomp_get_notif_data(filter);if (!sd) return -EINTR;unotif.id sd-id;unotif.pid task_pid_nr(sd-task);unotif.data *sd;if (copy_to_user(buf, unotif, sizeof(unotif)))return -EFAULT;return sizeof(unotif);}static ssize_t seccomp_notify_write(struct file *file,const char __user *buf,size_t count,loff_t *ppos) {struct seccomp_filter *filter file-private_data;struct seccomp_notif_resp resp;if (copy_from_user(resp, buf, sizeof(resp)))return -EFAULT;// 处理响应允许或拒绝系统调用seccomp_handle_notif_response(filter, resp);return count;}static const struct file_operations seccomp_notify_ops {.open seccomp_notify_open,.read seccomp_notify_read,.write seccomp_notify_write,};四、LSM(Linux安全模块)------------------c#include#include// LSM钩子结构struct security_hook_list {struct hlist_node list;struct hlist_head *head;union security_list_options hook;char *lsm;};// LSM钩子实现static int my_lsm_task_alloc(struct task_struct *task,unsigned long clone_flags) {// 初始化任务安全字段task-security kzalloc(sizeof(struct my_task_sec),GFP_KERNEL);if (!task-security) return -ENOMEM;return 0;}static void my_lsm_task_free(struct task_struct *task) {kfree(task-security);}static int my_lsm_file_permission(struct file *file,int mask) {// 检查文件访问权限struct inode *inode file_inode(file);struct my_file_sec *fsec inode-i_security;if (!fsec) return 0;// 检查自定义安全标签if (fsec-level current-security-level) {// 当前主体权限级别不足if (mask (MAY_READ | MAY_WRITE)) {return -EACCES;}}return 0;}static int my_lsm_bprm_set_creds(struct linux_binprm *bprm) {// 检查执行权限struct file *file bprm-file;struct my_file_sec *fsec;if (!file) return 0;fsec file_inode(file)-i_security;// 根据安全标签设置新进程的凭证if (fsec fsec-type MY_SEC_TYPE_TRUSTED) {// 提权bprm-cred-euid fsec-run_uid;}return 0;}// 注册LSM钩子static struct security_hook_list my_lsm_hooks[] {LSM_HOOK_INIT(task_alloc, my_lsm_task_alloc),LSM_HOOK_INIT(task_free, my_lsm_task_free),LSM_HOOK_INIT(file_permission, my_lsm_file_permission),LSM_HOOK_INIT(bprm_set_creds, my_lsm_bprm_set_creds),};void __init my_lsm_init(void) {security_add_hooks(my_lsm_hooks,ARRAY_SIZE(my_lsm_hooks),my_lsm);}五、SELinux操作-----------c#include#include// SELinux上下文struct selinux_state {bool disabled;bool initialized;bool enforcing;int policycap[POLICYDB_CAP_MAX 1];struct page *status_page;struct selinux_ss ss;};// SELinux上下文结构struct context {u32 user;u32 role;u32 type;u32 len;char *str;};// SELinux策略检查static int selinux_has_perm(struct context *subj,struct context *obj,u16 tclass, u32 perm) {struct av_decision avd;int ret;// 查询访问向量决策ret security_compute_av(subj-type,obj-type,tclass, perm, avd);if (ret) return ret;// 检查权限if (!(avd.allowed perm)) {// 审计拒绝audit_log(audit_context(),GFP_ATOMIC,AUDIT_AVC,denied %s for pid%d,perm_to_name(perm),task_pid_nr(current));return -EACCES;}// 检查是否需要向审计日志添加许可if (avd.auditallow perm) {audit_log(audit_context(),GFP_ATOMIC,AUDIT_AVC,granted %s, perm_to_name(perm));}return 0;}// 类型转换域转换static int selinux_bprm_set_creds(struct linux_binprm *bprm) {struct task_security_struct *tsec;struct inode_security_struct *isec;struct context oldc, newc;int ret;tsec current-security;isec d_backing_inode(bprm-file-f_path.dentry)-i_security;// 计算新域ret security_transition_sid(tsec-sid,isec-sid,SECCLASS_PROCESS,NULL, newc.sid);if (ret) return ret;// 设置新进程的安全IDbprm-cred-security-sid newc.sid;return 0;}六、AppArmor操作------------c#include#include// AppArmor策略struct aa_profile {struct aa_extable *file;struct aa_caps caps;struct aa_rlimit rlimits;const char *name;struct aa_profile *parent;};// 路径匹配static int aa_path_perm(const char *op,struct aa_profile *profile,struct path *path,int mask) {char *buffer;int error -EACCES;int len;// 获取绝对路径buffer kmalloc(PATH_MAX, GFP_KERNEL);if (!buffer) return -ENOMEM;len d_absolute_path(path, buffer, PATH_MAX);if (len 0) goto out;// 检查路径匹配if (profile-file) {error aa_dfa_match(profile-file-dfa,profile-file-start,buffer);}if (error) {// 记录拒绝aa_audit_msg(AUDIT_APPARMOR_DENIED,op, profile, buffer, error);}out:kfree(buffer);return error;}// 文件权限检查static int apparmor_file_permission(struct file *file,int mask) {struct aa_profile *profile;int error 0;profile aa_current_profile();if (!profile) return 0;// 检查文件权限error aa_path_perm(file_perm,profile,file-f_path,mask);return error;}七、用户态测试----------c#include#include#include#include#include#include#include#include#include#include#include// seccomp BPF辅助宏#define BPF_LD_ABS(syscall_nr) \BPF_STMT(BPF_LD | BPF_W | BPF_ABS, \offsetof(struct seccomp_data, nr))#define BPF_JEQ(syscall_nr, jt) \BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, \syscall_nr, jt, 0)// 允许系统调用的seccomp规则static struct sock_filter strict_filter[] {BPF_LD_ABS(0), // 加载系统调用号// 允许read, write, exit, sigreturnBPF_JEQ(__NR_read, 1),BPF_JEQ(__NR_write, 1),BPF_JEQ(__NR_exit, 1),BPF_JEQ(__NR_rt_sigreturn, 1),BPF_JEQ(__NR_exit_group, 1),// 拒绝其他所有系统调用BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL),// 允许BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),};// 应用seccomp过滤器static int apply_seccomp_filter(void) {struct sock_fprog prog {.len sizeof(strict_filter) / sizeof(strict_filter[0]),.filter strict_filter,};if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) 0) {perror(prctl NO_NEW_PRIVS);return -1;}if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, prog) 0) {perror(prctl SECCOMP);return -1;}printf(seccomp filter applied\n);return 0;}// 黑名单模式seccompstatic struct sock_filter blacklist_filter[] {BPF_LD_ABS(0),// 阻止特定的危险系统调用BPF_JEQ(__NR_execve, SECCOMP_RET_KILL),BPF_JEQ(__NR_fork, SECCOMP_RET_KILL),BPF_JEQ(__NR_vfork, SECCOMP_RET_KILL),BPF_JEQ(__NR_clone, SECCOMP_RET_KILL),BPF_JEQ(__NR_ptrace, SECCOMP_RET_KILL),// 检查socket参数BPF_STMT(BPF_LD | BPF_W | BPF_ABS,offsetof(struct seccomp_data, args[0])),BPF_JEQ(AF_INET, 0), // 允许AF_INETBPF_JEQ(AF_UNIX, 0), // 允许AF_UNIXBPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL), // 其他拒绝// 其他系统调用允许BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),};// seccomp通知测试需要上级进程static void seccomp_notify_test(void) {int notify_fd;notify_fd seccomp(SECCOMP_SET_MODE_FILTER,SECCOMP_FILTER_FLAG_NEW_LISTENER,prog);if (notify_fd 0) {perror(seccomp notify);return;}printf(seccomp notify fd: %d\n, notify_fd);// 处理通知struct seccomp_notif req;struct seccomp_notif_resp resp;while (1) {memset(req, 0, sizeof(req));if (ioctl(notify_fd, SECCOMP_IOCTL_NOTIF_RECV,req) 0)break;printf(Supervisor: syscall %d from pid %d\n,req.data.nr, req.pid);// 决定允许或拒绝memset(resp, 0, sizeof(resp));resp.id req.id;resp.error 0; // 允许resp.val 0;ioctl(notify_fd, SECCOMP_IOCTL_NOTIF_SEND, resp);}}// 测试seccomp限制static void test_seccomp_restrictions(void) {printf(\nTesting seccomp restrictions:\n);// 尝试创建socket应该在seccomp下被阻止int fd socket(AF_INET, SOCK_STREAM, 0);if (fd 0) {printf( socket() blocked: %s\n, strerror(errno));} else {printf( socket() allowed\n);close(fd);}// 尝试打开文件fd open(/tmp/test, O_RDONLY);if (fd 0) {printf( open() blocked: %s\n, strerror(errno));} else {printf( open() allowed\n);close(fd);}}// AppArmor状态查询static void show_apparmor_status(void) {FILE *fp fopen(/sys/kernel/security/apparmor/profiles,r);if (!fp) {printf(AppArmor not available\n);return;}printf(AppArmor profiles:\n);char line[512];while (fgets(line, sizeof(line), fp)) {printf( %s, line);}fclose(fp);}// SELinux状态查询static void show_selinux_status(void) {FILE *fp fopen(/sys/fs/selinux/enforce, r);if (!fp) {printf(SELinux not available\n);return;}char val[8];fgets(val, sizeof(val), fp);printf(SELinux enforcing: %s\n,val[0] 1 ? YES : NO);fclose(fp);fp fopen(/sys/fs/selinux/policyvers, r);if (fp) {fgets(val, sizeof(val), fp);printf(SELinux policy version: %s, val);fclose(fp);}}// 进程安全上下文static void show_process_context(void) {FILE *fp fopen(/proc/self/attr/current, r);if (fp) {char ctx[256];fgets(ctx, sizeof(ctx), fp);printf(Security context: %s, ctx);fclose(fp);}}int main(void) {printf(Seccomp Security Module Tests\n);printf(\n\n);printf(1. Security module status:\n);show_selinux_status();show_apparmor_status();printf(\n2. Process security context:\n);show_process_context();printf(\n3. Testing seccomp filter:\n);printf( Applying strict seccomp filter...\n);if (apply_seccomp_filter() 0) {printf( Filter applied, testing...\n);printf( This will likely kill the process\n);// 测试受限的系统调用test_seccomp_restrictions();// 如果还活着printf( Still alive!\n);}printf(\n4. seccomp notify test:\n);printf( (Requires supervisor process setup)\n);return 0;}