在套接字连接时从kext验证客户端

时间:2016-02-01 13:18:49

标签: sockets security authentication kernel-extension xnu

我在OS X上构建一个额外的安全层(围绕KAtuh构建)的kext。我在用户空间中使用客户端连接到套接字上的kext(如Apple所建议的那样),并且基本上控制了kext。因为该产品应该为OS X提供额外的安全性,所以它尽可能安全并且#34;反对攻击。一个攻击向量如下:A malicious process impersonates the client and sends malicious control data to the kext, disabling the security mechanism.。我想通过在连接时进行身份验证来防止这种情况。以下是我的解决方案:

  • 以root身份运行客户端,使用CTL_FLAG_PRIVILEGED标志以确保只有root客户端可以连接到kext。我不确定我是否希望让我的客户端以特权模式运行(再次:额外的攻击向量)。

  • 让kext只连接到一个客户端。但是,这很容易被忽略。

理想情况下,我想验证通过static int ctl_connect(kern_ctl_ref ctl_ref, struct sockaddr_ctl *sac, void **unitinfo)连接的客户端的身份。我怎么能这样做?

我也可以在static int ctl_set(kern_ctl_ref ctl_ref, u_int32_t unit, void *unitinfo, int opt, void *data, size_t len)中进行数据包身份验证,但是,我必须提出动态共享密钥。我在考虑secret = SHA256(getUDID()),但是AFAIK没有可用的加密KPI,也没有从内核空间到getUDID()的方法。

还有其他想法吗?#34;正确的"客户认证?

2 个答案:

答案 0 :(得分:1)

我向Apple的开发者技术支持部门提出了这个问题,并且他们已经说过,限制用户客户端访问kexts的唯一受支持的方法是区分根和非根进程。

就个人而言,为了减少攻击面,删除用户客户端权限确实很有用。检查特定组成员身份的Linux方式似乎也适用于OS X. (例如,您通常需要成为'kvm'组的一部分才能在Linux上使用KVM虚拟化技术。)成为组成员的唯一方法是通过root权限(设置Launch Daemon的GroupName需要root权限) )所以这应该是安全的。我自己还没有尝试过这个,但我有2个项目,这是有意义的,所以我会试一试,并将根据我的发现更新这个答案。

答案 1 :(得分:1)

Apple在AMFI kext(<sys/codesign.h>标头)中具有implemented功能,可用于从已签名的二进制文件中获取TeamID。如果此标头是公共的,那么这正是用于验证连接到kext的客户端进程的原因。

/*
 * Function: csfg_get_teamid
 *
 * Description: This returns a pointer to
 *      the teamid for the fileglob fg
 */
const char *
csfg_get_teamid(struct fileglob *fg)
{
    struct ubc_info *uip;
    const char *str = NULL;
    vnode_t vp;

    if (FILEGLOB_DTYPE(fg) != DTYPE_VNODE)
        return NULL;

    vp = (struct vnode *)fg->fg_data;
    if (vp == NULL)
        return NULL;

    vnode_lock(vp);
    if (!UBCINFOEXISTS(vp))
        goto out;

    uip = vp->v_ubcinfo;
    if (uip == NULL)
        goto out;

    if (uip->cs_blobs == NULL)
        goto out;

    /* It is OK to extract the teamid from the first blob
       because all blobs of a vnode must have the same teamid */    
    str = uip->cs_blobs->csb_teamid;
out:
    vnode_unlock(vp);

    return str;
}