6.系统system文件可以有多个套接字也可以有多个但系统类别的客体实例是全局性的只有一个。system 类型之上的操作有获取 ipc 信息ipc_info、 syslog 相关操作syslog_console、 syslog_ mod、 syslog_read和内核模块相关操作module_request。虽然叫系统却只涉及寥寥几个操作许可让人感到有些奇怪。1进程间通信● ipc_info 读取系统 ipc 信息具体来说当系统调用 msgctl 的 cmd 参数为 IPC_INFO 或 MSG_INFO 时或当系统调用semctl 的 cmd 参数为 IPC_INFO 或 SEM_INFO 时或当系统调用 shmctl 的 cmd 参数为 IPC_INFO或 SHM_INFO 时 SELinux 会判断此操作许可。2 syslog以下几个操作都和系统调用 syslog 相关。● syslog_read读取 kernel 日志消息。● syslog_mod清空 kernel 消息缓冲区。● syslog_console控制 kernel 日志打印到控制台。3 module● module_request加载内核模块。7.安全securitySELinux 的设计者希望设计出一个完备的系统对于自身的管理也要纳入到 SELinux 的管理体系中。所以 SELinux 引入了新的客体类别——安全。在安全类别上的操作都和 SELinux 自身管理有关。这里有一个问题 SELinux 是如何管理自身的呢因为 Linux 内核对增加系统调用非常慎重所以 SELinux 没有引入新的系统调用而是构建了一个文件系统——selinuxfs。在 Linux上增加文件系统是很容易的。用户态进程通过读写 selinuxfs 上的文件来实现对 SELinux 的管理。相应地 SELinux 规定了以下操作● check_context查看安全上下文是否合法。● compute_av根据源安全上下文、目的安全上下文、客体类型计算访问许可。● compute_create输入源安全上下文、目的安全上下文、客体类型根据 type_transition策略计算新安全上下文。● compute_member输入源安全上下文、目的安全上下文、客体类型根据 type_member策略计算新安全上下文。● compute_relabel输入源安全上下文、目的安全上下文、客体类型根据 type_change策略计算新安全上下文。● compute_user输入安全上下文和用户名计算新的安全上下文。● load_policy加载安全策略。● setbool改变 SELinux 布尔变量值。● setcheckreqprot修改 SELinux 变量 checkreqprot 值。在执行 mmap 和 mprotect 系统调用时若值为 0执行来自内核的检验方法若值为 1执行来自应用的检验模式。内核的检查方法是将 read 和 exec 联系起来。● setenforce改变 SELinux 的 enforcement 状态permissive 或 enforcing。● setsecparam改变 AVC 参数。8.能力能力是进程的特权。从逻辑上讲能力是进程的一种资源。如果能力可以是一种客体那么进程的内存大小、进程的描述符数量、文件占用的磁盘块数量、用户同时拥有的进程数量都可以是客体。如果把能力作为一种客体那么对能力的操作应该是添加、删除、查看。但是这样设计没有任何意义。因为在 execve 系统调用中不会区分添加和删除在 capset 系统调用中只允许删除能力而删除能力本身不应被限制查看进程的能力也没有什么安全问题没有限制的必要。SELinux 要套用它的标准逻辑“主体操作客体”。所以 SELinux 将能力定义为一种客体类别将能力上的操作定义为具体的能力如 cap_chown。这种设计带来了三个问题1具体的能力怎么能成为能力的操作呢这不合逻辑。2进程是主体能力是客体能力本身就是进程的一个属性主体和客体的安全上下文总是一样的。3 SELinux 为能力设计了两个客体类别 capability 和 capability2。 capability 对应前 32 个能力 capability2 对应后 32 个能力。SELinux 内部用一个比特表示一个操作 用一个 32 位整数表示在某个客体类别上的全部操作类型。如进程上的操作一共有 30 个目录上的操作一共有 25 个都没有超过 32。但是在能力上原有代码的数据结构无法表示为了解决这个问题 SELinux 就多引入了一个能力相关的客体类别 capability2。能力只有一个 capability 和 capability2 在语义上没有区别这种设计实在算不上优雅。9.用户态客体Linux 系统中还有一些客体存在于用户态。如数据库在内核眼里只有文件没有表 table、记录record之类。所以对数据库的控制自然就应该由用户态服务进程来实施。但是相关的策略仍然被内核掌控整个系统只有一个策略库这个策略库存储在内核内存之中由内核的安全服务器负责管理。那些用户态服务进程所做的工作就是查询策略库确定对用户态客体的操作是否允许。SELinux 的用户态客体包括数据库类型db_database、 db_table、 db_procedure、 db_column、db_tuple……、 X-Window 相关类型x_drawable、 x_screen、 x_gc、 x_font、 x_colormap……、dbus 等。10.其他SELinux 中还有一些很少用到的客体这里就不列举了。7.2.3 安全上下文的生成和变化7.2.1 节介绍了安全上下文 7.2.2 节介绍了客体类别和客体上的操作。有了安全上下文有了操作再加上 7.3 节要介绍的 SELinux 策略系统管理员就可以规定安全上下文为 A 的进程可以对安全上下文为 B 的文件进行 C 操作。这样就完成了 SELinux 的强制访问控制。但是主体和客体的安全上下文的值是怎么设置的主体和客体的安全上下文能不能改变如果能可以改变成什么值1.安全上下文的初始值进程的安全上下文的初始值有两个来源1创建进程时子进程的安全上下文是父进程的安全上下文的副本。security/selinux/hooks.c static int selinux_cred_prepare(struct cred *new, const struct cred *old, gfp_t gfp) { const struct task_security_struct *old_tsec; struct task_security_struct *tsec; old_tsec old-security; tsec kmemdup(old_tsec, sizeof(struct task_security_struct), gfp); if (!tsec) return -ENOMEM; new-security tsec; return 0; }2 Linux 系统中第一个进程的安全上下文是 SECINITSID_KERNEL 所对应的安全上下文。security/selinux/hooks.c static void cred_init_security(void) { struct cred *cred (struct cred *) current-real_cred; struct task_security_struct *tsec; tsec kzalloc(sizeof(struct task_security_struct), GFP_KERNEL); if (!tsec) panic(SELinux: Failed to initialize initial task.\n); tsec-osid tsec-sid SECINITSID_KERNEL; cred-security tsec; }SELinux 代码将所有的安全上下文存储在一个数组中为了提高效率 SELinux 代码用数组项的序号来代表安全上下文。这个序号被称作 sid。上面代码中的 SECINITSID_KERNEL 就是一个 sid。cred_init_security 函数被 SELinux 的初始化函数调用它所设置的进程正是系统的第一个进程security/selinux/hooks.c static __init int selinux_init(void) { if (!security_module_enable(selinux_ops)) { selinux_enabled 0; return 0; } if (!selinux_enabled) { printk(KERN_INFO SELinux: Disabled at boot.\n); return 0; } printk(KERN_INFO SELinux: Initializing.\n); /* Set the security state for the initial task. */ cred_init_security(); default_noexec !(VM_DATA_DEFAULT_FLAGS VM_EXEC); sel_inode_cache kmem_cache_create(selinux_inode_security, sizeof(struct inode_security_struct), 0, SLAB_PANIC, NULL); avc_init(); if (register_security(selinux_ops)) panic(SELinux: Unable to register with kernel.\n); if (selinux_enforcing) printk(KERN_DEBUG SELinux: Starting in enforcing mode\n); else printk(KERN_DEBUG SELinux: Starting in permissive mode\n); return 0; }2.安全上下文的改变不是所有的主体和客体都需要改变安全上下文进程间通信类客体就没有必要改变安全上下文。下面列出改变进程和文件的安全上下文的逻辑。1进程SELinux 提供了两种方式改变进程的安全上下文。第一种方式是进程调用 execve 系统调用第二种方式是通过写/proc/self/attr/current 文件。这两种方式在前面已经列举。2文件文件的安全上下文记录在文件的扩展属性 security.selinux 中修改扩展属性 security.selinux的值就是修改文件的安全上下文。security/selinux/hooks.c static int selinux_inode_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { struct inode *inode dentry-d_inode; struct inode_security_struct *isec inode-i_security; struct superblock_security_struct *sbsec; struct common_audit_data ad; u32 newsid, sid current_sid(); int rc 0; if (strcmp(name, XATTR_NAME_SELINUX)) return selinux_inode_setotherxattr(dentry, name); sbsec inode-i_sb-s_security; if (!(sbsec-flags SBLABEL_MNT)) return -EOPNOTSUPP; if (!inode_owner_or_capable(inode)) return -EPERM; ad.type LSM_AUDIT_DATA_DENTRY; ad.u.dentry dentry; rc avc_has_perm(sid, isec-sid, isec-sclass, FILE__RELABELFROM, ad); if (rc) return rc; rc security_context_to_sid(value, size, newsid); … if (rc) return rc; rc avc_has_perm(sid, newsid, isec-sclass, FILE__RELABELTO, ad); if (rc) return rc; rc security_validate_transition(isec-sid, newsid, sid, isec-sclass); if (rc) return rc; return avc_has_perm(newsid, sbsec-sid, SECCLASS_FILESYSTEM, FILESYSTEM__ASSOCIATE, ad); }上述代码判断的操作许可较多主要的有三个 1文件的安全上下文不再是现在的值RELABELFROM。2文件的安全上下文可以是新的值RELABELTO。3文件所在的文件系统允许文件新的安全上下文ASSOCIATE。7.3 安全策略UNIX/Linux 的设计传统是机制和策略分离。 SELinux 遵循了这一传统。 7.2 节介绍的SELinux 机制是1主体是进程客体细分为若干类别。2在每个客体类别上定义若干操作。3每一个主体和客体的实例都关联安全上下文。4主体操作客体时 SELinux 会根据策略判断操作是否允许。本节集中讲述一下 SELinux 的策略。下面看一个策略的例子策略语句 策略含义allow init sshd_exec_t:file { getattr open read execute }; 允许执行allow init sshd:process transition; 允许域转换allow sshd sshd_exec_t:file { entrypoint read execute }; 允许作为入口点allow sshd init:process sigchild; 允许发 sigchildallow init sshd:process { siginh rlimitinh }; 允许发 siginhtype_transition init sshd_exec_t:process sshd; 让域转换成为缺省操作简单来说上述语句就是让 init 进程可以执行 sshd 文件并且新的 sshd 进程的安全上下文是sshd。策略是用策略语言编写的。用户态策略语言文件一般有多个其格式是适合用户阅读的文本格式。要让策略起作用管理员需要用 SELinux 用户态工具将策略文件编译成一个二进制文件 然后通过 selinuxfs 接口 将这个二进制文件所表示的策略输入到内核存储空间的策略库中即图 7-3 中的 Security Server安全服务器。最终使用策略的是 SELinux 的钩子函数hooks为了提高效率 SELinux 的设计者在安全服务器和钩子函数之间放置了一个缓存——Access Vector Cache。内核代码在系统调用函数中嵌入了对内核安全模块钩子函数的调用 SELinux 的钩子函数会根据策略返回结果。这个返回值会影响系统调用成功与否。图 7-3 简单描述了SELinux 的架构。强调一下 SELinux 的策略是允许策略访问控制是白名单机制没有在策略中定义的操作都是被禁止的即“法无允许即禁止”。