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

Linux内核安全模块深入剖析【3.0】

14.2.2 规则列表内核为 audit 规则设置了六个列表User、Task、Entry、Watch、Exit 和 Type依次对应audit_filter_list 数组的第 0第 5 个元素。代码如下。kernel/auditfilter.c struct list_head audit_filter_list[AUDIT_NR_FILTERS] { LIST_HEAD_INIT(audit_filter_list[0]), LIST_HEAD_INIT(audit_filter_list[1]), LIST_HEAD_INIT(audit_filter_list[2]), LIST_HEAD_INIT(audit_filter_list[3]), LIST_HEAD_INIT(audit_filter_list[4]), LIST_HEAD_INIT(audit_filter_list[5]), #if AUDIT_NR_FILTERS ! 6 #error Fix audit_filter_list initialiser #endif }; static struct list_head audit_rules_list[AUDIT_NR_FILTERS] { LIST_HEAD_INIT(audit_rules_list[0]), LIST_HEAD_INIT(audit_rules_list[1]), LIST_HEAD_INIT(audit_rules_list[2]), LIST_HEAD_INIT(audit_rules_list[3]), LIST_HEAD_INIT(audit_rules_list[4]), LIST_HEAD_INIT(audit_rules_list[5]), }audit_filter_list 用于规则匹配audit_rules_list 只用于规则显示。当用户态进程通过 netlink套接字传送“AUDIT_LIST_RULES”消息给内核时内核就会把所有的审计规则发还给用户态进程。Watch 列表已经没有用处保留它多半是为了和旧版本的用户态程序兼容。用户态程序大多数情况下是 auditctl会向内核请求访问某个规则列表。比如请求向编号为 4Exit的列表中加入规则。Watch 列表的编号是 3删除它会导致其后的列表编号变动。这或许是保留它的原因。下面逐一解释规则列表。1. User此处的 User 指用户态审计消息。内核缺省是将所有接收到的用户态类型的审计消息发送给auditd。通过这个规则队列管理员可以配置规则让内核忽略某些用户态类型 audit 消息。相关代码如下下面看一下 audit_filter_user 的实现 kernel/auditfilter.c int audit_filter_user(int type) { … ret 1; /* Audit by default */ … list_for_each_entry_rcu(e, audit_filter_list[AUDIT_FILTER_USER], list) { rc audit_filter_user_rules(e-rule, type, state); if (rc) { if (rc 0 state AUDIT_DISABLED) ret 0; break; } } … return ret; }2. Type前面的 User 规则列表针对的是用户态消息类型下面要介绍的 Type 规则列表针对的是内核产生的消息类型。如果管理员不想看到某种类型的内核 audit 消息则可以生成一条规则让内核不发送这种类型的 audit 消息到 auditd。前面讲过其他内核子系统如果要产生一条内核审计消息日志性质的消息需要先调用audit_log_start 函数。下面看一下 audit_log_startkernel/audit.c struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, int type) { … if (unlikely(audit_filter_type(type))) return NULL; … }如果在 Type 规则队列中有条规则规定某个消息类型“不受欢迎”则使用此消息类型获取的 audit_buffer 是空的也就产生不了相应的 audit 消息。3. Taskaudit 子系统对进程创建有特殊照顾为它专门创建了一个规则列表。所以对于 clone 和fork 系统调用除了要经过下面提到的 Entry 和 Exit 两个规则列表外还会检查 Task 规则列表中的规则。4. EntryEntry 对应于系统调用的入口。在刚刚进入系统调用时能检查的只是系统调用号和系统调用的前四个参数。kernel/auditsc.c void __audit_syscall_entry(int arch, int major, unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4) { … context-arch arch; context-major major; context-argv[0] a1; context-argv[1] a2; context-argv[2] a3; context-argv[3] a4; … if (!context-dummy state AUDIT_BUILD_CONTEXT) { context-prio 0; state audit_filter_syscall(tsk, context, audit_filter_list[AUDIT_ FILTER_ENTRY]); } … }5. ExitExit 列表是最重要的。Exit 规则的检查点是在系统调用结束时此时是数据最丰富的时候。调用它的地方在 audit_get_context 中audit_get_context 这个函数名很难让人想到规则匹配。kernel/auditsc.c static inline struct audit_context *audit_get_context(struct task_struct *tsk, int return_valid, long return_code) { … if (context-in_syscall !context-dummy) { audit_filter_syscall(tsk, context, audit_filter_list[AUDIT_FILTER_ EXIT]); audit_filter_inodes(tsk, context); } tsk-audit_context NULL; return context; }14.2.3 对文件的审计Linux audit 子系统对文件的审计有三套方案。第一套使用文件的 inode 号第二套使用文件的路径名第三套使用目录的路径名。1. 使用 inode 号审计文件来看一下规则匹配的代码kernel/auditsc.c static int audit_filter_rules(struct task_struct *tsk, struct audit_krule *rule, struct audit_context *ctx, struct audit_names *name, enum audit_state *state, bool task_creation) { … for (i 0; i rule-field_count; i) { struct audit_field *f rule-fields[i]; struct audit_names *n; int result 0; switch (f-type) { case AUDIT_INODE: if (name) result audit_comparator(name-ino, f-op, f-val); else if (ctx) { list_for_each_entry(n, ctx-names_list, list) { if (audit_comparator(n-ino, f-op, f-val)) { result; break; } } } break; … } } }在 audit context 中逐一匹配规则中存储的 inode 号。2. 使用文件的路径名审计文件使用文件的路径名来审计文件依赖关键数据结构 audit_watch。在 audit_filter_rules 函数中有下面这段语句case AUDIT_WATCH: if (name)result audit_watch_compare(rule-watch, name-ino, name-dev); break;audit_watch_compare 的函数实现是kernel/audit_watch.c int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev) { return (watch-ino ! (unsigned long)-1) (watch-ino ino) (watch-dev dev); }看起来和前面的基于 inode 号的方案没有什么区别也是比较 inode 号。奥妙在于 watch 中的 ino 的值可以是“-1”表示这个 watch 还未生效。watch 的生效依赖于另一个数据类型—— audit_parent:kernel/audit_watch.c struct audit_watch { atomic_t count; /* reference count */ dev_t dev; /* associated superblock device */ char *path; /* insertion path */ unsigned long ino; /* associated inode number */ struct audit_parent *parent; /* associated parent */ struct list_head wlist; /* entry in parent-watches list */ struct list_head rules; /* anchor for krule-rlist */ }; struct audit_parent { struct list_head watches; /* anchor for audit_watch-wlist */ struct fsnotify_mark mark; /* fsnotify mark on the inode */ }audit_parent 只有两个成员一个是 fsnotify mark另一个是 list串起相关的 watch。audit_parent 对应一个目录audit_watch 对应一个文件。当用户为一个文件创建一个 audit watch时这个 audit watch 就被串入 audit parent 的 watches 链表中。audit watch 的神奇之处在于用户可以为还不存在的文件创建 watch。做到这一点需要 audit_parent 中的类型为 fsnotify_mark 的成员 mark。kernel/audit_watch.c static int audit_watch_handle_event(struct fsnotify_group *group, struct inode *to_tell, struct fsnotify_mark *inode_mark, struct fsnotify_mark *vfsmount_mark, u32 mask, void *data, int data_type, const unsigned char *dname) { struct inode *inode; struct audit_parent *parent; parent container_of(inode_mark, struct audit_parent, mark); BUG_ON(group ! audit_watch_group); switch (data_type) { case (FSNOTIFY_EVENT_PATH): inode ((struct path *)data)-dentry-d_inode; break; case (FSNOTIFY_EVENT_INODE): inode (struct inode *)data; break; default: BUG(); inode NULL; break; }; if (mask (FS_CREATE|FS_MOVED_TO) inode) audit_update_watch(parent, dname, inode-i_sb-s_dev, inode-i_ino, 0); else if (mask (FS_DELETE|FS_MOVED_FROM)) audit_update_watch(parent, dname, (dev_t)-1, (unsigned long)-1, 1); else if (mask (FS_DELETE_SELF|FS_UNMOUNT|FS_MOVE_SELF)) audit_remove_parent_watches(parent); return 0; } static const struct fsnotify_ops audit_watch_fsnotify_ops { .handle_event audit_watch_handle_event, }fsnotify 是 Linux 内核中的一个机制audit 依靠它在文件发生变化时得到通知。当目录下有文件创建或删除时audit_watch_handle_event 就会被调用。当文件创建时audit_watch 中的 ino 会被更新为实际的文件 ino 号当文件被删除时audit_watch 中的 ino 会被赋值为表示无效的“-1”。3. 使用目录的路径名来审计文件使用目录的路径名审计文件依赖关键数据结构 audit_tree。如果用 audit_watch 审计一个目录下的所有文件那么就需要建立许多条审计规则。即使如此仍然无法对还不存在并且不知道名字的文件实行审计。audit_watch 只能对知道名字但还不存在的文件建立审计规则。这种情况就需要 audit_tree 了。audit 子系统设计了两个结构体audit_tree 和 audit_chunk。在逻辑上是一个 tree 包含若干chunk。tree 代表目录树那 chunk 呢chunk 这个英文单词的意思是“一大块”这个单词多半是 trunk意思为树干的误用。可能 audit_tree.c 的作者是个母语非英语的程序员。目录树的概念比较容易理解。“树干”是什么呢“树干”就是文件系统的挂载点。在建立一条包含目录的审计规则时内核 audit 子系统会构建一个 audit_tree 实例同时循目录遍历一遇到挂载点就构建 audit_chunk 实例并将其关联到 audit_tree 中。在涉及文件的系统调用中内核 audit 系统的钩子函数会查询文件所在文件系统的挂载点将其记录到进程的 audit_context中。在系统调用结束时对 audit_context 进行检查。
http://www.zskr.cn/news/1370959.html

相关文章:

  • Linux内核安全模块深入剖析【2.9】
  • 从零开始将 OpenClaw Agent 工具接入 Taotoken 的详细步骤
  • next.js 开发中的水合(Hydration)问题
  • 手把手教你搞定TaiShan鲲鹏服务器CentOS 7.9安装(附BIOS关键设置与iBMC远程安装)
  • 如何永久免费使用Cursor Pro:终极指南与完整解决方案
  • 【紧急预警】Gemini CSR项目启动窗口期仅剩47天!错过Q3政策红利将影响全年ESG评级得分
  • Zotero中文文献管理难题的终极解决方案:茉莉花插件深度解析
  • GitHub中文插件:5分钟实现GitHub界面全面中文化的终极指南
  • 火狐浏览器配置Burp Suite抓包完全指南
  • 机器学习赋能水泥熟料矿物相实时预测:从数据清洗到模型部署的工业实践
  • TrafficMonitor插件生态完整指南:10分钟打造个性化桌面监控中心
  • 10分钟精通Translumo:Windows最强开源实时屏幕翻译工具完整指南
  • Sketch MeaXure终极指南:如何用现代化TypeScript插件高效完成设计标注
  • Warcraft Helper终极指南:8大功能让魔兽争霸3在现代系统重获新生
  • 辽宁省本溪寄快递省钱干货|不用跑网点!四款公众号 + 小程序寄件渠道,发全国性价比拉满 - 时讯资讯
  • VSCode中R语言开发环境配置与使用完整教程
  • DeepSeek敏感词识别失效真相:3类隐蔽绕过手法+实时过滤响应<80ms的工业级配置清单
  • GPT-SoVITS:用1分钟语音数据训练高质量TTS模型的实用指南
  • TV浏览器终极指南:智能电视上网的5大优势与完整解决方案
  • 如何用本地图像搜索工具实现千万级图片秒级检索:隐私优先的终极解决方案
  • 仅剩最后47套!《ChatGPT脑筋急转弯生成军规手册》PDF+127个经A/B测试验证的高互动Prompt模板(含儿童/职场/银发三版适配)
  • 初次使用Taotoken Token Plan套餐的成本控制体验
  • FFmpegGUI:5分钟掌握免费视频转换的终极图形化工具
  • 通过curl命令直接测试Taotoken大模型API连通性的方法
  • 【限时深度报告】ChatGPT翻译质量白皮书(2024Q2):覆盖17个垂直领域+8种语言对+5轮人工校验,仅开放48小时免费领取!
  • C# Windows自启动原理与生产级实现指南
  • 如何高效使用智能游戏助手:League Akari完全自动化指南
  • 大数据机器学习框架性能对比:从Spark MLlib到Scikit-learn的基准测试实践
  • 长期项目使用Taotoken感受到的API服务稳定性与可靠性
  • 为什么你需要一个智能激活管理工具来简化Windows和Office激活?