您所在的位置: 首页 > 读书频道 > 操作系统 > Linux >

3.5.7 函数avc_has_perm分析

http://book.51cto.com  2007-12-28 12:44  倪继利 著  电子工业出版社博文视点  我要评论(0)
  • 摘要:《Linux安全体系分析与编程》第三章分析了SELinux的安全机制,介绍了安全策略配置语言、内核策略库的结构,简述了SELinux内核模块的实现,还分析了用户空间的客体管理器。本文主要介绍的是函数avc_has_perm分析。
  • 标签:Linux  函数  avc  决策  Linux安全体系分析与编程

3.5.7  函数avc_has_perm分析

函数avc_has_perm从avc中查找决策信息,如果没找到,使用内核SELinux计算决策,并将决策信息相应条目插入到avc中,记录审核信息。决策的计算是通过读写/selinux/acess文件,调用内核SELinux接口函数完成的。

函数avc_has_perm列出如下(在libselinux/src/avc.c中):

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)
{
struct av_decision avd = { 0, 0, 0, 0, 0 };
int rc;
       //获得决策信息
rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, aeref, &avd);
       //如果决策否决了操作,则将安全上下文、决策信息等写入log文件或输出
avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata);
return rc;
}

函数avc_has_perm_noaudit从avc中查询决策信息,如果没找到相应条目,就通过内核SELinux计算决策信息,然后,将决策信息的条目插入到avc中,并返回决策信息到avd中。

函数avc_has_perm_noaudit列出如下(在libselinux/src/avc.c中):

int avc_has_perm_noaudit(security_id_t ssid,
 security_id_t tsid,
 security_class_t tclass,
 access_vector_t requested,
 struct avc_entry_ref *aeref, struct av_decision *avd)
{
struct avc_entry *ae;
int rc = 0;
struct avc_entry entry;
access_vector_t denied;
struct avc_entry_ref ref;

        //如果不使用线程,则每调用一次此函数,从内核SELinux中接收一次消息
if (!avc_using_threads) {
(void)avc_netlink_check_nb();
}

if (!aeref) {
avc_entry_ref_init(&ref);
aeref = &ref;
}

avc_get_lock(avc_lock);
avc_cache_stats_incr(entry_lookups);
ae = aeref->ae;
if (ae) {  //查看ae是否被使用
if (ae->ssid == ssid &&
    ae->tsid == tsid &&
    ae->tclass == tclass &&
    ((ae->avd.decided & requested) == requested)) {
avc_cache_stats_incr(entry_hits);
ae->used = 1;
} else {
avc_cache_stats_incr(entry_discards);
ae = 0;
}
}

if (!ae) {
avc_cache_stats_incr(entry_misses);
rc = avc_lookup(ssid, tsid, tclass, requested, aeref);
if (rc) {//从avc中没找到对应的条目
if ((ssid->refcnt <= 0) || (tsid->refcnt <= 0)) {
errno = EINVAL;
rc = -1;
goto out;
}
rc = security_compute_av(ssid->ctx, tsid->ctx, tclass,
 requested, &entry.avd);
if (rc)
goto out;
                        //将条目插入到avc中
rc = avc_insert(ssid, tsid, tclass, &entry, aeref);
if (rc)
goto out;
}
ae = aeref->ae;
}

if (avd)
memcpy(avd, &ae->avd, sizeof(*avd));

denied = requested & ~(ae->avd.allowed);

if ((!requested || denied) && avc_enforcing) {
errno = EACCES;
rc = -1;
}

      out:
avc_release_lock(avc_lock);
return rc;
}

函数security_compute_av通过socket与setrans后台进程通信,将安全上下文转移到原始安全上下文格式,然后,通过内核SELinux计算决策,将决策信息返回到avd中。

函数security_compute_av列出如下(在libselinux/src/compute_av.c中):

int security_compute_av(security_context_t scon,
security_context_t tcon,
security_class_t tclass,
access_vector_t requested, struct av_decision *avd)
{
int ret;
security_context_t rscon = scon;
security_context_t rtcon = tcon;
      //将安全上下文通过setrans后台进程转换到原始安全上下文
if (selinux_trans_to_raw_context(scon, &rscon))
return -1;
if (selinux_trans_to_raw_context(tcon, &rtcon)) {
freecon(rscon);
return -1;
}
      //通过内核SELinux计算决策
ret = security_compute_av_raw(rscon, rtcon, tclass, requested, avd);

freecon(rscon);
freecon(rtcon);

return ret;
}

函数security_compute_av_raw通过写文件/selinux/acess,调用内核SELinux的函数根据安全上下文对计算决策,然后,再通过读这个文件,读取决策信息。

函数security_compute_av_raw列出如下(在libselinux/src/compute_av.c中):

int security_compute_av_raw(security_context_t scon,
    security_context_t tcon,
    security_class_t tclass,
    access_vector_t requested, struct av_decision *avd)
{
char path[PATH_MAX];
char *buf;
size_t len;
int fd, ret;

if (!selinux_mnt) {
errno = ENOENT;
return -1;
}

snprintf(path, sizeof path, "%s/access", selinux_mnt); //得到文件路径/selinux/acess
fd = open(path, O_RDWR);    //打开文件
if (fd < 0)
return -1;

len = selinux_page_size;   //系统的页大小
buf = malloc(len);
if (!buf) {
ret = -1;
goto out;
}
      //将数据格式化写入buf
snprintf(buf, len, "%s %s %hu %x", scon, tcon, tclass, requested);

ret = write(fd, buf, strlen(buf)); //将buf写入文件
if (ret < 0)
goto out2;

memset(buf, 0, len);
ret = read(fd, buf, len - 1);  //读出文件到buf
if (ret < 0)
goto out2;

           //将文件中读出的数据进行格式转换
if (sscanf(buf, "%x %x %x %x %u", &avd->allowed,
   &avd->decided, &avd->auditallow, &avd->auditdeny,
   &avd->seqno) != 5) {
ret = -1;
goto out2;
}

ret = 0;
      out2:
free(buf);
      out:
close(fd);
return ret;
}

【责任编辑:董书 TEL:(010)68476606】

回书目   上一节   下一节
Linux——从菜鸟到高手
Linux/Solaris服务器的安全配置
Linux 集群技术专题
Linux中文环境
Linux防火墙
 
 验证码: (点击刷新验证码)   匿名发表
  • 网络工程师考试案例动手实验营

  • 作者:郭春柱
  • 本书依据2009年版《网络工程师考试大纲》的考核要求,深入研究了历年网络工程师考试试题的命题风格和试题结构,对考查的知识点..
Copyright©2005-2008 51CTO.COM 版权所有