我正在开发一个基于xattr(文件的扩展属性)的linux安全模块,我想实施安全措施来防止加载没有某些xattr的共享库。这需要我hook file_open并检查文件的幻数以确定它是否是共享库,然后进行基于xattr的安全检查。
以下代码是我的实现(尚未完全完成)。挂钩的 file_open
xattracl_file_open(struct file *file)
调用 xattracl_magic_check_elf(struct file* file)
通过读取前 4 个字节来检查 file
是否为 ELF 格式。
但是我发现了两个问题。首先,我无法直接从这个结构
file
获取文件路径,它总是打印为(efault)
,因此我使用了自定义的xattracl_get_realpath(struct path *path)
(类似于tomoyo LSM模块的做法)。其次,每次读取4个字节时,它们似乎都有不同的值,我完全无法理解。
然后我尝试调用
flip_open()
因为我可以获取真实的路径名并获取“真实”结构文件来读取其 4 个字节,但这将不起作用,因为挂钩的 file_open() 将递归地调用自身并导致内核恐慌。
代码(为了便于阅读,省略了部分内容):
// ............
// Read magic number from a file's first 4B
// Param:
// struct file *file: the file to be checked
// Return:
// (int)-ENOMEM/-ENOENT/0/1 for memory allocation error/file reading error/being ELF/not ELF
int xattracl_file_magic_check_elf(struct file *file){
const char *realpath=xattracl_get_realpath(&file->f_path);
if(!realpath){
return -ENOMEM;
}
char *value=(char*)kmalloc(4,GFP_NOFS);
if(!value){
return -ENOMEM;
}
kernel_read(file,value,4,0)==-1);
int iself=(value[0]==0x7F)&&(value[1]==0x45)&&(value[2]==0x4C)&&(value[3]==0x46);
printk(KERN_INFO"[xattracl] (file_magic_check_elf) file:%s magic:%02X%02X%02X%02X iself:%d\n",realpath,value[0],value[1],value[2],value[3],iself);
filp_close(realfile,NULL);
kfree(realpath);
kfree(value);
return iself;
}
// Hooked file_open for ELF loading control
// Param:
// struct file *file: the file to be checked
// Return:
// (static int)-ENOMEM/-EPERM/0 for memory allocation error/denying loading/allowing loading
static int xattracl_file_open(struct file *file){
// If file is not ELF, allow loading.
int iself=xattracl_file_magic_check_elf(file);
if(!iself){
// Only return 0 for testing
// return -EPERM;
return 0;
}
// Get the file's xattr
struct dentry *dentry=file->f_path.dentry;
struct inode *inode=d_backing_inode(dentry);
char *value=(char*)kmalloc(XATTRACL_XATTR_VALUE_SIZE,GFP_NOFS);
if(!value){
return -ENOMEM;
}
int size=__vfs_getxattr(dentry,inode,XATTRACL_XATTR_NAME,value,XATTRACL_XATTR_VALUE_SIZE);
value[MAX(size,0)]=0;
// Users can only load shared libraries with XATTRACL_XATTR_NAME:XATTRACL_XATTR_ACTION_ALLOW
int action=strcmp(value,XATTRACL_XATTR_ACTION_ALLOW)?-EPERM:0;
printk(KERN_INFO"[xattracl] (file_open) file:%s type:%s "XATTRACL_XATTR_NAME":%s action:%s\n",dentry->d_name.name,iself?"OTHER":"ELF",value,action?"deny":"allow");
kfree(value);
// Only return 0 for testing
// return action;
return 0;
}
// ............
static struct security_hook_list xattracl_hooks[] __lsm_ro_after_init={
// ............
LSM_HOOK_INIT(file_open,xattracl_file_open),
// ............
};
// ............
dmesg 日志记录了这种奇怪的现象:
[pairman@fedora Downloads]$ dmesg | grep /usr/lib64/libc.so.6
[ 176.002714] [xattracl] (file_magic_check_elf) file:/usr/lib64/libc.so.6, magic:35205B31 elf:0
[ 176.006182] [xattracl] (file_magic_check_elf) file:/usr/lib64/libc.so.6, magic:CDDF5D32 elf:0
[ 177.045407] [xattracl] (file_magic_check_elf) file:/usr/lib64/libc.so.6, magic:4DA46A31 elf:0
[ 177.045412] [xattracl] (file_magic_check_elf) file:/usr/lib64/libc.so.6, magic:354E8438 elf:0
[ 177.050782] [xattracl] (file_magic_check_elf) file:/usr/lib64/libc.so.6, magic:CDDF5D32 elf:0
[ 177.053388] [xattracl] (file_magic_check_elf) file:/usr/lib64/libc.so.6, magic:5DDB5E31 elf:0
[ 179.175885] [xattracl] (file_magic_check_elf) file:/usr/lib64/libc.so.6, magic:4DA46A31 elf:0
[ 179.175907] [xattracl] (file_magic_check_elf) file:/usr/lib64/libc.so.6, magic:354E8438 elf:0
[pairman@fedora Downloads]$ xxd /usr/lib64/libc.so.6 | head -1
00000000: 7f45 4c46 0201 0103 0000 0000 0000 0000 .ELF............
我一直在寻找selinux和apparnor的类似场景和源代码,但没有找到任何有用的东西。
解释为什么我无法直接从
file
(即(efault)
)获取文件路径,以及为什么它的内容看起来随机、不正确并且每次都会变化,以及如何正确获取文件的幻数无需打电话file_open
。
是否有以正确的linux安全模块方式检查和审核共享库加载的其他方法?这样我就不用被这种痛苦淹没了。
感谢 Marco Bonelli,几个月后我现在记得我还没有正确回答。挂钩 mmap_file() 并通过 PERM_EXEC 参数检查文件是否是可执行文件解决了这个问题。