Skip to content

Commit

Permalink
AppArmor: mediation of non file objects
Browse files Browse the repository at this point in the history
ipc:
AppArmor ipc is currently limited to mediation done by file mediation
and basic ptrace tests.  Improved mediation is a wip.

rlimits:
AppArmor provides basic abilities to set and control rlimits at
a per profile level.  Only resources specified in a profile are controled
or set.  AppArmor rules set the hard limit to a value <= to the current
hard limit (ie. they can not currently raise hard limits), and if
necessary will lower the soft limit to the new hard limit value.

AppArmor does not track resource limits to reset them when a profile
is left so that children processes inherit the limits set by the
parent even if they are not confined by the same profile.

Capabilities:  AppArmor provides a per profile mask of capabilities,
that will further restrict.

Signed-off-by: John Johansen <john.johansen@canonical.com>
Signed-off-by: James Morris <jmorris@namei.org>
  • Loading branch information
John Johansen authored and James Morris committed Aug 2, 2010
1 parent b5e95b4 commit 0ed3b28
Show file tree
Hide file tree
Showing 6 changed files with 508 additions and 0 deletions.
141 changes: 141 additions & 0 deletions security/apparmor/capability.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
* AppArmor security module
*
* This file contains AppArmor capability mediation functions
*
* Copyright (C) 1998-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/capability.h>
#include <linux/errno.h>
#include <linux/gfp.h>

#include "include/apparmor.h"
#include "include/capability.h"
#include "include/context.h"
#include "include/policy.h"
#include "include/audit.h"

/*
* Table of capability names: we generate it from capabilities.h.
*/
#include "capability_names.h"

struct audit_cache {
struct aa_profile *profile;
kernel_cap_t caps;
};

static DEFINE_PER_CPU(struct audit_cache, audit_cache);

/**
* audit_cb - call back for capability components of audit struct
* @ab - audit buffer (NOT NULL)
* @va - audit struct to audit data from (NOT NULL)
*/
static void audit_cb(struct audit_buffer *ab, void *va)
{
struct common_audit_data *sa = va;
audit_log_format(ab, " capname=");
audit_log_untrustedstring(ab, capability_names[sa->u.cap]);
}

/**
* audit_caps - audit a capability
* @profile: profile confining task (NOT NULL)
* @task: task capability test was performed against (NOT NULL)
* @cap: capability tested
* @error: error code returned by test
*
* Do auditing of capability and handle, audit/complain/kill modes switching
* and duplicate message elimination.
*
* Returns: 0 or sa->error on success, error code on failure
*/
static int audit_caps(struct aa_profile *profile, struct task_struct *task,
int cap, int error)
{
struct audit_cache *ent;
int type = AUDIT_APPARMOR_AUTO;
struct common_audit_data sa;
COMMON_AUDIT_DATA_INIT(&sa, CAP);
sa.tsk = task;
sa.u.cap = cap;
sa.aad.op = OP_CAPABLE;
sa.aad.error = error;

if (likely(!error)) {
/* test if auditing is being forced */
if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
!cap_raised(profile->caps.audit, cap)))
return 0;
type = AUDIT_APPARMOR_AUDIT;
} else if (KILL_MODE(profile) ||
cap_raised(profile->caps.kill, cap)) {
type = AUDIT_APPARMOR_KILL;
} else if (cap_raised(profile->caps.quiet, cap) &&
AUDIT_MODE(profile) != AUDIT_NOQUIET &&
AUDIT_MODE(profile) != AUDIT_ALL) {
/* quiet auditing */
return error;
}

/* Do simple duplicate message elimination */
ent = &get_cpu_var(audit_cache);
if (profile == ent->profile && cap_raised(ent->caps, cap)) {
put_cpu_var(audit_cache);
if (COMPLAIN_MODE(profile))
return complain_error(error);
return error;
} else {
aa_put_profile(ent->profile);
ent->profile = aa_get_profile(profile);
cap_raise(ent->caps, cap);
}
put_cpu_var(audit_cache);

return aa_audit(type, profile, GFP_ATOMIC, &sa, audit_cb);
}

/**
* profile_capable - test if profile allows use of capability @cap
* @profile: profile being enforced (NOT NULL, NOT unconfined)
* @cap: capability to test if allowed
*
* Returns: 0 if allowed else -EPERM
*/
static int profile_capable(struct aa_profile *profile, int cap)
{
return cap_raised(profile->caps.allow, cap) ? 0 : -EPERM;
}

/**
* aa_capable - test permission to use capability
* @task: task doing capability test against (NOT NULL)
* @profile: profile confining @task (NOT NULL)
* @cap: capability to be tested
* @audit: whether an audit record should be generated
*
* Look up capability in profile capability set.
*
* Returns: 0 on success, or else an error code.
*/
int aa_capable(struct task_struct *task, struct aa_profile *profile, int cap,
int audit)
{
int error = profile_capable(profile, cap);

if (!audit) {
if (COMPLAIN_MODE(profile))
return complain_error(error);
return error;
}

return audit_caps(profile, task, cap, error);
}
45 changes: 45 additions & 0 deletions security/apparmor/include/capability.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* AppArmor security module
*
* This file contains AppArmor capability mediation definitions.
*
* Copyright (C) 1998-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.
*/

#ifndef __AA_CAPABILITY_H
#define __AA_CAPABILITY_H

#include <linux/sched.h>

struct aa_profile;

/* aa_caps - confinement data for capabilities
* @allowed: capabilities mask
* @audit: caps that are to be audited
* @quiet: caps that should not be audited
* @kill: caps that when requested will result in the task being killed
* @extended: caps that are subject finer grained mediation
*/
struct aa_caps {
kernel_cap_t allow;
kernel_cap_t audit;
kernel_cap_t quiet;
kernel_cap_t kill;
kernel_cap_t extended;
};

int aa_capable(struct task_struct *task, struct aa_profile *profile, int cap,
int audit);

static inline void aa_free_cap_rules(struct aa_caps *caps)
{
/* NOP */
}

#endif /* __AA_CAPBILITY_H */
28 changes: 28 additions & 0 deletions security/apparmor/include/ipc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* AppArmor security module
*
* This file contains AppArmor ipc mediation function definitions.
*
* Copyright (C) 1998-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.
*/

#ifndef __AA_IPC_H
#define __AA_IPC_H

#include <linux/sched.h>

struct aa_profile;

int aa_may_ptrace(struct task_struct *tracer_task, struct aa_profile *tracer,
struct aa_profile *tracee, unsigned int mode);

int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee,
unsigned int mode);

#endif /* __AA_IPC_H */
46 changes: 46 additions & 0 deletions security/apparmor/include/resource.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* AppArmor security module
*
* This file contains AppArmor resource limits function definitions.
*
* Copyright (C) 1998-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.
*/

#ifndef __AA_RESOURCE_H
#define __AA_RESOURCE_H

#include <linux/resource.h>
#include <linux/sched.h>

struct aa_profile;

/* struct aa_rlimit - rlimit settings for the profile
* @mask: which hard limits to set
* @limits: rlimit values that override task limits
*
* AppArmor rlimits are used to set confined task rlimits. Only the
* limits specified in @mask will be controlled by apparmor.
*/
struct aa_rlimit {
unsigned int mask;
struct rlimit limits[RLIM_NLIMITS];
};

int aa_map_resource(int resource);
int aa_task_setrlimit(struct aa_profile *profile, unsigned int resource,
struct rlimit *new_rlim);

void __aa_transition_rlimits(struct aa_profile *old, struct aa_profile *new);

static inline void aa_free_rlimit_rules(struct aa_rlimit *rlims)
{
/* NOP */
}

#endif /* __AA_RESOURCE_H */
114 changes: 114 additions & 0 deletions security/apparmor/ipc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
* AppArmor security module
*
* This file contains AppArmor ipc mediation
*
* Copyright (C) 1998-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/gfp.h>
#include <linux/ptrace.h>

#include "include/audit.h"
#include "include/capability.h"
#include "include/context.h"
#include "include/policy.h"

/* call back to audit ptrace fields */
static void audit_cb(struct audit_buffer *ab, void *va)
{
struct common_audit_data *sa = va;
audit_log_format(ab, " target=");
audit_log_untrustedstring(ab, sa->aad.target);
}

/**
* aa_audit_ptrace - do auditing for ptrace
* @profile: profile being enforced (NOT NULL)
* @target: profile being traced (NOT NULL)
* @error: error condition
*
* Returns: %0 or error code
*/
static int aa_audit_ptrace(struct aa_profile *profile,
struct aa_profile *target, int error)
{
struct common_audit_data sa;
COMMON_AUDIT_DATA_INIT(&sa, NONE);
sa.aad.op = OP_PTRACE;
sa.aad.target = target;
sa.aad.error = error;

return aa_audit(AUDIT_APPARMOR_AUTO, profile, GFP_ATOMIC, &sa,
audit_cb);
}

/**
* aa_may_ptrace - test if tracer task can trace the tracee
* @tracer_task: task who will do the tracing (NOT NULL)
* @tracer: profile of the task doing the tracing (NOT NULL)
* @tracee: task to be traced
* @mode: whether PTRACE_MODE_READ || PTRACE_MODE_ATTACH
*
* Returns: %0 else error code if permission denied or error
*/
int aa_may_ptrace(struct task_struct *tracer_task, struct aa_profile *tracer,
struct aa_profile *tracee, unsigned int mode)
{
/* TODO: currently only based on capability, not extended ptrace
* rules,
* Test mode for PTRACE_MODE_READ || PTRACE_MODE_ATTACH
*/

if (unconfined(tracer) || tracer == tracee)
return 0;
/* log this capability request */
return aa_capable(tracer_task, tracer, CAP_SYS_PTRACE, 1);
}

/**
* aa_ptrace - do ptrace permission check and auditing
* @tracer: task doing the tracing (NOT NULL)
* @tracee: task being traced (NOT NULL)
* @mode: ptrace mode either PTRACE_MODE_READ || PTRACE_MODE_ATTACH
*
* Returns: %0 else error code if permission denied or error
*/
int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee,
unsigned int mode)
{
/*
* tracer can ptrace tracee when
* - tracer is unconfined ||
* - tracer is in complain mode
* - tracer has rules allowing it to trace tracee currently this is:
* - confined by the same profile ||
* - tracer profile has CAP_SYS_PTRACE
*/

struct aa_profile *tracer_p;
/* cred released below */
const struct cred *cred = get_task_cred(tracer);
int error = 0;
tracer_p = aa_cred_profile(cred);

if (!unconfined(tracer_p)) {
/* lcred released below */
struct cred *lcred = get_task_cred(tracee);
struct aa_profile *tracee_p = aa_cred_profile(lcred);

error = aa_may_ptrace(tracer, tracer_p, tracee_p, mode);
error = aa_audit_ptrace(tracer_p, tracee_p, error);

put_cred(lcred);
}
put_cred(cred);

return error;
}
Loading

0 comments on commit 0ed3b28

Please sign in to comment.