将 LKM 移植到 LSM - 意外行为

Porting LKM to LSM - Unexpected behavior

我有一个 Linux 内核模块,它检查是否存在特定 USB 设备并在匹配时执行 printk。这段代码工作正常并按照我的预期执行。

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include <linux/list.h>
#include <linux/slab.h>

MODULE_LICENSE("GPL");

static int HARD_VEND;
static int HARD_PROD;
static char *HARD_SERI;

struct USBCred
{
    int vendor;
    int product;
    char serial[128];
};

static struct USBCred create_creds_device(struct usb_device *dev)
{
    struct USBCred creds;

    creds.vendor = dev->descriptor.idVendor;
    creds.product = dev->descriptor.idProduct;

    if((dev->serial) == NULL)
    {
        strcpy(creds.serial, "(null)");
    } else {
        strcpy(creds.serial, dev->serial);
    }

    return creds;
}

static struct USBCred create_creds_hub(struct usb_bus *bus)
{
    struct USBCred creds;

    creds.vendor = bus->root_hub->descriptor.idVendor;
    creds.product = bus->root_hub->descriptor.idProduct;

    if((bus->root_hub->serial) == NULL)
    {
        strcpy(creds.serial, "(null)");
    } else {
        strcpy(creds.serial, bus->root_hub->serial);
    }

    return creds;
}


static int check_usb_creds(struct USBCred usb_data) 
{
    if(usb_data.vendor != HARD_VEND && usb_data.product != HARD_PROD && strcmp(usb_data.serial, HARD_SERI))
    {
        return 1;
    } else 
    {
        printk(KERN_INFO "*********** RootPug Module - Match ***********");
        printk(KERN_INFO "Vendor ID = %x, HC Vendor ID  = %x", usb_data.vendor, HARD_VEND);
        printk(KERN_INFO "Product ID = %x, HC Product ID = %x", usb_data.product, HARD_PROD);
        printk(KERN_INFO "Serial = %s, HC Serial= %s", usb_data.serial, HARD_SERI);
        return 0; 
    }
}

static int __init usb_fun_init (void)  
{  
    int id;
    int chix;

    struct USBCred cred;

    struct usb_bus *bus; 
    struct usb_device *dev, *childdev = NULL;

    HARD_VEND = 0x26bd;
        HARD_PROD = 0x9917;
        HARD_SERI = "070172966462EB10";

    mutex_lock(&usb_bus_idr_lock);

    idr_for_each_entry(&usb_bus_idr, bus, id)
        {        
        cred = create_creds_hub(bus);
        //print_USBCred(cred);
        check_usb_creds(cred);

        dev = bus->root_hub;
        usb_hub_for_each_child(dev, chix, childdev)
        {
            if(childdev)
            {           
                usb_lock_device(childdev);
                cred = create_creds_device(childdev);
                //print_USBCred(cred);
                check_usb_creds(cred);
                usb_unlock_device(childdev);
                        }
        }
    }

    mutex_unlock(&usb_bus_idr_lock);    
    return 0;  
}

static void __exit usb_fun_exit (void)  
{  
    printk(KERN_INFO "***************** RootPug Module - Exit *****************\n");  
} 

module_init(usb_fun_init);
module_exit(usb_fun_exit); 

当转移到 LSM 时,LSM 注册没有问题,钩子注册正确,但代码的行为并不像我想要的那样,我不明白为什么。我已经添加了调试语句以了解代码到达的位置,但似乎 idr_for_each_entry() 没有被执行,因为没有打印该循环中的调试语句。我使用了一个基于标志的系统来提供一种机制,使 -EPERM 作为默认 return 值,如果找到 usb 则被覆盖。

我不明白为什么只执行互斥锁,而不检查集线器或 USB 设备,但相同的代码可以用作 LKM。有问题的实际代码在 appcl_inode_create 挂钩中。为了简洁起见,我省略了其他挂钩,但它们目前除了 return 期望值 0 之外什么都不做。

#include <linux/init.h>
#include <linux/kd.h>
#include <linux/kernel.h>
#include <linux/tracehook.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/lsm_hooks.h>
#include <linux/xattr.h>
#include <linux/security.h>
#include <linux/capability.h>
#include <linux/unistd.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/slab.h>
#include <linux/pagemap.h>
#include <linux/proc_fs.h>
#include <linux/magic.h>
#include <linux/ctype.h>
#include <linux/swap.h>
#include <linux/spinlock.h>
#include <linux/syscalls.h>
#include <linux/dcache.h>
#include <linux/file.h>
#include <linux/fdtable.h>
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/tty.h>
#include <linux/types.h>
#include <linux/atomic.h>
#include <linux/bitops.h>
#include <linux/interrupt.h>
#include <linux/parser.h>
#include <linux/nfs_mount.h>
#include <linux/string.h>
#include <linux/mutex.h>
#include <linux/posix-timers.h>
#include <linux/syslog.h>
#include <linux/user_namespace.h>
#include <linux/export.h>
#include <linux/msg.h>
#include <linux/shm.h>
#include <linux/gfp.h>

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/list.h>
#include <linux/cred.h>
#include <linux/fs.h>
#include <linux/fs_struct.h>
#include <linux/fsnotify.h>
#include <linux/path.h>
#include <linux/fdtable.h>
#include <linux/binfmts.h>
#include <linux/time.h>

#include <linux/usb.h>
#include <linux/usb/hcd.h>

#include "include/appcl_lsm.h"
//#include "include/audit.h"

MODULE_LICENSE("GPLv3");
MODULE_AUTHOR("Jack Cuthbertson");


static int HARD_VEND;
static int HARD_PROD;
static char *HARD_SERI;

struct USBCred
{
    int vendor;
    int product;
    char serial[128];
};

static struct USBCred create_creds_device(struct usb_device *dev)
{
    struct USBCred creds;

    creds.vendor = dev->descriptor.idVendor;
    creds.product = dev->descriptor.idProduct;

    if((dev->serial) == NULL)
    {
        strcpy(creds.serial, "(null)");
    } else {
        strcpy(creds.serial, dev->serial);
    }

    return creds;
}

static struct USBCred create_creds_hub(struct usb_bus *bus)
{
    struct USBCred creds;

    creds.vendor = bus->root_hub->descriptor.idVendor;
    creds.product = bus->root_hub->descriptor.idProduct;

    if((bus->root_hub->serial) == NULL)
    {
        strcpy(creds.serial, "(null)");
    } else {
        strcpy(creds.serial, bus->root_hub->serial);
    }

    return creds;
}


static int check_usb_creds(struct USBCred usb_data) 
{
    if(usb_data.vendor != HARD_VEND && usb_data.product != HARD_PROD && strcmp(usb_data.serial, HARD_SERI))
    {
            printk(KERN_INFO "*********** RootPlug Module - Non Match ***********");
            printk(KERN_INFO "Vendor ID = %x, HC Vendor ID  = %x", usb_data.vendor, HARD_VEND);
        printk(KERN_INFO "Product ID = %x, HC Product ID = %x", usb_data.product, HARD_PROD);
        printk(KERN_INFO "Serial = %s, HC Serial= %s", usb_data.serial, HARD_SERI);
        return 1;
    } else 
    {
        printk(KERN_INFO "*********** RootPlug Module - Match ***********");
        printk(KERN_INFO "Vendor ID = %x, HC Vendor ID  = %x", usb_data.vendor, HARD_VEND);
        printk(KERN_INFO "Product ID = %x, HC Product ID = %x", usb_data.product, HARD_PROD);
        printk(KERN_INFO "Serial = %s, HC Serial= %s", usb_data.serial, HARD_SERI);
        return 0; 
    }
}

static int appcl_lsm_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode)
{
int id;
int chix;

int flag = -EPERM;

struct USBCred cred;

struct usb_bus *bus; 
struct usb_device *dev, *childdev = NULL;

    HARD_VEND = 0x26bd;
    HARD_PROD = 0x9917;
    HARD_SERI = "070172966462EB10";

    printk(KERN_ALERT "Rootplug: Beginning check\n");

    mutex_lock(&usb_bus_idr_lock);
    printk(KERN_ALERT "Rootplug: Mutex locked the bus list\n");

    //loop though all usb buses
    idr_for_each_entry(&usb_bus_idr, bus, id)
    {        
        printk(KERN_ALERT "Rootplug: Checking hubs.\n");        
        cred = create_creds_hub(bus);

        //Check creds of usb buses
        if(check_usb_creds(cred) == 0)
        {
            mutex_unlock(&usb_bus_idr_lock);
            printk(KERN_ALERT "Rootplug: Unlock hub success!\n");
            flag = 0;
        } else {
            printk(KERN_ALERT "Rootplug: Unlock hub fail!\n");
        }


        dev = bus->root_hub;
        usb_hub_for_each_child(dev, chix, childdev)
        {
            if(childdev)
            {   
                printk(KERN_ALERT "Rootplug: Checking USB devices\n");      
                usb_lock_device(childdev);
                cred = create_creds_device(childdev);

                if(check_usb_creds(cred) == 0)
                {
                    usb_unlock_device(childdev);
                    mutex_unlock(&usb_bus_idr_lock);
                    printk(KERN_ALERT "Rootplug: Unlock USB success!\n");       
                } else {
                    usb_unlock_device(childdev);
            printk(KERN_ALERT "Rootplug: Unlock USB Failure!\n");       
                }

            } else {

                printk(KERN_ALERT "Rootplug: No child dev\n");
            }
        }
    }

    mutex_unlock(&usb_bus_idr_lock);
    printk(KERN_ALERT "Rootplug: Unlock failed - Flag: %i\n", flag);
    return flag;
}

static struct security_hook_list appcl_hooks[] = {
    /*
     * XATTR HOOKS
     */
    LSM_HOOK_INIT(inode_setxattr, appcl_lsm_inode_setxattr),
    LSM_HOOK_INIT(inode_post_setxattr, appcl_lsm_inode_post_setxattr),
    LSM_HOOK_INIT(inode_getxattr, appcl_lsm_inode_getxattr),
    LSM_HOOK_INIT(inode_removexattr, appcl_lsm_inode_removexattr),
    LSM_HOOK_INIT(d_instantiate, appcl_lsm_d_instantiate),
    LSM_HOOK_INIT(inode_setsecurity, appcl_lsm_inode_setsecurity),
    LSM_HOOK_INIT(inode_init_security, appcl_lsm_inode_init_security),
    /*
     * INODE HOOKS
     */
    LSM_HOOK_INIT(inode_alloc_security, appcl_lsm_inode_alloc_security),
    LSM_HOOK_INIT(inode_free_security, appcl_lsm_inode_free_security),
    /*
     * General permission mask
     */
    LSM_HOOK_INIT(inode_permission, appcl_lsm_inode_permission),
    /*
     * Specific permission hooks
     */
    LSM_HOOK_INIT(inode_create, appcl_lsm_inode_create),
    LSM_HOOK_INIT(inode_rename, appcl_lsm_inode_rename),
    LSM_HOOK_INIT(inode_link, appcl_lsm_inode_link),
    LSM_HOOK_INIT(inode_unlink, appcl_lsm_inode_unlink),
    LSM_HOOK_INIT(inode_symlink, appcl_lsm_inode_symlink),
    LSM_HOOK_INIT(inode_mkdir, appcl_lsm_inode_mkdir),
    LSM_HOOK_INIT(inode_rmdir, appcl_lsm_inode_rmdir),
    LSM_HOOK_INIT(inode_mknod, appcl_lsm_inode_mknod),
    LSM_HOOK_INIT(inode_readlink, appcl_lsm_inode_readlink),
    LSM_HOOK_INIT(inode_follow_link, appcl_lsm_inode_follow_link),
    //LSM_HOOK_INIT(inode_setattr, appcl_lsm_inode_setattr),
    //LSM_HOOK_INIT(inode_getattr, appcl_lsm_inode_getattr),
    /*
     * FILE HOOKS
     */
    LSM_HOOK_INIT(file_alloc_security, appcl_lsm_file_alloc_security),
    LSM_HOOK_INIT(file_free_security, appcl_lsm_file_free_security),
    LSM_HOOK_INIT(file_permission, appcl_lsm_file_permission),
    //LSM_HOOK_INIT(file_fcntl, appcl_lsm_file_fcntl),
    LSM_HOOK_INIT(file_open, appcl_lsm_file_open),
    LSM_HOOK_INIT(file_receive, appcl_lsm_file_receive),
    /*
     * CRED HOOKS
     */
    LSM_HOOK_INIT(cred_alloc_blank, appcl_lsm_cred_alloc_blank),
    LSM_HOOK_INIT(cred_free, appcl_lsm_cred_free),
    LSM_HOOK_INIT(cred_prepare, appcl_lsm_cred_prepare),
    LSM_HOOK_INIT(cred_transfer, appcl_lsm_cred_transfer),
    LSM_HOOK_INIT(bprm_set_creds, appcl_lsm_bprm_set_creds),
    /*
     * SUPERBLOCK HOOKS
     */
    LSM_HOOK_INIT(sb_alloc_security, appcl_lsm_sb_alloc_security),
    LSM_HOOK_INIT(sb_free_security, appcl_lsm_sb_free_security),
};

static __init int appcl_init(void)
{
    printk(KERN_ALERT "Rootplug: Module loading... \n");

    /*
     * Set security attributes for initial task
     */

    security_add_hooks(appcl_hooks, ARRAY_SIZE(appcl_hooks), "appcl");

    printk(KERN_ALERT "Rootplug: module initialised\n");

    return 0;
}

DEFINE_LSM(appcl) = {
        .name = "appcl",
        .init = appcl_init,
};

处理匹配的函数对 printk 函数使用了不同的警报级别。因此,在引导过程的那个阶段,消息不会显示到控制台。

过去是什么:

printk(KERN_INFO "message");

应该是:

printk(KERN_ALERT "message");

正在调用匹配函数,在重新编译内核后,钩子强制为return 0,我可以从/var/log/*看到函数正在执行并输出正确的信息。