接前一篇文章:LSM零知识学习五、插桩原理实现细节(3)

本文内容参考:

LSM(Linux Security Modules)框架原理解析_lsm linux_pwl999的博客-CSDN博客

特此致谢!

三、LSM回调的注册

上回书留了一个扣子: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宏(也可以说是函数)。

  • SELinux

security/selinux/hooks.c中:

LSM_HOOK_INIT(file_open, selinux_file_open),

 展开后为:

{ .head = &security_hook_heads.file_open, .hook = { .file_open = selinux_file_open } },
  • AppArmor

security/apparmor/lsm.c中:

LSM_HOOK_INIT(file_open, apparmor_file_open),

展开后为:

{ .head = &security_hook_heads.file_open, .hook = { .file_open = apparmor_file_open } },
  • Smack

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 } },
  • TOYOMO

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;
}
06-16 17:42