提交 ee67fcbf 编写于 作者: K Krzysztof Struczynski 提交者: Zheng Zengkai

ima: Add a list of the installed ima namespaces

hulk inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I49KW1
CVE: NA

--------------------------------

Add a list of the installed ima namespaces. IMA namespace is considered
installed, if there is at least one process born in that namespace.

This list will be used to check the read-write violations and to detect
any object related changes relevant across namespaces.
Signed-off-by: NKrzysztof Struczynski <krzysztof.struczynski@huawei.com>
Reviewed-by: NZhang Tianxing <zhangtianxing3@huawei.com>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
上级 a8352473
......@@ -11,10 +11,12 @@
#include <linux/fs.h>
#include <linux/security.h>
#include <linux/kexec.h>
struct linux_binprm;
struct linux_binprm;
struct nsproxy;
struct task_struct;
struct list_head;
struct llist_node;
#ifdef CONFIG_IMA
extern int ima_bprm_check(struct linux_binprm *bprm);
......@@ -206,6 +208,10 @@ struct ima_namespace {
struct ns_common ns;
struct ucounts *ucounts;
struct user_namespace *user_ns;
struct list_head list;
struct llist_node cleanup_list; /* namespaces on a death row */
atomic_t inactive; /* set only when ns is added to the cleanup list */
bool frozen;
} __randomize_layout;
extern struct ima_namespace init_ima_ns;
......
......@@ -363,12 +363,23 @@ static inline enum integrity_status ima_get_cache_status(struct integrity_iint_c
#endif /* CONFIG_IMA_APPRAISE */
extern struct list_head ima_ns_list;
extern struct rw_semaphore ima_ns_list_lock;
#ifdef CONFIG_IMA_NS
int __init ima_init_namespace(void);
static inline struct ima_namespace *get_current_ns(void)
{
return current->nsproxy->ima_ns;
}
#else
static inline int __init ima_init_namespace(void)
{
list_add_tail(&init_ima_ns.list, &ima_ns_list);
return 0;
}
static inline struct ima_namespace *get_current_ns(void)
{
return &init_ima_ns;
......
......@@ -32,6 +32,7 @@ struct ima_namespace init_ima_ns = {
#ifdef CONFIG_IMA_NS
.ns.ops = &imans_operations,
#endif
.frozen = true
};
EXPORT_SYMBOL(init_ima_ns);
......@@ -158,6 +159,10 @@ int __init ima_init(void)
ima_init_policy();
rc = ima_init_namespace();
if (rc != 0)
return rc;
rc = ima_fs_init();
if (rc != 0)
return rc;
......
......@@ -47,6 +47,9 @@ bool ima_plus_standard_pcr;
static int hash_setup_done;
DECLARE_RWSEM(ima_ns_list_lock);
LIST_HEAD(ima_ns_list);
static struct notifier_block ima_lsm_policy_notifier = {
.notifier_call = ima_lsm_policy_change,
};
......
......@@ -21,9 +21,20 @@
#include <linux/user_namespace.h>
#include <linux/nsproxy.h>
#include <linux/sched.h>
#include <linux/list.h>
#include <linux/llist.h>
#include <linux/rwsem.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
#include "ima.h"
static LLIST_HEAD(cleanup_list);
static struct workqueue_struct *imans_wq;
/* Protects tasks entering the same, not yet active namespace */
static DEFINE_MUTEX(frozen_lock);
static struct ucounts *inc_ima_namespaces(struct user_namespace *ns)
{
return inc_ucount(ns, current_euid(), UCOUNT_IMA_NAMESPACES);
......@@ -78,6 +89,7 @@ static struct ima_namespace *clone_ima_ns(struct user_namespace *user_ns,
ns->ns.ops = &imans_operations;
ns->user_ns = get_user_ns(user_ns);
ns->ucounts = ucounts;
ns->frozen = false;
return ns;
......@@ -109,6 +121,19 @@ struct ima_namespace *copy_ima_ns(unsigned long flags,
return clone_ima_ns(user_ns, old_ns);
}
int __init ima_init_namespace(void)
{
/* Create workqueue for cleanup */
imans_wq = create_singlethread_workqueue("imans");
if (unlikely(!imans_wq))
return -ENOMEM;
/* No other reader or writer at this stage */
list_add_tail(&init_ima_ns.list, &ima_ns_list);
return 0;
}
static void destroy_ima_ns(struct ima_namespace *ns)
{
dec_ima_namespaces(ns->ucounts);
......@@ -117,13 +142,46 @@ static void destroy_ima_ns(struct ima_namespace *ns)
kfree(ns);
}
static void cleanup_ima(struct work_struct *work)
{
struct ima_namespace *ima_ns, *tmp;
struct llist_node *ima_kill_list;
/* Atomically snapshot the list of namespaces to cleanup */
ima_kill_list = llist_del_all(&cleanup_list);
/* Remove ima namespace from the namespace list */
down_write(&ima_ns_list_lock);
llist_for_each_entry(ima_ns, ima_kill_list, cleanup_list)
list_del(&ima_ns->list);
up_write(&ima_ns_list_lock);
/* After removing ima namespace from the ima_ns_list, memory can be
* freed. At this stage nothing should keep a reference to the given
* namespace.
*/
llist_for_each_entry_safe(ima_ns, tmp, ima_kill_list, cleanup_list)
destroy_ima_ns(ima_ns);
}
static DECLARE_WORK(ima_cleanup_work, cleanup_ima);
void free_ima_ns(struct kref *kref)
{
struct ima_namespace *ns;
struct ima_namespace *ima_ns;
ns = container_of(kref, struct ima_namespace, kref);
ima_ns = container_of(kref, struct ima_namespace, kref);
/* Namespace can be destroyed instantly if no process ever was born
* into it - it was never added to the ima_ns_list.
*/
if (!ima_ns->frozen) {
destroy_ima_ns(ima_ns);
return;
}
destroy_ima_ns(ns);
atomic_set(&ima_ns->inactive, 1);
if (llist_add(&ima_ns->cleanup_list, &cleanup_list))
queue_work(imans_wq, &ima_cleanup_work);
}
static inline struct ima_namespace *to_ima_ns(struct ns_common *ns)
......@@ -168,8 +226,32 @@ static void imans_put(struct ns_common *ns)
put_ima_ns(to_ima_ns(ns));
}
static int imans_activate(struct ima_namespace *ima_ns)
{
if (ima_ns == &init_ima_ns)
return 0;
if (ima_ns->frozen)
return 0;
mutex_lock(&frozen_lock);
if (ima_ns->frozen)
goto out;
ima_ns->frozen = true;
down_write(&ima_ns_list_lock);
list_add_tail(&ima_ns->list, &ima_ns_list);
up_write(&ima_ns_list_lock);
out:
mutex_unlock(&frozen_lock);
return 0;
}
static int imans_install(struct nsset *nsset, struct ns_common *new)
{
int res;
struct nsproxy *nsproxy = nsset->nsproxy;
struct ima_namespace *ns = to_ima_ns(new);
......@@ -180,6 +262,10 @@ static int imans_install(struct nsset *nsset, struct ns_common *new)
!ns_capable(nsset->cred->user_ns, CAP_SYS_ADMIN))
return -EPERM;
res = imans_activate(ns);
if (res)
return res;
get_ima_ns(ns);
put_ima_ns(nsproxy->ima_ns);
nsproxy->ima_ns = ns;
......@@ -188,11 +274,12 @@ static int imans_install(struct nsset *nsset, struct ns_common *new)
put_ima_ns(nsproxy->ima_ns_for_children);
nsproxy->ima_ns_for_children = ns;
return 0;
return res;
}
int imans_on_fork(struct nsproxy *nsproxy, struct task_struct *tsk)
{
int res;
struct ns_common *nsc = &nsproxy->ima_ns_for_children->ns;
struct ima_namespace *ns = to_ima_ns(nsc);
......@@ -200,11 +287,15 @@ int imans_on_fork(struct nsproxy *nsproxy, struct task_struct *tsk)
if (nsproxy->ima_ns == nsproxy->ima_ns_for_children)
return 0;
res = imans_activate(ns);
if (res)
return res;
get_ima_ns(ns);
put_ima_ns(nsproxy->ima_ns);
nsproxy->ima_ns = ns;
return 0;
return res;
}
static struct user_namespace *imans_owner(struct ns_common *ns)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册