[RFC PATCH 5/7] SELINUXNS: Migrate all open files and all vma to new namespace
Alexander Kozhevnikov
alexander.kozhevnikov at huawei.com
Mon Apr 18 09:45:50 UTC 2022
From: Igor Baranov <igor.baranov at huawei.com>
When process switched to another namespace and loads a new policy, the
following problem occurs: the current open files in their
file_security_struct contain the sid's relevant to the loaded policy
in the old namespace. Under the new policy, they have completely
random (incorrect) values, and, as a rule, accessing such descriptors
leads to failure. For example, a process gets EACCES when writing to its
own stdout.
Our solution: reinitialize sid's and isid's to actual values in new policy
of all opened files, as well as of files referenced by process's VMA.
Signed-off-by: Alexander Kozhevnikov <alexander.kozhevnikov at huawei.com>
Signed-off-by: Igor Baranov <igor.baranov at huawei.com>
---
security/selinux/hooks.c | 94 +++++++++++++++++++++++++++++++++++-
security/selinux/selinuxfs.c | 2 +-
2 files changed, 93 insertions(+), 3 deletions(-)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index b618c4e0ef36..74d32b6a4855 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -91,6 +91,7 @@
#include <uapi/linux/mount.h>
#include <linux/fsnotify.h>
#include <linux/fanotify.h>
+#include <linux/sched/mm.h>
#include "avc.h"
#include "objsec.h"
@@ -4159,8 +4160,7 @@ static int selinux_file_open(struct file *file)
* Task label is already saved in the file security
* struct as its SID.
*/
- //TODO: namespace?
- fsec->isid = isec->sid;
+ fsec->isid = update_sid(isec);
fsec->pseqno = avc_policy_seqno(current_selinux_state);
/*
* Since the inode label or policy seqno may have changed
@@ -7659,6 +7659,8 @@ static void delayed_superblock_init(struct super_block *sb, void *unused)
selinux_set_mnt_opts(sb, NULL, 0, NULL);
}
+static void migrate_files(void);
+
void selinux_complete_init(void)
{
pr_debug("SELinux: Completing initialization.\n");
@@ -7666,6 +7668,9 @@ void selinux_complete_init(void)
/* Set up any superblocks initialized prior to the policy load. */
pr_debug("SELinux: Setting up existing superblocks.\n");
iterate_supers(delayed_superblock_init, NULL);
+
+ if (current_selinux_state->id != 0)
+ migrate_files();
}
/* SELinux requires early initialization in order to label
@@ -7816,3 +7821,88 @@ int selinux_disable(struct selinux_state *state)
return 0;
}
#endif
+
+
+/* TODO: check&return errors? */
+static void migrate_fds(void)
+{
+ unsigned int fd;
+ struct files_struct *files = current->files;
+ u32 tsid = current_sid();
+
+ rcu_read_lock();
+ for (fd = 0; fd < files_fdtable(files)->max_fds; fd++) {
+ struct inode *inode;
+ struct file_security_struct *fsec;
+ struct file *file = fcheck_files(files, fd);
+
+ if (!file)
+ continue;
+
+ fsec = selinux_file(file);
+
+ fsec->sid = fsec->fown_sid = tsid;
+ inode = file_inode(file);
+ if (inode) {
+ get_file(file);
+ rcu_read_unlock();
+ fsec->isid = update_sid(inode_security(inode));
+ rcu_read_lock();
+ fput(file);
+ }
+ }
+ rcu_read_unlock();
+}
+
+static int migrate_vmas(void)
+{
+ int ret;
+ struct mempolicy *task_mempolicy;
+ struct vm_area_struct *vma;
+ u32 tsid = current_sid();
+ struct mm_struct *mm = mm_access(current, PTRACE_MODE_READ | PTRACE_MODE_FSCREDS);
+
+ if (IS_ERR_OR_NULL(mm))
+ return PTR_ERR(mm);
+
+ ret = mmap_read_lock_killable(mm);
+ if (ret)
+ goto out_put_mm;
+
+ task_mempolicy = get_task_policy(current);
+ mpol_get(task_mempolicy);
+
+ for (vma = mm->mmap; vma; vma = vma->vm_next) {
+ struct file *file = vma->vm_file;
+ struct file_security_struct *fsec;
+ struct inode *inode;
+
+ if (!file)
+ continue;
+
+ fsec = selinux_file(file);
+
+ inode = file_inode(file);
+ if (inode)
+ fsec->isid = update_sid(inode_security(inode));
+
+ fsec->sid = fsec->fown_sid = tsid;
+ }
+
+ mpol_put(task_mempolicy);
+ mmap_read_unlock(mm);
+
+out_put_mm:
+ mmput(mm);
+
+ return ret;
+}
+
+/* TODO return error? */
+void migrate_files(void)
+{
+ migrate_fds();
+
+/* TODO: return error */
+ migrate_vmas();
+}
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 2da27f2fc2e3..18c5383b87a9 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -2306,7 +2306,7 @@ static int selinuxfs_compare(struct super_block *sb, struct fs_context *fc)
{
struct selinux_fs_info *fsi = sb->s_fs_info;
- return (current_selinux_state == fsi->state);
+ return (current_selinux_state->id == fsi->state->id);
}
static int sel_get_tree(struct fs_context *fc)
--
2.34.1
More information about the Linux-security-module-archive
mailing list