mirror of
				https://github.com/linuxkit/linuxkit.git
				synced 2025-10-31 08:02:52 +00:00 
			
		
		
		
	This is a project with a v1 of the IMA namespacing patches. See the readme for details on use. Signed-off-by: Tycho Andersen <tycho@docker.com>
		
			
				
	
	
		
			263 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			263 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From 3966bcc59bbb0d43b4b2bf8b005788cad75cf65d Mon Sep 17 00:00:00 2001
 | |
| From: Guilherme Magalhaes <guilherme.magalhaes@hpe.com>
 | |
| Date: Tue, 9 May 2017 13:41:24 -0300
 | |
| Subject: [PATCH 04/11] ima: add support to namespace securityfs file
 | |
| 
 | |
| Creating the namespace securityfs file under ima folder. When a mount
 | |
| namespace id is written to the namespace file, a new folder is created and
 | |
| with a policy file for that specified namespace. Then, user defined policy
 | |
| for namespaces may be set by writing rules to this namespace policy file.
 | |
| With this interface, there is no need to give visibility for the securityfs
 | |
| inside mount namespaces or containers in userspace.
 | |
| 
 | |
| Signed-off-by: Guilherme Magalhaes <guilherme.magalhaes@hpe.com>
 | |
| ---
 | |
|  security/integrity/ima/ima.h    |   4 +
 | |
|  security/integrity/ima/ima_fs.c | 183 ++++++++++++++++++++++++++++++++++++++++
 | |
|  2 files changed, 187 insertions(+)
 | |
| 
 | |
| diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
 | |
| index 42fb91ba..6e8ca8e 100644
 | |
| --- a/security/integrity/ima/ima.h
 | |
| +++ b/security/integrity/ima/ima.h
 | |
| @@ -326,4 +326,8 @@ static inline int security_filter_rule_match(u32 secid, u32 field, u32 op,
 | |
|  #define	POLICY_FILE_FLAGS	S_IWUSR
 | |
|  #endif /* CONFIG_IMA_WRITE_POLICY */
 | |
|  
 | |
| +#ifdef CONFIG_IMA_PER_NAMESPACE
 | |
| +#define NAMESPACES_FILE_FLAGS  S_IWUSR
 | |
| +#endif
 | |
| +
 | |
|  #endif /* __LINUX_IMA_H */
 | |
| diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
 | |
| index ca303e5..6456407 100644
 | |
| --- a/security/integrity/ima/ima_fs.c
 | |
| +++ b/security/integrity/ima/ima_fs.c
 | |
| @@ -23,6 +23,8 @@
 | |
|  #include <linux/rcupdate.h>
 | |
|  #include <linux/parser.h>
 | |
|  #include <linux/vmalloc.h>
 | |
| +#include <linux/proc_ns.h>
 | |
| +#include <linux/radix-tree.h>
 | |
|  
 | |
|  #include "ima.h"
 | |
|  
 | |
| @@ -272,6 +274,40 @@ static const struct file_operations ima_ascii_measurements_ops = {
 | |
|  	.release = seq_release,
 | |
|  };
 | |
|  
 | |
| +#ifdef CONFIG_IMA_PER_NAMESPACE
 | |
| +/*
 | |
| + * check_mntns: check a mount namespace is valid
 | |
| + *
 | |
| + * @ns_id: namespace id to be checked
 | |
| + * Returns 0 if the namespace is valid.
 | |
| + *
 | |
| + * Note: a better way to implement this check is needed. There are
 | |
| + * cases where the namespace id is valid but not in use by any process
 | |
| + * and then this implementation misses this case. Could we use an
 | |
| + * interface similar to what setns implements?
 | |
| + */
 | |
| +static int check_mntns(unsigned int ns_id)
 | |
| +{
 | |
| +	struct task_struct *p;
 | |
| +	int result = 1;
 | |
| +	struct ns_common *ns;
 | |
| +
 | |
| +	rcu_read_lock();
 | |
| +	for_each_process(p) {
 | |
| +		ns = mntns_operations.get(p);
 | |
| +		if (ns->inum == ns_id) {
 | |
| +			result = 0;
 | |
| +			mntns_operations.put(ns);
 | |
| +			break;
 | |
| +		}
 | |
| +		mntns_operations.put(ns);
 | |
| +	}
 | |
| +	rcu_read_unlock();
 | |
| +
 | |
| +	return result;
 | |
| +}
 | |
| +#endif
 | |
| +
 | |
|  static ssize_t ima_read_policy(char *path)
 | |
|  {
 | |
|  	void *data;
 | |
| @@ -366,6 +402,9 @@ static struct dentry *ascii_runtime_measurements;
 | |
|  static struct dentry *runtime_measurements_count;
 | |
|  static struct dentry *violations;
 | |
|  static struct dentry *ima_policy;
 | |
| +#ifdef CONFIG_IMA_PER_NAMESPACE
 | |
| +static struct dentry *ima_namespaces;
 | |
| +#endif
 | |
|  
 | |
|  enum ima_fs_flags {
 | |
|  	IMA_FS_BUSY,
 | |
| @@ -451,6 +490,139 @@ static const struct file_operations ima_measure_policy_ops = {
 | |
|  	.llseek = generic_file_llseek,
 | |
|  };
 | |
|  
 | |
| +#ifdef CONFIG_IMA_PER_NAMESPACE
 | |
| +/*
 | |
| + * Assumes namespace id is in use by some process and this mapping
 | |
| + * does not exist in the map table.
 | |
| + */
 | |
| +static int create_mnt_ns_directory(unsigned int ns_id)
 | |
| +{
 | |
| +	int result;
 | |
| +	struct dentry *ns_dir, *ns_policy;
 | |
| +	char dir_name[64];
 | |
| +
 | |
| +	snprintf(dir_name, sizeof(dir_name), "%u", ns_id);
 | |
| +
 | |
| +	ns_dir = securityfs_create_dir(dir_name, ima_dir);
 | |
| +	if (IS_ERR(ns_dir)) {
 | |
| +		result = PTR_ERR(ns_dir);
 | |
| +		goto out;
 | |
| +	}
 | |
| +
 | |
| +	ns_policy = securityfs_create_file("policy", POLICY_FILE_FLAGS,
 | |
| +		                                ns_dir, NULL,
 | |
| +		                                &ima_measure_policy_ops);
 | |
| +	if (IS_ERR(ns_policy)) {
 | |
| +		result = PTR_ERR(ns_policy);
 | |
| +		securityfs_remove(ns_dir);
 | |
| +		goto out;
 | |
| +	}
 | |
| +
 | |
| +	result = 0;
 | |
| +
 | |
| +out:
 | |
| +	return result;
 | |
| +}
 | |
| +
 | |
| +static ssize_t handle_new_namespace_policy(const char *data, size_t datalen)
 | |
| +{
 | |
| +	unsigned int ns_id;
 | |
| +	ssize_t result;
 | |
| +
 | |
| +	result = -EINVAL;
 | |
| +
 | |
| +	if (sscanf(data, "%u", &ns_id) != 1) {
 | |
| +		pr_err("IMA: invalid namespace id: %s\n", data);
 | |
| +		goto out;
 | |
| +	}
 | |
| +
 | |
| +	if (check_mntns(ns_id)) {
 | |
| +		result = -ENOENT;
 | |
| +		pr_err("IMA: unused namespace id %u\n", ns_id);
 | |
| +		goto out;
 | |
| +	}
 | |
| +
 | |
| +	result = create_mnt_ns_directory(ns_id);
 | |
| +	if (result != 0) {
 | |
| +		pr_err("IMA: namespace id %u directory creation failed\n", ns_id);
 | |
| +		goto out;
 | |
| +	}
 | |
| +
 | |
| +	result = datalen;
 | |
| +	pr_info("IMA: directory created for namespace id %u\n", ns_id);
 | |
| +
 | |
| +out:
 | |
| +	return result;
 | |
| +}
 | |
| +
 | |
| +static ssize_t ima_write_namespaces(struct file *file, const char __user *buf,
 | |
| +		                            size_t datalen, loff_t *ppos)
 | |
| +{
 | |
| +	char *data;
 | |
| +	ssize_t result;
 | |
| +
 | |
| +	if (datalen >= PAGE_SIZE)
 | |
| +		datalen = PAGE_SIZE - 1;
 | |
| +
 | |
| +	/* No partial writes. */
 | |
| +	result = -EINVAL;
 | |
| +	if (*ppos != 0)
 | |
| +		goto out;
 | |
| +
 | |
| +	result = -ENOMEM;
 | |
| +	data = kmalloc(datalen + 1, GFP_KERNEL);
 | |
| +	if (!data)
 | |
| +		goto out;
 | |
| +
 | |
| +	*(data + datalen) = '\0';
 | |
| +
 | |
| +	result = -EFAULT;
 | |
| +	if (copy_from_user(data, buf, datalen))
 | |
| +		goto out_free;
 | |
| +
 | |
| +	result = mutex_lock_interruptible(&ima_write_mutex);
 | |
| +	if (result < 0)
 | |
| +		goto out_free;
 | |
| +
 | |
| +	result = handle_new_namespace_policy(data, datalen);
 | |
| +
 | |
| +	mutex_unlock(&ima_write_mutex);
 | |
| +
 | |
| +out_free:
 | |
| +	kfree(data);
 | |
| +out:
 | |
| +	return result;
 | |
| +}
 | |
| +
 | |
| +static int ima_open_namespaces(struct inode *inode, struct file *filp)
 | |
| +{
 | |
| +	if (!(filp->f_flags & O_WRONLY))
 | |
| +		return -EACCES;
 | |
| +
 | |
| +	if (!capable(CAP_SYS_ADMIN))
 | |
| +		return -EPERM;
 | |
| +
 | |
| +	if (test_and_set_bit(IMA_FS_BUSY, &ima_fs_flags))
 | |
| +		return -EBUSY;
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static int ima_release_namespaces(struct inode *inode, struct file *file)
 | |
| +{
 | |
| +	clear_bit(IMA_FS_BUSY, &ima_fs_flags);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static const struct file_operations ima_namespaces_ops = {
 | |
| +		.open = ima_open_namespaces,
 | |
| +		.write = ima_write_namespaces,
 | |
| +		.read = seq_read,
 | |
| +		.release = ima_release_namespaces,
 | |
| +		.llseek = generic_file_llseek,
 | |
| +};
 | |
| +#endif
 | |
| +
 | |
|  int __init ima_fs_init(void)
 | |
|  {
 | |
|  	ima_dir = securityfs_create_dir("ima", NULL);
 | |
| @@ -490,6 +662,14 @@ int __init ima_fs_init(void)
 | |
|  	if (IS_ERR(ima_policy))
 | |
|  		goto out;
 | |
|  
 | |
| +#ifdef CONFIG_IMA_PER_NAMESPACE
 | |
| +	ima_namespaces = securityfs_create_file("namespaces", NAMESPACES_FILE_FLAGS,
 | |
| +						ima_dir, NULL,
 | |
| +						&ima_namespaces_ops);
 | |
| +	if (IS_ERR(ima_namespaces))
 | |
| +		goto out;
 | |
| +#endif
 | |
| +
 | |
|  	return 0;
 | |
|  out:
 | |
|  	securityfs_remove(violations);
 | |
| @@ -498,5 +678,8 @@ int __init ima_fs_init(void)
 | |
|  	securityfs_remove(binary_runtime_measurements);
 | |
|  	securityfs_remove(ima_dir);
 | |
|  	securityfs_remove(ima_policy);
 | |
| +#ifdef CONFIG_IMA_PER_NAMESPACE
 | |
| +	securityfs_remove(ima_namespaces);
 | |
| +#endif
 | |
|  	return -1;
 | |
|  }
 | |
| -- 
 | |
| 2.9.3
 | |
| 
 |