Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 192ca6b5 authored by John Johansen's avatar John Johansen
Browse files

apparmor: revalidate files during exec



Instead of running file revalidation lazily when read/write are called
copy selinux and revalidate the file table on exec. This avoids
extra mediation overhead in read/write and also prevents file handles
being passed through to a grand child unchecked.

Signed-off-by: default avatarJohn Johansen <john.johansen@canonical.com>
parent 2835a13b
Loading
Loading
Loading
Loading
+72 −0
Original line number Diff line number Diff line
@@ -12,8 +12,13 @@
 * License.
 */

#include <linux/tty.h>
#include <linux/fdtable.h>
#include <linux/file.h>

#include "include/apparmor.h"
#include "include/audit.h"
#include "include/context.h"
#include "include/file.h"
#include "include/match.h"
#include "include/path.h"
@@ -445,3 +450,70 @@ int aa_file_perm(const char *op, struct aa_profile *profile, struct file *file,
	return aa_path_perm(op, profile, &file->f_path, PATH_DELEGATE_DELETED,
			    request, &cond);
}

static void revalidate_tty(struct aa_profile *profile)
{
	struct tty_struct *tty;
	int drop_tty = 0;

	tty = get_current_tty();
	if (!tty)
		return;

	spin_lock(&tty->files_lock);
	if (!list_empty(&tty->tty_files)) {
		struct tty_file_private *file_priv;
		struct file *file;
		/* TODO: Revalidate access to controlling tty. */
		file_priv = list_first_entry(&tty->tty_files,
					     struct tty_file_private, list);
		file = file_priv->file;

		if (aa_file_perm(OP_INHERIT, profile, file,
				 MAY_READ | MAY_WRITE))
			drop_tty = 1;
	}
	spin_unlock(&tty->files_lock);
	tty_kref_put(tty);

	if (drop_tty)
		no_tty();
}

static int match_file(const void *p, struct file *file, unsigned int fd)
{
	struct aa_profile *profile = (struct aa_profile *)p;

	if (aa_file_perm(OP_INHERIT, profile, file,
			 aa_map_file_to_perms(file)))
		return fd + 1;
	return 0;
}


/* based on selinux's flush_unauthorized_files */
void aa_inherit_files(const struct cred *cred, struct files_struct *files)
{
	struct aa_profile *profile = aa_get_newest_cred_profile(cred);
	struct file *devnull = NULL;
	unsigned int n;

	revalidate_tty(profile);

	/* Revalidate access to inherited open files. */
	n = iterate_fd(files, 0, match_file, profile);
	if (!n) /* none found? */
		goto out;

	devnull = dentry_open(&aa_null, O_RDWR, cred);
	if (IS_ERR(devnull))
		devnull = NULL;
	/* replace all the matching ones with this */
	do {
		replace_fd(n - 1, devnull, 0);
	} while ((n = iterate_fd(files, n, match_file, profile)) != 0);
	if (devnull)
		fput(devnull);
out:
	aa_put_profile(profile);
}
+1 −0
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ enum audit_type {
#define OP_FLOCK "file_lock"
#define OP_FMMAP "file_mmap"
#define OP_FMPROT "file_mprotect"
#define OP_INHERIT "file_inherit"

#define OP_CREATE "create"
#define OP_POST_CREATE "post_create"
+2 −0
Original line number Diff line number Diff line
@@ -186,6 +186,8 @@ int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry,
int aa_file_perm(const char *op, struct aa_profile *profile, struct file *file,
		 u32 request);

void aa_inherit_files(const struct cred *cred, struct files_struct *files);

static inline void aa_free_file_rules(struct aa_file_rules *rules)
{
	aa_put_dfa(rules->dfa);
+6 −0
Original line number Diff line number Diff line
@@ -417,6 +417,10 @@ static int common_file_perm(const char *op, struct file *file, u32 mask)
	struct aa_profile *profile, *fprofile;
	int error = 0;

	/* don't reaudit files closed during inheritance */
	if (file->f_path.dentry == aa_null.dentry)
		return -EACCES;

	fprofile = aa_cred_raw_profile(file->f_cred);
	AA_BUG(!fprofile);

@@ -600,6 +604,8 @@ static void apparmor_bprm_committing_creds(struct linux_binprm *bprm)
	    (unconfined(new_ctx->profile)))
		return;

	aa_inherit_files(bprm->cred, current->files);

	current->pdeath_signal = 0;

	/* reset soft limits and set hard limits for the new profile */