seteuid0's blog
Themed by Diary.
SELinux中核外应用查询策略API总结

SELinux中支持应用使用libselinux库来针对SELinux进行安全扩展(selinux aware application),这样应用就可以使用SELinux的策略库来实现内部的访问控制,当前的passwd、dbus、udev等都使用selinux进行了扩展。其中passwd使用selinux进行密码修改检查,dbus对收、发进行了权限检查,分成了:acquire_svc和send_msg。 SELinux提供给用户空间的用户计算策略是否允许的接口主要有2类:selinux_check_access和avc_has_perm,下面对这两类接口进行说明。 selinux_check_access的函数原型为:

int selinux_check_access(const security_context_t scon, const security_context_t tcon, const char *class, const char *perm, void *audit‐ data);

需要输入的为主体、客体、客体类、权限集的字符串表示。 avc_has_perm的函数原型为:

int avc_has_perm(security_id_t ssid, security_id_t tsid, security_class_t tclass, access_vector_t requested, struct avc_entry_ref *aeref, void *auditdata);

需要输入的为主体、客体、客体类、权限集对应的id号,因此需要在使用以前将安全上下文与id号进行映射。在/usr/include/selinux/flask.h和/usr/include/selinux/av_permissions.h对客体类和权限集进行了定义,但是如果使用头文件中的编号,就导致应用与默认的refpolicy的编号顺序必须保持一致,否则容易导致编号与实际内容产生冲突。SELinux的开发者创建了selinux_set_mapping函数来动态建立客体类和权限集的映射关系。

int selinux_set_mapping(struct  security_class_mapping *map); struct security_class_mapping { const char *name; const char *perms[]; };

例如:

static struct security_class_mapping dbus_map[] = { { “dbus”, { “acquire_svc”, “send_msg”, NULL } }, { NULL } }; #define DBUS__ACQUIRE_SVC 1 #define DBUS__SEND_MSG 2

通过定义类似如上的内容将客体类和权限集在核外进行动态的映射,这样就可以放心的使用类似“DBUS__ACQUIRE_SVC“的宏定义了。 细心的读者可能还会发现avc_has_perm是对avc信息进行处理,所在调用avc_has_perm之前还需要初始化avc相关信息。需要调用avc_open和avc_entry_ref_init等进行初始化。 当使用selinux_check_access的时候就不需要对avc进行初始化操作,因为在selinux_check_access里面进行了调用,实现如下:

int selinux_check_access(const security_context_t scon, const security_context_t tcon, const char *class, const char *perm, void *aux) { int rc; security_id_t scon_id; security_id_t tcon_id; security_class_t sclass; access_vector_t av; if (is_selinux_enabled() == 0) return 0; __selinux_once(once, avc_init_once); rc = avc_context_to_sid(scon, &scon_id); if (rc < 0) return rc; rc = avc_context_to_sid(tcon, &tcon_id); if (rc < 0) return rc; sclass = string_to_security_class(class); if (sclass == 0) { rc = errno; if (security_deny_unknown() == 0) return 0; errno = rc; return -1; } av = string_to_av_perm(sclass, perm); if (av == 0) { rc = errno; if (security_deny_unknown() == 0) return 0; errno = rc; return -1; } return avc_has_perm (scon_id, tcon_id, sclass, av, NULL, aux); }

其中__selinux_once中对avc_init_once进行调用,avc_init_once对avc_open进行调用,即完成了对avc的初始化。里面调用avc_init丢netlink进行初始化,使核外可以获知selinux状态信息,audit等信息。 除此以外,API中还有security_compute_av函数,该函数的原型为:

int security_compute_av(security_context_t scon, security_context_t tcon, security_class_t tclass, access_vector_t requested, struct av_decision *avd);

该函数对策略信息是否允许进行查询,但并不对avc进行处理,avc_has_perm里面就是调用了security_compute_av获取策略信息。   示例代码: avc_has_perm_example