基于上下文的权限管理模型设计——利用LSM机制

设计思路

1.模仿SMACK的编码风格,所以首先要精读一遍SMACK的代码,找到有用的部分。(虽然之前也读过并模仿过,但是复杂度不是一个等级)。
2.确定数据结构和hook函数。
3.初步实现部分功能。
4.调试bug,完善功能

SMACK的用户空间工具:smackload

chsmack:
显示或设置 Smack 扩展属性值
smackctl:
加载 Smack 访问规则
smackaccess:
报告带有一个标签的进程是否可以访问带有另一个标签的对象

Smack 使用扩展属性 (xattrs) 在文件系统对象上存储标签。属性存储在扩展属性安全名称空间中。只有拥有CAP_MAC_ADMIN的进程才能改变这些属性中的任何一个。

Smack 使用的扩展属性是:

SMACK64
用于做出访问控制决策。在几乎所有情况下,赋予新文件系统对象的标签将是创建它的进程的标签。
SMACK64EXEC
执行具有此属性集的程序文件的进程的 Smack 标签将使用此属性的值运行。
SMACK64MMAP
不允许文件被一个进程映射,该进程的 Smack 标签不允许对该属性中包含的标签的进程进行所有允许的访问。这是共享库的一个非常具体的用例。
SMACK64TRANSMUTE
只能有值“TRUE”。如果在目录中创建对象时该属性存在于目录中,并且允许对该目录进行写访问的 Smack 规则(下文详述)包括转换(“t”)模式,则该对象将获得目录的标签创建过程的标签。如果创建的对象是一个目录,则还设置 SMACK64TRANSMUTE 属性。
SMACK64IPIN
此属性仅适用于套接字的文件描述符。使用此属性中的 Smack 标签对传递到此套接字的数据包进行访问控制决策。
SMACK64IPOUT
此属性仅适用于套接字的文件描述符。使用此属性中的 Smack 标签对来自此套接字的数据包进行访问控制决策。

工作1 阅读源码,弄清楚如何通过伪文件系统管理rules_list

SMACK的安全标签

为task打上标签: 我们知道Smack利用了LSM机制,LSM是要改造内核对象,为其添加安全域,对于任务而言,它的结构体task_struct里有一个成员是cred型,而cred结构体中有一项是void *security,这正是task的安全域,它指向了task_smack这个结构体,这个结构体里的成员就是父进程和子进程的安全标签,smack_lsm.c中的代码static struct task_smack *new_task_smack(char *task, char *forked, gfp_t gfp)是用来设置task_smack的父子进程smack标签,参数task指向父进程smack标签,forked指向子进程的smack标签,task_struct是以Linux内核链表形式组织起来,当设置完进程的安全标签后,该函数会初始化task_smack链表。

获取task的安全标签:在smack_lsm.c中,有一个很重要的宏–task_security(task),它的作用是获取进程的安全域,即void *security所指向的task_smack结构体,而在smack.h中有一个静态函数smk_of_current(),它用来获取当前进程的smack标签。

为inode打上标签:inode结构体中安全域是指向了inode_smack结构体,它不仅包含了文件对象的smack标签,而且包含了创建该inode的进程的smack标签,在smack_lsm.c中,钩子函数smack_inode_post_setxattr为inode打上标签,但是要注意只有以超级用户运行程序,才能在用户空间将文件打上Smack标签,因为像setxattr(设置安全标签)或者xattr这样的函数或命令都被安插了Smack的钩子smack_inode_setxattr,而此钩子会检查当前运行的程序有没有超级用户的权限。

获取inode标签:smk_fetch, smk_of_inode, smack_inode_getsecurity用来获取inode的smack标签。注意,Smack标签形式是键–值,键是XATTR_NAME_SMACK,XATTR_NAME_SMACKEXEC(进程标签),XATTR_NAME_SMACKIPIN(接收包的标签),XATTR_NAME_SMACKIPOUT(外发包的标签)它们在Linux的源码xattr.h中作为宏定义,而这里的值是Smack标签的值,即Smack的字符串,钩子函数一般是根据键(name)来获取值(value)。

伪文件系统部分源码解析

在SMACKfs.c中,完成了superblock的定义和操作实现,以最简单的“/smack/mapped"为例,修改“/smack/mapped"实际上就是对内存中的一个变量smack_cipso_mapped进行read和write,实现方式为

/**
 * smk_read_mapped - read() for /smack/mapped
 * @filp: file pointer, not actually used
 * @buf: where to put the result
 * @count: maximum to send along
 * @ppos: where to start
 *
 * Returns number of bytes read or error code, as appropriate
 */
static ssize_t smk_read_mapped(struct file *filp, char __user *buf,
			       size_t count, loff_t *ppos)
{
	char temp[80];
	ssize_t rc;

	if (*ppos != 0)
		return 0;

	sprintf(temp, "%d", smack_cipso_mapped);
	rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));

	return rc;
}

最后把这些操作放在file_operations结构体中:

static const struct file_operations smk_mapped_ops = {
	.read		= smk_read_mapped,
	.write		= smk_write_mapped,
	.llseek		= default_llseek,
};

smack通过调用simple_fill_super填充superblock:

static int smk_fill_super(struct super_block *sb, void *data, int silent)
{
	int rc;
	struct inode *root_inode;

	static const struct tree_descr smack_files[] = {
		[SMK_LOAD] = {
			"load", &smk_load_ops, S_IRUGO|S_IWUSR},
		[SMK_CIPSO] = {
			"cipso", &smk_cipso_ops, S_IRUGO|S_IWUSR},
		[SMK_DOI] = {
			"doi", &smk_doi_ops, S_IRUGO|S_IWUSR},
		[SMK_DIRECT] = {
			"direct", &smk_direct_ops, S_IRUGO|S_IWUSR},
		[SMK_AMBIENT] = {
			"ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR},
		[SMK_NET4ADDR] = {
			"netlabel", &smk_net4addr_ops, S_IRUGO|S_IWUSR},
		[SMK_ONLYCAP] = {
			"onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR},
		[SMK_LOGGING] = {
			"logging", &smk_logging_ops, S_IRUGO|S_IWUSR},
		[SMK_LOAD_SELF] = {
			"load-self", &smk_load_self_ops, S_IRUGO|S_IWUGO},
		[SMK_ACCESSES] = {
			"access", &smk_access_ops, S_IRUGO|S_IWUGO},
		[SMK_MAPPED] = {
			"mapped", &smk_mapped_ops, S_IRUGO|S_IWUSR},
		[SMK_LOAD2] = {
			"load2", &smk_load2_ops, S_IRUGO|S_IWUSR},
		[SMK_LOAD_SELF2] = {
			"load-self2", &smk_load_self2_ops, S_IRUGO|S_IWUGO},
		[SMK_ACCESS2] = {
			"access2", &smk_access2_ops, S_IRUGO|S_IWUGO},
		[SMK_CIPSO2] = {
			"cipso2", &smk_cipso2_ops, S_IRUGO|S_IWUSR},
		[SMK_REVOKE_SUBJ] = {
			"revoke-subject", &smk_revoke_subj_ops,
			S_IRUGO|S_IWUSR},
		[SMK_CHANGE_RULE] = {
			"change-rule", &smk_change_rule_ops, S_IRUGO|S_IWUSR},
		[SMK_SYSLOG] = {
			"syslog", &smk_syslog_ops, S_IRUGO|S_IWUSR},
		[SMK_PTRACE] = {
			"ptrace", &smk_ptrace_ops, S_IRUGO|S_IWUSR},
#ifdef CONFIG_SECURITY_SMACK_BRINGUP
		[SMK_UNCONFINED] = {
			"unconfined", &smk_unconfined_ops, S_IRUGO|S_IWUSR},
#endif
#if IS_ENABLED(CONFIG_IPV6)
		[SMK_NET6ADDR] = {
			"ipv6host", &smk_net6addr_ops, S_IRUGO|S_IWUSR},
#endif /* CONFIG_IPV6 */
		[SMK_RELABEL_SELF] = {
			"relabel-self", &smk_relabel_self_ops,
				S_IRUGO|S_IWUGO},
		/* last one */
			{""}
	};

	rc = simple_fill_super(sb, SMACK_MAGIC, smack_files);
	if (rc != 0) {
		printk(KERN_ERR "%s failed %d while creating inodes\n",
			__func__, rc);
		return rc;
	}

	root_inode = d_inode(sb->s_root);

	return 0;
}

smk_mount是对superblock进行的自定义mount操作。

/**
 * smk_mount - get the smackfs superblock
 * @fs_type: passed along without comment
 * @flags: passed along without comment
 * @dev_name: passed along without comment
 * @data: passed along without comment
 *
 * Just passes everything along.
 *
 * Returns what the lower level code does.
 */
static struct dentry *smk_mount(struct file_system_type *fs_type,
		      int flags, const char *dev_name, void *data)
{
	return mount_single(fs_type, flags, data, smk_fill_super);
}


然后定义superblock的file_system_type结构体,和挂载的位置。
file_system_type结构体代表Linux内核的各种文件系统,每一种文件系统必须要有自己的file_system_type结构,用于描述具体的文件系统的类型。

static struct file_system_type smk_fs_type = {
	.name		= "smackfs",
	.mount		= smk_mount,
	.kill_sb	= kill_litter_super,
};

每当一个文件系统被安装时,就会有一个vfsmount结构和mount被创建,mount代表该文件系统的一个安装实例。对于每一个mount的文件系统都有一个vfsmount结构来表示,smackfs安装时的vfsmount定义如下所示:

static struct vfsmount *smackfs_mount;

file_system_type,vfsmount,mount是伪文件系统实现中最重要的三个结构体。

Linux内核初始化时,执行init_smk_fs()函数登记smackfs,init_smk_fs()函数在各个伪文件系统的实现(如sockfs等)中大同小异,是非常八股文的写法,可以直接参考。

/**
 * init_smk_fs - get the smackfs superblock
 *
 * register the smackfs
 *
 * Do not register smackfs if Smack wasn't enabled
 * on boot. We can not put this method normally under the
 * smack_init() code path since the security subsystem get
 * initialized before the vfs caches.
 *
 * Returns true if we were not chosen on boot or if
 * we were chosen and filesystem registration succeeded.
 */
static int __init init_smk_fs(void)
{
	int err;
	int rc;

	if (smack_enabled == 0)
		return 0;

	err = smk_init_sysfs();
	if (err)
		printk(KERN_ERR "CBAC: sysfs mountpoint problem.\n");

	err = register_filesystem(&smk_fs_type);
	if (!err) {
		smackfs_mount = kern_mount(&smk_fs_type);
		if (IS_ERR(smackfs_mount)) {
			printk(KERN_ERR "smackfs:  could not mount!\n");
			err = PTR_ERR(smackfs_mount);
			smackfs_mount = NULL;
		}
	}

	smk_cipso_doi();
	smk_unlbl_ambient(NULL);

	return err;
}

__initcall(init_smk_fs);

用户空间——smackload分析

该部分对应毕业设计中的上下文管理器部分,因为我是将上下文信息存储在伪文件系统中,而非安全策略。但是策略管理器亦可参考编码风格。

参考

[1] SMACK核心机制浅析https://www.twblogs.net/a/5e4f4104bd9eee101e84dc78/?lang=zh-cn
[2] 浅析Linux内核sockfs网络文件系统 https://zhuanlan.zhihu.com/p/462049620
[3] smackload工具测试实例 https://www.its203.com/article/kkxgx/52088638?2022-04-04

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值