当前位置: 首页 > news >正文

Linux seccomp与安全模块

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_RDONLY
if (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_INET
if (domain != AF_UNIX && domain != AF_INET) {
return SECCOMP_RET_ERRNO | EAFNOSUPPORT;
}

// 只允许SOCK_STREAM
if (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;

// 设置新进程的安全ID
bprm->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, sigreturn
BPF_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;
}

// 黑名单模式seccomp
static 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_INET
BPF_JEQ(AF_UNIX, 0), // 允许AF_UNIX
BPF_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;
}
```

http://www.jsqmd.com/news/902080/

相关文章:

  • 喜鹊抽奖系统:打造沉浸式活动现场抽奖体验的跨平台解决方案
  • 别再纠结了!家用服务器选PVE还是unRaid?从NAS玩家视角聊聊我的踩坑心得
  • GetQzonehistory完整指南:3步轻松备份你的QQ空间历史记忆
  • 2026 生产制造业抖音推广 工程客户决策逻辑和获客要点解析
  • 3步从图片中提取数据:WebPlotDigitizer免费开源工具完整指南
  • 2026最新丹东市黄金回收白银回收铂金回收店铺实力口碑排行榜TOP5;K金+金条+银条+首饰回收靠谱门店及联系方式推荐 - 前途无量YY
  • 三步解锁音乐自由:开源NCM转换工具让你掌控自己的音乐收藏
  • 13.给Hermes一个不会丢的浏览器身份
  • 5款VeLoCity皮肤:让VLC播放器焕然一新的终极美化指南
  • 空洞骑士模组管理为何如此困难?Lumafly为你带来跨平台智能解决方案
  • 从分子到宇宙:用PyTorch Geometric实战几何等变GNN,搞定3D分子构象预测
  • Kali Linux磁盘扩容避坑指南:搞定fstab和resume配置,开机唤醒不再‘转圈圈’
  • 别再等硬盘挂了!用smartctl给你的Linux服务器硬盘做个全面体检(附CentOS 7安装配置)
  • 如何快速实现QQ音乐格式转换:Mac用户的终极音频解码指南
  • Maxwell仿真动画制作保姆级教程:从保存场数据到导出磁力线动图(含Toyota Prius 2D模型实例)
  • 基于Claude Code的5个自动化工作流:重塑开发者日常效率
  • M3D-Stereo数据集:构建真实可控的立体图像退化基准
  • VLC播放器终极美化指南:5款专业级VeLoCity皮肤全面解析
  • 互联网大厂 Java 求职面试:从音视频服务到微服务架构的全面挑战
  • 百度网盘提取码一键获取终极指南:3步告别资源获取烦恼
  • Windows 11下用EasyUEFI给Ubuntu做引导,避开Secure Boot的坑
  • 基于SIP URI的AI语音机器人:零成本部署与实战优化指南
  • 多LLM协同架构在AI法律调解系统中的应用与实践
  • 告别无限循环!UE4粒子特效生命周期与内存管理避坑指南(含特效池WorldPSCPool)
  • 别再乱调grub了!手把手教你用tuned-adm优雅隔离Linux CPU核心(以CentOS 7为例)
  • UE5 GAS插件避坑指南:从ActionRPG项目精简到实战,手把手配置你的第一个技能
  • 如何用arXiv MCP Server打造你的AI研究助手:5分钟快速上手指南
  • 终极硬件调优指南:Universal x86 Tuning Utility完整解析
  • 番茄小说下载器:3步打造个人离线小说图书馆的完整指南
  • 从一个月到一周:他用文心重构金融科技高管课