接前一篇文章:LSM零知识学习五、插桩原理实现细节(3)
本文内容参考:
LSM(Linux Security Modules)框架原理解析_lsm linux_pwl999的博客-CSDN博客
特此致谢!
上回书留了一个扣子:file_open函数指针指向了谁?又是什么时候被赋值的?
要弄清楚这个问题,先来看一下LSM_HOOK_INIT。LSM_HOOK_INIT是一个宏,在include/linux/lsm_hooks.h中定义,代码如下:
/*
* Initializing a security_hook_list structure takes
* up a lot of space in a source file. This macro takes
* care of the common case and reduces the amount of
* text involved.
*/
#define LSM_HOOK_INIT(HEAD, HOOK) \
{ .head = &security_hook_heads.HEAD, .hook = { .HEAD = HOOK } }
各个安全模块中都有调用LSM_HOOK_INIT宏(也可以说是函数)。
security/selinux/hooks.c中:
LSM_HOOK_INIT(file_open, selinux_file_open),
展开后为:
{ .head = &security_hook_heads.file_open, .hook = { .file_open = selinux_file_open } },
security/apparmor/lsm.c中:
LSM_HOOK_INIT(file_open, apparmor_file_open),
展开后为:
{ .head = &security_hook_heads.file_open, .hook = { .file_open = apparmor_file_open } },
security/smack/smack_lsm.c中:
LSM_HOOK_INIT(file_open, smack_file_open),
展开后为:
{ .head = &security_hook_heads.file_open, .hook = { .file_open = smack_file_open } },
security/tomoyo/tomoyo.c中:
LSM_HOOK_INIT(file_open, tomoyo_file_open),
展开后为:
{ .head = &security_hook_heads.file_open, .hook = { .file_open = toyomo_file_open } },
Landlock
security/landlock/fs.c中:
LSM_HOOK_INIT(file_open, hook_file_open),
展开后为:
{ .head = &security_hook_heads.file_open, .hook = { .file_open = hook_file_open } },
security_hook_heads以及其类型struct security_hook_heads前文已介绍过,这里不再赘述。
下面以SELinux和AppArmor为例,分别看一下selinux_file_open和apparmor_file_open的实现。
selinux_file_open在security/selinux/hooks.c中,代码如下:
static int selinux_file_open(struct file *file)
{
struct file_security_struct *fsec;
struct inode_security_struct *isec;
fsec = selinux_file(file);
isec = inode_security(file_inode(file));
/*
* Save inode label and policy sequence number
* at open-time so that selinux_file_permission
* can determine whether revalidation is necessary.
* Task label is already saved in the file security
* struct as its SID.
*/
fsec->isid = isec->sid;
fsec->pseqno = avc_policy_seqno(&selinux_state);
/*
* Since the inode label or policy seqno may have changed
* between the selinux_inode_permission check and the saving
* of state above, recheck that access is still permitted.
* Otherwise, access might never be revalidated against the
* new inode label or new policy.
* This check is not redundant - do not remove.
*/
return file_path_has_perm(file->f_cred, file, open_file_to_av(file));
}
apparmor_file_open在security/apparmor/lsm.c中,代码如下:
static int apparmor_file_open(struct file *file)
{
struct aa_file_ctx *fctx = file_ctx(file);
struct aa_label *label;
int error = 0;
if (!path_mediated_fs(file->f_path.dentry))
return 0;
/* If in exec, permission is handled by bprm hooks.
* Cache permissions granted by the previous exec check, with
* implicit read and executable mmap which are required to
* actually execute the image.
*/
if (current->in_execve) {
fctx->allow = MAY_EXEC | MAY_READ | AA_EXEC_MMAP;
return 0;
}
label = aa_get_newest_cred_label(file->f_cred);
if (!unconfined(label)) {
struct user_namespace *mnt_userns = file_mnt_user_ns(file);
struct inode *inode = file_inode(file);
struct path_cond cond = {
i_uid_into_mnt(mnt_userns, inode),
inode->i_mode
};
error = aa_path_perm(OP_OPEN, label, &file->f_path, 0,
aa_map_file_to_perms(file), &cond);
/* todo cache full allowed permissions set and state */
fctx->allow = aa_map_file_to_perms(file);
}
aa_put_label(label);
return error;
}