不多说了,都是理由,还是不够自律。2023.10.24

漏洞编号 相关漏洞 漏洞描述 漏洞影响 CVSS3.1基础得分 受影响的版本 受影响的仓库 修复链接 参考链接
OpenHarmony-SA-2023-0203 CVE-2023-22436 内核子系统中check_permission_for_set_tokenid函数中存在UAF漏洞。 本地攻击者利用该漏洞攻击可以权限提升,获得root权限。 7.8 OpenHarmony-v3.1-Release 到 OpenHarmony-v3.1.5-Release kernel_linux_5.10 3.1.x 研究员上报

patch

  +5 -6 drivers/accesstokenid/access_tokenid.c 
  @@ -8,7 +8,6 @@

  #define pr_fmt(fmt) "access_token_id: " fmt

- #include <linux/cred.h>
  #include <linux/errno.h>
  #include <linux/fs.h>
  #include <linux/miscdevice.h>
  @@ -24,7 +23,7 @@ int access_tokenid_get_tokenid(struct file *file, void __user *uarg)

  static bool check_permission_for_set_tokenid(struct file *file)
  {
-   const struct cred *cred = get_task_cred(current);
+   kuid_t uid = current_uid();
    struct inode *inode = file->f_inode;

    if (inode == NULL) {
  @@ -32,8 +31,8 @@ static bool check_permission_for_set_tokenid(struct file *file)
      return false;
    }

-   if (uid_eq(cred->uid, GLOBAL_ROOT_UID) ||
-       uid_eq(cred->uid, inode->i_uid)) {
+   if (uid_eq(uid, GLOBAL_ROOT_UID) ||
+       uid_eq(uid, inode->i_uid)) {
      return true;
    }

  @@ -58,7 +57,7 @@ static bool check_permission_for_ftokenid(struct file *file)
  {
    int i;
    struct group_info *group_info;
-   const struct cred *cred = get_task_cred(current);
+   kuid_t uid = current_uid();
    struct inode *inode = file->f_inode;

    if (inode == NULL) {
  @@ -66,7 +65,7 @@ static bool check_permission_for_ftokenid(struct file *file)
      return false;
    }

-   if (uid_eq(cred->uid, GLOBAL_ROOT_UID))
+   if (uid_eq(uid, GLOBAL_ROOT_UID))
      return true;

    group_info = get_current_groups();

分析

accesstokenid 驱动提供读写tokenid/ftokenid的能力,两者类似,这里仅分析前者。

[1]处通过get_task_cred()获取当前进程的cred对象,此时cred对象的reference count会加1。但是函数check_permission_for_set_tokenid在后续的过程中,使用完cred对象后并没有将reference count减1(即调用put_cred)。

那么,如果攻击者一直调用函数check_permission_for_set_tokenid(),那么cred对象的reference count会一直递增1,最后溢出为0,触发释放导致UAF。

static bool check_permission_for_set_tokenid(struct file *file)
{
	const struct cred *cred = get_task_cred(current); // [1]
	struct inode *inode = file->f_inode;

	if (inode == NULL) {
		pr_err("%s: file inode is null\n", __func__);
		return false;
	}

  if (uid_eq(cred->uid, GLOBAL_ROOT_UID) ||
      uid_eq(cred->uid, inode->i_uid)) {
		return true;
	}

	return false;
}

所有进程都有各自的cred对象(task结构体中),用来描述进程的uid等身份信息,且所有cred对象都存储于名为cred_jar的slab池中。如下所示,一开始attack process 的cred指针指向cred_jar中的第二个cred。

-------------															-------------
    cred      --------                   cred(uid==x)
-------------					|										-------------
attack process        -----------------> cred(uid==xxx)
            					   									-------------
                                         cred(uid==y)
					              									-------------
                                         cred(uid==z)
												            			-------------
															              cred_jar

接着触发漏洞,让cred对象的reference count溢出为0,触发释放,然而引用并没有销毁,指针仍然指向它。

reference count溢出为0时不会自动释放cred对象,可以通过open & close一个文件来进行释放。open会+1,close会-1并释放。

-------------															-------------
    cred      --------                   cred(uid==x)
-------------					|										-------------
attack process        -----------------> 
            					   									-------------
                                         cred(uid==y)
					              									-------------
                                         cred(uid==z)
												            			-------------
															              cred_jar

最后借助某一个privileged process 进行堆喷,覆盖刚才释放的cred对象,UAF,本地提权到root。

-------------															-------------
    cred      --------                   cred(uid==x)
-------------					|										-------------
attack process        -----------------> cred(uid==0)
            					|										-------------
                                         cred(uid==y)    
-------------					|										-------------
    cred      --------                   cred(uid==z)
-------------															-------------
privileged process															

参考文献

  • https://gitee.com/openharmony/security/blob/master/zh/security-disclosure/2023/2023-02.md
  • https://gitee.com/openharmony/kernel_linux_5.10/commit/4048f12d993e0a89e9dda401224f12a99b701052