/*
* AppArmor security module
*
* This file contains AppArmor policy attachment and domain transitions
*
* Copyright (C) 2002-2008 Novell/SUSE
* Copyright 2009-2010 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2 of the
* License.
*/
#include <linux/errno.h>
#include <linux/fdtable.h>
#include <linux/file.h>
#include <linux/mount.h>
#include <linux/syscalls.h>
#include <linux/tracehook.h>
#include <linux/personality.h>
#include "include/audit.h"
#include "include/apparmorfs.h"
#include "include/context.h"
#include "include/domain.h"
#include "include/file.h"
#include "include/ipc.h"
#include "include/match.h"
#include "include/path.h"
#include "include/policy.h"
#include "include/policy_ns.h"
/**
* aa_free_domain_entries - free entries in a domain table
* @domain: the domain table to free (MAYBE NULL)
*/
void aa_free_domain_entries(struct aa_domain *domain)
{
int i;
if (domain) {
if (!domain->table)
return;
for (i = 0; i < domain->size; i++)
kzfree(domain->table[i]);
kzfree(domain->table);
domain->table = NULL;
}
}
/**
* may_change_ptraced_domain - check if can change profile on ptraced task
* @to_label: profile to change to (NOT NULL)
* @info: message if there is an error
*
* Check if current is ptraced and if so if the tracing task is allowed
* to trace the new domain
*
* Returns: %0 or error if change not allowed
*/
static int may_change_ptraced_domain(struct aa_label *to_label,
const char **info)
{
struct task_struct *tracer;
struct aa_label *tracerl = NULL;
int error = 0;
rcu_read_lock();
tracer = ptrace_parent(current);
if (tracer)
/* released below */
tracerl = aa_get_task_label(tracer);
/* not ptraced */
if (!tracer || unconfined(tracerl))
goto out;
error = aa_may_ptrace(tracerl, to_label, PTRACE_MODE_ATTACH);
out:
rcu_read_unlock();
aa_put_label(tracerl);
if (error)
*info = "ptrace prevents transition";
return error;
}
/**** TODO: dedup to aa_label_match - needs perm and dfa, merging
* specifically this is an exact copy of aa_label_match except
* aa_compute_perms is replaced with aa_compute_fperms
* and policy.dfa with file.dfa
****/
/* match a profile and its associated ns component if needed
* Assumes visibility test has already been done.
* If a subns profile is not to be matched should be prescreened with
* visibility test.
*/
static inline unsigned int match_component(struct aa_profile *profile,
struct aa_profile *tp,
bool stack, unsigned int state)
{
const char *ns_name;
if (stack)
state = aa_dfa_match(profile->file.dfa, state, "&");
if (profile->ns == tp->ns)
return aa_dfa_match(profile->file.dfa, state, tp->base.hname);
/* try matching with namespace name and then profile */
ns_name = aa_ns_name(profile->ns, tp->ns, true);
state = aa_dfa_match_len(profile->file.dfa, state, ":", 1);
state = aa_dfa_match(profile->file.dfa, state, ns_name);
state = aa_dfa_match_len(profile->file.dfa, state, ":", 1);
return aa_dfa_match(profile->file.dfa, state, tp->base.hname);
}
/**
* label_compound_match - find perms for full compound label
* @profile: profile to find perms for
* @label: label to check access permissions for
* @stack: whether this is a stacking request
* @start: state to start match in
* @subns: whether to do permission checks on components in a subns
* @request: permissions to request
* @perms: perms struct to set
*
* Returns: 0 on success else ERROR
*
* For the label A//&B//&C this does the perm match for A//&B//&C
* @perms should be preinitialized with allperms OR a previous permission
* check to be stacked.
*/
static int label_compound_match(struct aa_profile *profile,
struct