[PATCH 1/2] !!!! HERE BE DRAGONS - COMPLETELY UNTESTED !!!!

From: Christian Brauner
Date: Fri Dec 10 2021 - 04:31:27 EST


The relevant ima_ns that .open/.read/.write operate on is always taken to be
the ima_ns of the filesystem's userns, i.e. sb->s_user_ns->ima_ns. This - but
I'm not an ima person - makes the most sense to me and the semantics are
straightforward. If I write to a file to alter some policy then I expect the
ima namespace of the user namespace to be affected that the securityfs instance
was mounted in.
---
security/integrity/ima/ima_fs.c | 30 ++++++++++++++++++-----------
security/integrity/ima/ima_policy.c | 8 ++++++--
2 files changed, 25 insertions(+), 13 deletions(-)

diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index 778983fd9a73..95b7b9ec2a76 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -49,7 +49,8 @@ static ssize_t ima_show_htable_violations(struct file *filp,
char __user *buf,
size_t count, loff_t *ppos)
{
- struct ima_namespace *ns = get_current_ns();
+ struct user_namespace *user_ns = filp->f_path.mnt->mnt_sb->s_user_ns;
+ struct ima_namespace *ns = user_ns->ima_ns;

return ima_show_htable_value(buf, count, ppos, &ns->ima_htable.violations);
}
@@ -63,7 +64,8 @@ static ssize_t ima_show_measurements_count(struct file *filp,
char __user *buf,
size_t count, loff_t *ppos)
{
- struct ima_namespace *ns = get_current_ns();
+ struct user_namespace *user_ns = filp->f_path.mnt->mnt_sb->s_user_ns;
+ struct ima_namespace *ns = user_ns->ima_ns;

return ima_show_htable_value(buf, count, ppos, &ns->ima_htable.len);
}
@@ -76,7 +78,9 @@ static const struct file_operations ima_measurements_count_ops = {
/* returns pointer to hlist_node */
static void *ima_measurements_start(struct seq_file *m, loff_t *pos)
{
- struct ima_namespace *ns = get_current_ns();
+ const struct file *filp = m->file;
+ struct user_namespace *user_ns = filp->f_path.mnt->mnt_sb->s_user_ns;
+ struct ima_namespace *ns = user_ns->ima_ns;
loff_t l = *pos;
struct ima_queue_entry *qe;

@@ -94,7 +98,9 @@ static void *ima_measurements_start(struct seq_file *m, loff_t *pos)

static void *ima_measurements_next(struct seq_file *m, void *v, loff_t *pos)
{
- struct ima_namespace *ns = get_current_ns();
+ const struct file *filp = m->file;
+ struct user_namespace *user_ns = filp->f_path.mnt->mnt_sb->s_user_ns;
+ struct ima_namespace *ns = user_ns->ima_ns;
struct ima_queue_entry *qe = v;

/* lock protects when reading beyond last element
@@ -273,9 +279,8 @@ static const struct file_operations ima_ascii_measurements_ops = {
.release = seq_release,
};

-static ssize_t ima_read_policy(char *path)
+static ssize_t ima_read_policy(struct ima_namespace *ns, char *path)
{
- struct ima_namespace *ns = get_current_ns();
void *data = NULL;
char *datap;
size_t size;
@@ -317,7 +322,8 @@ static ssize_t ima_read_policy(char *path)
static ssize_t ima_write_policy(struct file *file, const char __user *buf,
size_t datalen, loff_t *ppos)
{
- struct ima_namespace *ns = get_current_ns();
+ struct user_namespace *user_ns = file->f_path.mnt->mnt_sb->s_user_ns;
+ struct ima_namespace *ns = user_ns->ima_ns;
char *data;
ssize_t result;

@@ -340,7 +346,7 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf,
goto out_free;

if (data[0] == '/') {
- result = ima_read_policy(data);
+ result = ima_read_policy(ns, data);
} else if (ima_appraise & IMA_APPRAISE_POLICY) {
pr_err("signed policy file (specified as an absolute pathname) required\n");
integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL,
@@ -378,7 +384,8 @@ static const struct seq_operations ima_policy_seqops = {
*/
static int ima_open_policy(struct inode *inode, struct file *filp)
{
- struct ima_namespace *ns = get_current_ns();
+ struct user_namespace *user_ns = inode->i_sb->s_user_ns;
+ struct ima_namespace *ns = user_ns->ima_ns;

if (!(filp->f_flags & O_WRONLY)) {
#ifndef CONFIG_IMA_READ_POLICY
@@ -386,7 +393,7 @@ static int ima_open_policy(struct inode *inode, struct file *filp)
#else
if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
return -EACCES;
- if (!mac_admin_ns_capable(ns->user_ns))
+ if (!mac_admin_ns_capable(user_ns))
return -EPERM;
return seq_open(filp, &ima_policy_seqops);
#endif
@@ -405,7 +412,8 @@ static int ima_open_policy(struct inode *inode, struct file *filp)
*/
static int ima_release_policy(struct inode *inode, struct file *file)
{
- struct ima_namespace *ns = get_current_ns();
+ struct user_namespace *user_ns = inode->i_sb->s_user_ns;
+ struct ima_namespace *ns = user_ns->ima_ns;
const char *cause = ns->valid_policy ? "completed" : "failed";

if ((file->f_flags & O_ACCMODE) == O_RDONLY)
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 747dca6131d6..41e5f17ec44d 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -1908,7 +1908,9 @@ static const char *const mask_tokens[] = {

void *ima_policy_start(struct seq_file *m, loff_t *pos)
{
- struct ima_namespace *ns = get_current_ns();
+ const struct file *filp = m->file;
+ struct user_namespace *user_ns = filp->f_path.mnt->mnt_sb->user_ns;
+ struct ima_namespace *ns = user_ns->ima_ns;
loff_t l = *pos;
struct ima_rule_entry *entry;
struct list_head *ima_rules_tmp;
@@ -1928,7 +1930,9 @@ void *ima_policy_start(struct seq_file *m, loff_t *pos)
void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos)
{
struct ima_rule_entry *entry = v;
- struct ima_namespace *ns = get_current_ns();
+ const struct file *filp = m->file;
+ struct user_namespace *user_ns = filp->f_path.mnt->mnt_sb->user_ns;
+ struct ima_namespace *ns = user_ns->ima_ns;

rcu_read_lock();
entry = list_entry_rcu(entry->list.next, struct ima_rule_entry, list);
--
2.30.2