Commit 6bfc18ae authored by John Johansen's avatar John Johansen Committed by Tim Gardner

UBUNTU: SAUCE: (no-up) apparmor: Sync to apparmor3 - RC1 snapshot

This is a sync and squash to the apparmor 3 RC 1 development snapshot.
The set of patches in this squash are available at the apparmor-3.RC1
tag in git://kernel.ubuntu.com/jj/ubuntu-utopic.git.

This cleans up several functions over the alpha6 sync, and includes
multiple bug fixes. In addition it picks up
- new network mediation
- fine grained mediation of all unix socket types

BugLink: http://bugs.launchpad.net/bugs/1362199Signed-off-by: default avatarJohn Johansen <john.johansen@canonical.com>
Signed-off-by: default avatarTyler Hicks <tyhicks@canonical.com>
Signed-off-by: default avatarTim Gardner <tim.gardner@canonical.com>
Signed-off-by: default avatarAndy Whitcroft <apw@canonical.com>
Signed-off-by: default avatarTim Gardner <tim.gardner@canonical.com>
parent 41689645
#
# Generated include files
#
net_names.h
capability_names.h
rlim_names.h
......@@ -30,6 +30,41 @@ config SECURITY_APPARMOR_BOOTPARAM_VALUE
If you are unsure how to answer this question, answer 1.
config SECURITY_APPARMOR_STATS
bool "enable debug statistics"
depends on SECURITY_APPARMOR
select APPARMOR_LABEL_STATS
default n
help
This enables keeping statistics on various internal structures
and functions in apparmor.
If you are unsure how to answer this question, answer N.
config SECURITY_APPARMOR_UNCONFINED_INIT
bool "Set init to unconfined on boot"
depends on SECURITY_APPARMOR
default y
help
This option determines policy behavior during early boot by
placing the init process in the unconfined state, or the
'default' profile.
This option determines policy behavior during early boot by
placing the init process in the unconfined state, or the
'default' profile.
'Y' means init and its children are not confined, unless the
init process is re-execed after a policy load; loaded policy
will only apply to processes started after the load.
'N' means init and its children are confined in a profile
named 'default', which can be replaced later and thus
provide for confinement for processes started early at boot,
though not confined during early boot.
If you are unsure how to answer this question, answer Y.
config SECURITY_APPARMOR_HASH
bool "enable introspection of sha1 hashes for loaded profiles"
depends on SECURITY_APPARMOR
......
......@@ -4,11 +4,44 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
resource.o sid.o file.o
resource.o sid.o file.o label.o mount.o net.o af_unix.o
apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
clean-files := capability_names.h rlim_names.h
clean-files := capability_names.h rlim_names.h net_names.h
# Build a lower case string table of address family names
# Transform lines from
# define AF_LOCAL 1 /* POSIX name for AF_UNIX */
# #define AF_INET 2 /* Internet IP Protocol */
# to
# [1] = "local",
# [2] = "inet",
#
# and build the securityfs entries for the mapping.
# Transforms lines from
# #define AF_INET 2 /* Internet IP Protocol */
# to
# #define AA_FS_AF_MASK "local inet"
quiet_cmd_make-af = GEN $@
cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\
sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e "/AF_ROUTE/d" -e \
's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
echo "};" >> $@ ;\
echo -n '\#define AA_FS_AF_MASK "' >> $@ ;\
sed -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e "/AF_ROUTE/d" -e \
's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/\L\1/p'\
$< | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
# Build a lower case string table of sock type names
# Transform lines from
# SOCK_STREAM = 1,
# to
# [1] = "stream",
quiet_cmd_make-sock = GEN $@
cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\
sed $^ >>$@ -r -n \
-e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
echo "};" >> $@
# Build a lower case string table of capability names
# Transforms lines from
......@@ -61,6 +94,7 @@ cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \
tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
$(obj)/capability.o : $(obj)/capability_names.h
$(obj)/net.o : $(obj)/net_names.h
$(obj)/resource.o : $(obj)/rlim_names.h
$(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
$(src)/Makefile
......@@ -68,3 +102,8 @@ $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
$(obj)/rlim_names.h : $(srctree)/include/uapi/asm-generic/resource.h \
$(src)/Makefile
$(call cmd,make-rlim)
$(obj)/net_names.h : $(srctree)/include/linux/socket.h \
$(srctree)/include/linux/net.h \
$(src)/Makefile
$(call cmd,make-af)
$(call cmd,make-sock)
This diff is collapsed.
This diff is collapsed.
......@@ -39,10 +39,16 @@ const char *const op_table[] = {
"getattr",
"open",
"file_receive",
"file_perm",
"file_lock",
"file_mmap",
"file_mprotect",
"file_inherit",
"pivotroot",
"mount",
"umount",
"create",
"post_create",
......@@ -59,6 +65,7 @@ const char *const op_table[] = {
"socket_shutdown",
"ptrace",
"signal",
"exec",
"change_hat",
......@@ -114,34 +121,41 @@ static void audit_pre(struct audit_buffer *ab, void *ca)
if (aa_g_audit_header) {
audit_log_format(ab, "apparmor=");
audit_log_string(ab, aa_audit_type[sa->aad->type]);
audit_log_string(ab, aa_audit_type[aad(sa)->type]);
}
if (sa->aad->op) {
if (aad(sa)->op) {
audit_log_format(ab, " operation=");
audit_log_string(ab, op_table[sa->aad->op]);
audit_log_string(ab, op_table[aad(sa)->op]);
}
if (sa->aad->info) {
if (aad(sa)->info) {
audit_log_format(ab, " info=");
audit_log_string(ab, sa->aad->info);
if (sa->aad->error)
audit_log_format(ab, " error=%d", sa->aad->error);
audit_log_string(ab, aad(sa)->info);
if (aad(sa)->error)
audit_log_format(ab, " error=%d", aad(sa)->error);
}
if (sa->aad->profile) {
struct aa_profile *profile = sa->aad->profile;
if (profile->ns != root_ns) {
audit_log_format(ab, " namespace=");
audit_log_untrustedstring(ab, profile->ns->base.hname);
if (aad(sa)->label) {
struct aa_label *label = aad(sa)->label;
if (label_isprofile(label)) {
struct aa_profile *profile = labels_profile(label);
if (profile->ns != root_ns) {
audit_log_format(ab, " namespace=");
audit_log_untrustedstring(ab,
profile->ns->base.hname);
}
audit_log_format(ab, " profile=");
audit_log_untrustedstring(ab, profile->base.hname);
} else {
audit_log_format(ab, " label=");
aa_label_audit(ab, root_ns, label, false, GFP_ATOMIC);
}
audit_log_format(ab, " profile=");
audit_log_untrustedstring(ab, profile->base.hname);
}
if (sa->aad->name) {
if (aad(sa)->name) {
audit_log_format(ab, " name=");
audit_log_untrustedstring(ab, sa->aad->name);
audit_log_untrustedstring(ab, aad(sa)->name);
}
}
......@@ -153,7 +167,12 @@ static void audit_pre(struct audit_buffer *ab, void *ca)
void aa_audit_msg(int type, struct common_audit_data *sa,
void (*cb) (struct audit_buffer *, void *))
{
sa->aad->type = type;
/* TODO: redirect messages for profile to the correct ns
* rejects from subns should goto the audit associated
* with it, and audits from parent ns should got ns
* associated with it
*/
aad(sa)->type = type;
common_lsm_audit(sa, audit_pre, cb);
}
......@@ -161,7 +180,6 @@ void aa_audit_msg(int type, struct common_audit_data *sa,
* aa_audit - Log a profile based audit event to the audit subsystem
* @type: audit type for the message
* @profile: profile to check against (NOT NULL)
* @gfp: allocation flags to use
* @sa: audit event (NOT NULL)
* @cb: optional callback fn for type specific fields (MAYBE NULL)
*
......@@ -169,14 +187,13 @@ void aa_audit_msg(int type, struct common_audit_data *sa,
*
* Returns: error on failure
*/
int aa_audit(int type, struct aa_profile *profile, gfp_t gfp,
struct common_audit_data *sa,
int aa_audit(int type, struct aa_profile *profile, struct common_audit_data *sa,
void (*cb) (struct audit_buffer *, void *))
{
BUG_ON(!profile);
if (type == AUDIT_APPARMOR_AUTO) {
if (likely(!sa->aad->error)) {
if (likely(!aad(sa)->error)) {
if (AUDIT_MODE(profile) != AUDIT_ALL)
return 0;
type = AUDIT_APPARMOR_AUDIT;
......@@ -188,22 +205,22 @@ int aa_audit(int type, struct aa_profile *profile, gfp_t gfp,
if (AUDIT_MODE(profile) == AUDIT_QUIET ||
(type == AUDIT_APPARMOR_DENIED &&
AUDIT_MODE(profile) == AUDIT_QUIET))
return sa->aad->error;
return aad(sa)->error;
if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED)
type = AUDIT_APPARMOR_KILL;
if (!unconfined(profile))
sa->aad->profile = profile;
aad(sa)->label = &profile->label;
aa_audit_msg(type, sa, cb);
if (sa->aad->type == AUDIT_APPARMOR_KILL)
if (aad(sa)->type == AUDIT_APPARMOR_KILL)
(void)send_sig_info(SIGKILL, NULL,
sa->u.tsk ? sa->u.tsk : current);
sa->type == LSM_AUDIT_DATA_TASK && sa->u.tsk ?
sa->u.tsk : current);
if (sa->aad->type == AUDIT_APPARMOR_ALLOWED)
return complain_error(sa->aad->error);
if (aad(sa)->type == AUDIT_APPARMOR_ALLOWED)
return complain_error(aad(sa)->error);
return sa->aad->error;
return aad(sa)->error;
}
......@@ -53,6 +53,7 @@ static void audit_cb(struct audit_buffer *ab, void *va)
/**
* audit_caps - audit a capability
* @sa: audit data
* @profile: profile being tested for confinement (NOT NULL)
* @cap: capability tested
* @error: error code returned by test
......@@ -62,17 +63,12 @@ static void audit_cb(struct audit_buffer *ab, void *va)
*
* Returns: 0 or sa->error on success, error code on failure
*/
static int audit_caps(struct aa_profile *profile, int cap, int error)
static int audit_caps(struct common_audit_data *sa, struct aa_profile *profile,
int cap, int error)
{
struct audit_cache *ent;
int type = AUDIT_APPARMOR_AUTO;
struct common_audit_data sa;
struct apparmor_audit_data aad = {0,};
sa.type = LSM_AUDIT_DATA_CAP;
sa.aad = &aad;
sa.u.cap = cap;
sa.aad->op = OP_CAPABLE;
sa.aad->error = error;
aad(sa)->error = error;
if (likely(!error)) {
/* test if auditing is being forced */
......@@ -104,24 +100,40 @@ static int audit_caps(struct aa_profile *profile, int cap, int error)
}
put_cpu_var(audit_cache);
return aa_audit(type, profile, GFP_ATOMIC, &sa, audit_cb);
return aa_audit(type, profile, 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
* @sa: audit data (MAY BE NULL indicating no auditing)
*
* Returns: 0 if allowed else -EPERM
*/
static int profile_capable(struct aa_profile *profile, int cap)
static int profile_capable(struct aa_profile *profile, int cap,
struct common_audit_data *sa)
{
return cap_raised(profile->caps.allow, cap) ? 0 : -EPERM;
int error;
if (cap_raised(profile->caps.allow, cap) &&
!cap_raised(profile->caps.denied, cap))
error = 0;
else
error = -EPERM;
if (!sa) {
if (COMPLAIN_MODE(profile))
return complain_error(error);
return error;
}
return audit_caps(sa, profile, cap, error);
}
/**
* aa_capable - test permission to use capability
* @profile: profile being tested against (NOT NULL)
* @label: label being tested for capability (NOT NULL)
* @cap: capability to be tested
* @audit: whether an audit record should be generated
*
......@@ -129,15 +141,15 @@ static int profile_capable(struct aa_profile *profile, int cap)
*
* Returns: 0 on success, or else an error code.
*/
int aa_capable(struct aa_profile *profile, int cap, int audit)
int aa_capable(struct aa_label *label, int cap, int audit)
{
int error = profile_capable(profile, cap);
struct aa_profile *profile;
int error = 0;
DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_CAP, OP_CAPABLE);
sa.u.cap = cap;
if (!audit) {
if (COMPLAIN_MODE(profile))
return complain_error(error);
return error;
}
error = fn_for_each_confined(label, profile,
profile_capable(profile, cap, audit ? &sa : NULL));
return audit_caps(profile, cap, error);
return error;
}
......@@ -14,9 +14,9 @@
*
*
* AppArmor sets confinement on every task, via the the aa_task_cxt and
* the aa_task_cxt.profile, both of which are required and are not allowed
* the aa_task_cxt.label, both of which are required and are not allowed
* to be NULL. The aa_task_cxt is not reference counted and is unique
* to each cred (which is reference count). The profile pointed to by
* to each cred (which is reference count). The label pointed to by
* the task_cxt is reference counted.
*
* TODO
......@@ -47,9 +47,9 @@ struct aa_task_cxt *aa_alloc_task_context(gfp_t flags)
void aa_free_task_context(struct aa_task_cxt *cxt)
{
if (cxt) {
aa_put_profile(cxt->profile);
aa_put_profile(cxt->previous);
aa_put_profile(cxt->onexec);
aa_put_label(cxt->label);
aa_put_label(cxt->previous);
aa_put_label(cxt->onexec);
kzfree(cxt);
}
......@@ -63,41 +63,41 @@ void aa_free_task_context(struct aa_task_cxt *cxt)
void aa_dup_task_context(struct aa_task_cxt *new, const struct aa_task_cxt *old)
{
*new = *old;
aa_get_profile(new->profile);
aa_get_profile(new->previous);
aa_get_profile(new->onexec);
aa_get_label(new->label);
aa_get_label(new->previous);
aa_get_label(new->onexec);
}
/**
* aa_get_task_profile - Get another task's profile
* aa_get_task_label - Get another task's label
* @task: task to query (NOT NULL)
*
* Returns: counted reference to @task's profile
* Returns: counted reference to @task's label
*/
struct aa_profile *aa_get_task_profile(struct task_struct *task)
struct aa_label *aa_get_task_label(struct task_struct *task)
{
struct aa_profile *p;
struct aa_label *p;
rcu_read_lock();
p = aa_get_profile(__aa_task_profile(task));
p = aa_get_newest_label(__aa_task_raw_label(task));
rcu_read_unlock();
return p;
}
/**
* aa_replace_current_profile - replace the current tasks profiles
* @profile: new profile (NOT NULL)
* aa_replace_current_label - replace the current tasks label
* @label: new label (NOT NULL)
*
* Returns: 0 or error on failure
*/
int aa_replace_current_profile(struct aa_profile *profile)
int aa_replace_current_label(struct aa_label *label)
{
struct aa_task_cxt *cxt = current_cxt();
struct cred *new;
BUG_ON(!profile);
BUG_ON(!label);
if (cxt->profile == profile)
if (cxt->label == label)
return 0;
new = prepare_creds();
......@@ -105,19 +105,15 @@ int aa_replace_current_profile(struct aa_profile *profile)
return -ENOMEM;
cxt = cred_cxt(new);
if (unconfined(profile) || (cxt->profile->ns != profile->ns))
/* if switching to unconfined or a different profile namespace
if (unconfined(label) || (labels_ns(cxt->label) != labels_ns(label)))
/* if switching to unconfined or a different label namespace
* clear out context state
*/
aa_clear_task_cxt_trans(cxt);
/* be careful switching cxt->profile, when racing replacement it
* is possible that cxt->profile->replacedby->profile is the reference
* keeping @profile valid, so make sure to get its reference before
* dropping the reference on cxt->profile */
aa_get_profile(profile);
aa_put_profile(cxt->profile);
cxt->profile = profile;
aa_get_label(label);
aa_put_label(cxt->label);
cxt->label = label;
commit_creds(new);
return 0;
......@@ -125,11 +121,11 @@ int aa_replace_current_profile(struct aa_profile *profile)
/**
* aa_set_current_onexec - set the tasks change_profile to happen onexec
* @profile: system profile to set at exec (MAYBE NULL to clear value)
* @label: system label to set at exec (MAYBE NULL to clear value)
*
* Returns: 0 or error on failure
*/
int aa_set_current_onexec(struct aa_profile *profile)
int aa_set_current_onexec(struct aa_label *label)
{
struct aa_task_cxt *cxt;
struct cred *new = prepare_creds();
......@@ -137,9 +133,9 @@ int aa_set_current_onexec(struct aa_profile *profile)
return -ENOMEM;
cxt = cred_cxt(new);
aa_get_profile(profile);
aa_put_profile(cxt->onexec);
cxt->onexec = profile;
aa_get_label(label);
aa_put_label(cxt->onexec);
cxt->onexec = label;
commit_creds(new);
return 0;
......@@ -147,7 +143,7 @@ int aa_set_current_onexec(struct aa_profile *profile)
/**
* aa_set_current_hat - set the current tasks hat
* @profile: profile to set as the current hat (NOT NULL)
* @label: label to set as the current hat (NOT NULL)
* @token: token value that must be specified to change from the hat
*
* Do switch of tasks hat. If the task is currently in a hat
......@@ -155,29 +151,29 @@ int aa_set_current_onexec(struct aa_profile *profile)
*
* Returns: 0 or error on failure
*/
int aa_set_current_hat(struct aa_profile *profile, u64 token)
int aa_set_current_hat(struct aa_label *label, u64 token)
{
struct aa_task_cxt *cxt;
struct cred *new = prepare_creds();
if (!new)
return -ENOMEM;
BUG_ON(!profile);
BUG_ON(!label);
cxt = cred_cxt(new);
if (!cxt->previous) {
/* transfer refcount */
cxt->previous = cxt->profile;
cxt->previous = cxt->label;
cxt->token = token;
} else if (cxt->token == token) {
aa_put_profile(cxt->profile);
aa_put_label(cxt->label);
} else {
/* previous_profile && cxt->token != token */
abort_creds(new);
return -EACCES;
}
cxt->profile = aa_get_newest_profile(profile);
cxt->label = aa_get_newest_label(label);
/* clear exec on switching context */
aa_put_profile(cxt->onexec);
aa_put_label(cxt->onexec);
cxt->onexec = NULL;
commit_creds(new);
......@@ -185,15 +181,15 @@ int aa_set_current_hat(struct aa_profile *profile, u64 token)
}
/**
* aa_restore_previous_profile - exit from hat context restoring the profile
* aa_restore_previous_label - exit from hat context restoring previous label
* @token: the token that must be matched to exit hat context
*
* Attempt to return out of a hat to the previous profile. The token
* Attempt to return out of a hat to the previous label. The token
* must match the stored token value.
*
* Returns: 0 or error of failure
*/
int aa_restore_previous_profile(u64 token)
int aa_restore_previous_label(u64 token)
{
struct aa_task_cxt *cxt;
struct cred *new = prepare_creds();
......@@ -205,15 +201,15 @@ int aa_restore_previous_profile(u64 token)
abort_creds(new);
return -EACCES;
}
/* ignore restores when there is no saved profile */
/* ignore restores when there is no saved label */
if (!cxt->previous) {
abort_creds(new);
return 0;
}
aa_put_profile(cxt->profile);
cxt->profile = aa_get_newest_profile(cxt->previous);
BUG_ON(!cxt->profile);
aa_put_label(cxt->label);
cxt->label = aa_get_newest_label(cxt->previous);
BUG_ON(!cxt->label);
/* clear exec && prev information when restoring to previous context */
aa_clear_task_cxt_trans(cxt);
......
This diff is collapsed.
This diff is collapsed.
/*
* AppArmor security module
*
* This file contains AppArmor af_unix fine grained mediation
*
* Copyright 2014 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_AF_UNIX_H
#include <net/af_unix.h>
#include "label.h"
//#include "include/net.h"
#define unix_addr_len(L) ((L) - sizeof(sa_family_t))
#define unix_abstract_name_len(L) (unix_addr_len(L) - 1)
#define unix_abstract_len(U) (unix_abstract_name_len((U)->addr->len))
#define addr_unix_abstract_name(B) ((B)[0] == 0)
#define addr_unix_anonymous(U) (addr_unix_len(U) <= 0)
#define addr_unix_abstract(U) (!addr_unix_anonymous(U) && addr_unix_abstract_name((U)->addr))
//#define unix_addr_fs(U) (!unix_addr_anonymous(U) && !unix_addr_abstract_name((U)->addr))
#define unix_addr(A) ((struct sockaddr_un *)(A))
#define unix_addr_anon(A, L) ((A) && unix_addr_len(L) <= 0)
#define unix_addr_fs(A, L) (!unix_addr_anon(A, L) && unix_addr(A)->sun_path[0] == '/')
#define UNIX_ANONYMOUS(U) (!unix_sk(U)->addr)
/* from net/unix/af_unix.c */
#define UNIX_ABSTRACT(U) (!UNIX_ANONYMOUS(U) && \
unix_sk(U)->addr->hash < UNIX_HASH_SIZE)
#define UNIX_FS(U) (!UNIX_ANONYMOUS(U) && unix_sk(U)->addr->name->sun_path[0])
#define unix_peer(sk) (unix_sk(sk)->peer)
#define unix_connected(S) ((S)->state == SS_CONNECTED)
static inline void print_unix_addr(struct sockaddr_un *A, int L)
{
char *buf = (A) ? (char *) &(A)->sun_path : NULL;
int len = unix_addr_len(L);
if (!buf || len <= 0)
printk(" <anonymous>");
else if (buf[0])
printk(" %s", buf);
else
/* abstract name len includes leading \0 */
printk(" %d @%.*s", len - 1, len - 1, buf+1);
};
/*
printk("%s: %s: f %d, t %d, p %d", __FUNCTION__, \
#SK , \
*/
#define print_unix_sk(SK) \
do { \
struct unix_sock *u = unix_sk(SK); \
printk("%s: f %d, t %d, p %d", #SK , \
(SK)->sk_family, (SK)->sk_type, (SK)->sk_protocol); \
if (u->addr) \
print_unix_addr(u->addr->name, u->addr->len); \
else \
print_unix_addr(NULL, sizeof(sa_family_t)); \
/* printk("\n");*/ \
} while (0)
#define print_sk(SK) \
do { \
if (!(SK)) { \
printk("%s: %s is null\n", __FUNCTION__, #SK); \
} else if ((SK)->sk_family == PF_UNIX) { \
print_unix_sk(SK); \
printk("\n"); \
} else { \
printk("%s: %s: family %d\n", __FUNCTION__, #SK , \
(SK)->sk_family); \
} \
} while (0)
#define print_sock_addr(U) \
do { \
printk("%s:\n", __FUNCTION__); \
printk(" sock %s:", sock_cxt && sock_cxt->label && sock_cxt->label->hname ? sock_cxt->label->hname : "<null>"); print_sk(sock); \
printk(" other %s:", other_cxt && other_cxt->label && other_cxt->label->hname ? other_cxt->label->hname : "<null>"); print_sk(other); \
printk(" new %s", new_cxt && new_cxt->label && new_cxt->label->hname ? new_cxt->label->hname : "<null>"); print_sk(newsk); \
} while (0)
#define DEFINE_AUDIT_UNIX(NAME, OP, SK, T, P) \
struct lsm_network_audit NAME ## _net = { .sk = (SK), \
.family = (AF_UNIX)}; \
DEFINE_AUDIT_DATA(NAME, LSM_AUDIT_DATA_NONE, OP); \
NAME.u.net = &(NAME ## _net); \
aad(&NAME)->net.type = (T); \
aad(&NAME)->net.protocol = (P)
int aa_unix_peer_perm(struct aa_label *label, int op, u32 request,
struct sock *sk, struct sock *peer_sk,
struct aa_label *peer_label);
int aa_unix_label_sk_perm(struct aa_label *label, int op, u32 request,
struct sock *sk);
int aa_unix_sock_perm(int op, u32 request, struct socket *sock);
int aa_unix_create_perm(struct aa_label *label, int family, int type,
int protocol);
int aa_unix_bind_perm(struct socket *sock, struct sockaddr *address,
int addrlen);
int aa_unix_connect_perm(struct socket *sock, struct sockaddr *address,
int addrlen);
int aa_unix_listen_perm(struct socket *sock, int backlog);
int aa_unix_accept_perm(struct socket *sock, struct socket *newsock);
int aa_unix_msg_perm(int op, u32 request, struct socket *sock,
struct msghdr *msg, int size);
int aa_unix_opt_perm(int op, u32 request, struct socket *sock, int level,
int optname);
int aa_unix_file_perm(struct aa_label *label, int op, u32 request,
struct socket *sock);
#endif /* __AA_AF_UNIX_H */
......@@ -4,7 +4,7 @@
* This file contains AppArmor basic global and lib definitions
*
* Copyright (C) 1998-2008 Novell/SUSE
* Copyright 2009-2010 Canonical Ltd.
* Copyright 2009-2013 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
......@@ -20,6 +20,17 @@
#include "match.h"
/* Provide our own test for whether a write lock is held for asserts
* this is because on none SMP systems write_can_lock will always
* resolve to true, which is what you want for code making decisions
* based on it, but wrong for asserts checking that the lock is held
*/
#ifdef CONFIG_SMP
#define write_is_locked(X) !write_can_lock(X)
#else
#define write_is_locked(X) (1)
#endif /* CONFIG_SMP */
/*
* Class of mediation types in the AppArmor policy db
*/
......@@ -30,8 +41,12 @@
#define AA_CLASS_NET 4
#define AA_CLASS_RLIMITS 5
#define AA_CLASS_DOMAIN 6
#define AA_CLASS_MOUNT 7
#define AA_CLASS_PTRACE 9
#define AA_CLASS_SIGNAL 10
#define AA_CLASS_LABEL 16
#define AA_CLASS_LAST AA_CLASS_DOMAIN
#define AA_CLASS_LAST AA_CLASS_LABEL
/* Control parameters settable through module/boot flags */
extern enum audit_mode aa_g_audit;
......@@ -42,6 +57,7 @@ extern bool aa_g_lock_policy;
extern bool aa_g_logsyscall;
extern bool aa_g_paranoid_load;
extern unsigned int aa_g_path_max;
extern bool aa_g_unconfined_init;
/*
* DEBUG remains global (no per profile flag) since it is mostly used in sysctl
......@@ -54,6 +70,12 @@ extern unsigned int aa_g_path_max;
printk(KERN_DEBUG "AppArmor: " fmt, ##args); \
} while (0)
#define AA_WARN(X) WARN((X), "APPARMOR WARN %s: %s\n", __FUNCTION__, #X)
#define AA_BUG(X, args...) AA_BUG_FMT((X), "" args )
#define AA_BUG_FMT(X, fmt, args...) \
WARN((X), "AppArmor WARN %s: (" #X "): " fmt, __FUNCTION__ , ##args )
#define AA_ERROR(fmt, args...) \
do { \
if (printk_ratelimit()) \
......@@ -65,6 +87,7 @@ extern int apparmor_initialized __initdata;
/* fn's in lib */
char *aa_split_fqname(char *args, char **ns_name);
char *aa_splitn_fqname(char *fqname, size_t n, char **ns_name, size_t *ns_len);
void aa_info_message(const char *str);
void *__aa_kvmalloc(size_t size, gfp_t flags);
......@@ -113,9 +136,40 @@ static inline unsigned int aa_dfa_null_transition(struct aa_dfa *dfa,
return aa_dfa_next(dfa, start, 0);
}
static inline bool mediated_filesystem(struct dentry *dentry)
static inline bool path_mediated_fs(struct dentry *dentry)
{
return !(dentry->d_sb->s_flags & MS_NOUSER);
}
struct counted_str {
struct kref count;
char name[];
};
#define str_to_counted(str) \
((struct counted_str *)(str - offsetof(struct counted_str,name)))
#define __counted /* atm just a notation */
void aa_str_kref(struct kref *kref);
char *aa_str_alloc(int size, gfp_t gfp);
static inline __counted char *aa_get_str(__counted char *str)
{
if (str)
kref_get(&(str_to_counted(str)->count));
return str;
}
static inline void aa_put_str(__counted char *str)
{
if (str)
kref_put(&str_to_counted(str)->count, aa_str_kref);
}
const char *aa_imode_name(umode_t mode);
#endif /* __APPARMOR_H */
......@@ -15,6 +15,8 @@
#ifndef __AA_APPARMORFS_H
#define __AA_APPARMORFS_H
extern struct path aa_null;
enum aa_fs_type {
AA_FS_TYPE_BOOLEAN,
AA_FS_TYPE_STRING,
......
......@@ -22,8 +22,7 @@
#include <linux/slab.h>
#include "file.h"
struct aa_profile;
#include "label.h"
extern const char *const audit_mode_names[];
#define AUDIT_MAX_INDEX 5
......@@ -67,10 +66,16 @@ enum aa_ops {
OP_GETATTR,
OP_OPEN,
OP_FRECEIVE,
OP_FPERM,
OP_FLOCK,
OP_FMMAP,
OP_FMPROT,
OP_INHERIT,
OP_PIVOTROOT,
OP_MOUNT,
OP_UMOUNT,
OP_CREATE,
OP_POST_CREATE,
......@@ -84,9 +89,10 @@ enum aa_ops {
OP_GETPEERNAME,
OP_GETSOCKOPT,
OP_SETSOCKOPT,
OP_SOCK_SHUTDOWN,
OP_SHUTDOWN,
OP_PTRACE,
OP_SIGNAL,
OP_EXEC,
OP_CHANGE_HAT,
......@@ -106,37 +112,69 @@ struct apparmor_audit_data {
int error;
int op;
int type;
void *profile;
struct aa_label *label;
const char *name;
const char *info;
u32 request;
u32 denied;
union {
void *target;
struct {
long pos;
void *target;
} iface;
const void *target;
union {
struct {
long pos;
} iface;
struct {
kuid_t ouid;
} fs;
struct {
int type, protocol;
struct sock *peer_sk;
void *addr;
int addrlen;
} net;
int signal;
};
};
struct {
int rlim;
unsigned long max;
} rlim;
struct {
const char *target;
u32 request;
u32 denied;
kuid_t ouid;
} fs;
const char *src_name;
const char *type;
const char *trans;
const char *data;
unsigned long flags;
} mnt;
};
};
/* define a short hand for apparmor_audit_data structure */
#define aad apparmor_audit_data
/* macros for dealing with apparmor_audit_data structure */
#define aad(SA) (SA)->apparmor_audit_data
#define DEFINE_AUDIT_DATA(NAME, T, X) \
/* TODO: cleanup audit init so we don't need _aad = {0,} */ \
struct apparmor_audit_data NAME ## _aad = { .op = (X), }; \
struct common_audit_data NAME = \
{ \
.type = (T), \
.u.tsk = NULL, \
}; \
NAME.apparmor_audit_data = &(NAME ## _aad)
void aa_audit_msg(int type, struct common_audit_data *sa,
void (*cb) (struct audit_buffer *, void *));
int aa_audit(int type, struct aa_profile *profile, gfp_t gfp,
struct common_audit_data *sa,
int aa_audit(int type, struct aa_profile *profile, struct common_audit_data *sa,
void (*cb) (struct audit_buffer *, void *));
#define aa_audit_error(ERROR, SA, CB) \
({ \
aad((SA))->error = (ERROR); \
aa_audit_msg(AUDIT_APPARMOR_ERROR, (SA), (CB)); \
aad((SA))->error; \
})
static inline int complain_error(int error)
{
if (error == -EPERM || error == -EACCES)
......
......@@ -19,11 +19,12 @@
#include "apparmorfs.h"
struct aa_profile;
struct aa_label;
/* aa_caps - confinement data for capabilities
* @allowed: capabilities mask
* @audit: caps that are to be audited
* @denied: caps that are explicitly denied
* @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
......@@ -31,6 +32,7 @@ struct aa_profile;
struct aa_caps {
kernel_cap_t allow;
kernel_cap_t audit;
kernel_cap_t denied;
kernel_cap_t quiet;
kernel_cap_t kill;
kernel_cap_t extended;
......@@ -38,7 +40,7 @@ struct aa_caps {
extern struct aa_fs_entry aa_fs_entry_caps[];
int aa_capable(struct aa_profile *profile, int cap, int audit);
int aa_capable(struct aa_label *label, int cap, int audit);
static inline void aa_free_cap_rules(struct aa_caps *caps)
{
......
......@@ -19,59 +19,29 @@
#include <linux/slab.h>
#include <linux/sched.h>
#include "label.h"
#include "policy.h"
#define cred_cxt(X) (X)->security
#define current_cxt() cred_cxt(current_cred())
/* struct aa_file_cxt - the AppArmor context the file was opened in
* @perms: the permission the file was opened with
*
* The file_cxt could currently be directly stored in file->f_security
* as the profile reference is now stored in the f_cred. However the
* cxt struct will expand in the future so we keep the struct.
*/
struct aa_file_cxt {
u16 allow;
};
/**
* aa_alloc_file_context - allocate file_cxt
* @gfp: gfp flags for allocation
*
* Returns: file_cxt or NULL on failure
*/
static inline struct aa_file_cxt *aa_alloc_file_context(gfp_t gfp)
{
return kzalloc(sizeof(struct aa_file_cxt), gfp);
}
/**
* aa_free_file_context - free a file_cxt
* @cxt: file_cxt to free (MAYBE_NULL)
*/
static inline void aa_free_file_context(struct aa_file_cxt *cxt)
{
if (cxt)
kzfree(cxt);
}
#define current_ns() labels_ns(aa_current_raw_label())
/**
* struct aa_task_cxt - primary label for confined tasks
* @profile: the current profile (NOT NULL)
* @exec: profile to transition to on next exec (MAYBE NULL)
* @previous: profile the task may return to (MAYBE NULL)
* @token: magic value the task must know for returning to @previous_profile
* @label: the current label (NOT NULL)
* @exec: label to transition to on next exec (MAYBE NULL)
* @previous: label the task may return to (MAYBE NULL)
* @token: magic value the task must know for returning to @previous
*
* Contains the task's current profile (which could change due to
* Contains the task's current label (which could change due to
* change_hat). Plus the hat_magic needed during change_hat.
*
* TODO: make so a task can be confined by a stack of contexts
*/
struct aa_task_cxt {
struct aa_profile *profile;
struct aa_profile *onexec;
struct aa_profile *previous;
struct aa_label *label;
struct aa_label *onexec;
struct aa_label *previous;
u64 token;
};
......@@ -79,39 +49,50 @@ struct aa_task_cxt *aa_alloc_task_context(gfp_t flags);
void aa_free_task_context(struct aa_task_cxt *cxt);
void aa_dup_task_context(struct aa_task_cxt *new,
const struct aa_task_cxt *old);
int aa_replace_current_profile(struct aa_profile *profile);
int aa_set_current_onexec(struct aa_profile *profile);
int aa_set_current_hat(struct aa_profile *profile, u64 token);
int aa_restore_previous_profile(u64 cookie);
struct aa_profile *aa_get_task_profile(struct task_struct *task);
int aa_replace_current_label(struct aa_label *label);
int aa_set_current_onexec(struct aa_label *label);
int aa_set_current_hat(struct aa_label *label, u64 token);
int aa_restore_previous_label(u64 cookie);
struct aa_label *aa_get_task_label(struct task_struct *task);
/**
* aa_cred_profile - obtain cred's profiles
* @cred: cred to obtain profiles from (NOT NULL)
* aa_cred_raw_label - obtain cred's label
* @cred: cred to obtain label from (NOT NULL)
*
* Returns: confining profile
* Returns: confining label
*
* does NOT increment reference count
*/
static inline struct aa_profile *aa_cred_profile(const struct cred *cred)
static inline struct aa_label *aa_cred_raw_label(const struct cred *cred)
{
struct aa_task_cxt *cxt = cred_cxt(cred);
BUG_ON(!cxt || !cxt->profile);
return cxt->profile;
BUG_ON(!cxt || !cxt->label);
return cxt->label;
}
/**
* __aa_task_profile - retrieve another task's profile
* aa_get_newest_cred_label - obtain the newest version of the label on a cred
* @cred: cred to obtain label from (NOT NULL)
*
* Returns: newest version of confining label
*/
static inline struct aa_label *aa_get_newest_cred_label(const struct cred *cred)
{
return aa_get_newest_label(aa_cred_raw_label(cred));
}
/**
* __aa_task_raw_label - retrieve another task's label
* @task: task to query (NOT NULL)
*
* Returns: @task's profile without incrementing its ref count
* Returns: @task's label without incrementing its ref count
*
* If @task != current needs to be called in RCU safe critical section
*/
static inline struct aa_profile *__aa_task_profile(struct task_struct *task)
static inline struct aa_label *__aa_task_raw_label(struct task_struct *task)
{
return aa_cred_profile(__task_cred(task));
return aa_cred_raw_label(__task_cred(task));
}
/**
......@@ -122,44 +103,93 @@ static inline struct aa_profile *__aa_task_profile(struct task_struct *task)
*/
static inline bool __aa_task_is_confined(struct task_struct *task)
{
return !unconfined(__aa_task_profile(task));
return !unconfined(__aa_task_raw_label(task));
}
/**
* __aa_current_profile - find the current tasks confining profile
* aa_current_raw_label - find the current tasks confining label
*
* Returns: up to date confining profile or the ns unconfined profile (NOT NULL)
* Returns: up to date confining label or the ns unconfined label (NOT NULL)
*
* This fn will not update the tasks cred to the most up to date version
* of the profile so it is safe to call when inside of locks.
* of the label so it is safe to call when inside of locks.
*/
static inline struct aa_label *aa_current_raw_label(void)
{
return aa_cred_raw_label(current_cred());
}
/**
* aa_get_current_label - get the newest version of the current tasks label
*
* Returns: newest version of confining label (NOT NULL)
*
* This fn will not update the tasks cred, so it is safe inside of locks
*
* The returned reference must be put with aa_put_label()
*/
static inline struct aa_label *aa_get_current_label(void)
{
struct aa_label *l = aa_current_raw_label();
if (label_invalid(l))
return aa_get_newest_label(l);
return aa_get_label(l);
}
/**
* aa_begin_current_label - find newest version of the current tasks label
*
* Returns: newest version of confining label (NOT NULL)
*
* This fn will not update the tasks cred, so it is safe inside of locks
*
* The returned reference must be put with aa_end_current_label()
*/
static inline struct aa_label *aa_begin_current_label(void)
{
struct aa_label *l = aa_current_raw_label();
if (label_invalid(l))
l = aa_get_newest_label(l);
return l;
}
/**
* aa_end_current_label - put a reference found with aa_begin_current_label
* @label: label reference to put
*
* Should only be used with a reference obtained with aa_begin_current_label
* and never used in situations where the task cred may be updated
*/
static inline struct aa_profile *__aa_current_profile(void)
static inline void aa_end_current_label(struct aa_label *label)
{
return aa_cred_profile(current_cred());
if (label != aa_current_raw_label())
aa_put_label(label);
}
/**
* aa_current_profile - find the current tasks confining profile and do updates
* aa_current_label - find the current tasks confining label and update it
*
* Returns: up to date confining profile or the ns unconfined profile (NOT NULL)
* Returns: up to date confining label or the ns unconfined label (NOT NULL)
*
* This fn will update the tasks cred structure if the profile has been
* This fn will update the tasks cred structure if the label has been
* replaced. Not safe to call inside locks
*/
static inline struct aa_profile *aa_current_profile(void)
static inline struct aa_label *aa_current_label(void)
{
const struct aa_task_cxt *cxt = current_cxt();
struct aa_profile *profile;
BUG_ON(!cxt || !cxt->profile);
struct aa_label *label;
BUG_ON(!cxt || !cxt->label);
if (PROFILE_INVALID(cxt->profile)) {
profile = aa_get_newest_profile(cxt->profile);
aa_replace_current_profile(profile);
aa_put_profile(profile);
if (label_invalid(cxt->label)) {
label = aa_get_newest_label(cxt->label);
aa_replace_current_label(label);
aa_put_label(label);
cxt = current_cxt();
}
return cxt->profile;
return cxt->label;
}
/**
......@@ -168,8 +198,8 @@ static inline struct aa_profile *aa_current_profile(void)
*/
static inline void aa_clear_task_cxt_trans(struct aa_task_cxt *cxt)
{
aa_put_profile(cxt->previous);
aa_put_profile(cxt->onexec);
aa_put_label(cxt->previous);
aa_put_label(cxt->onexec);
cxt->previous = NULL;
cxt->onexec = NULL;
cxt->token = 0;
......
......@@ -23,6 +23,8 @@ struct aa_domain {
char **table;
};
struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex);
int apparmor_bprm_set_creds(struct linux_binprm *bprm);
int apparmor_bprm_secureexec(struct linux_binprm *bprm);
void apparmor_bprm_committing_creds(struct linux_binprm *bprm);
......
......@@ -15,38 +15,75 @@
#ifndef __AA_FILE_H
#define __AA_FILE_H
#include <linux/spinlock.h>
#include "domain.h"
#include "match.h"
#include "label.h"
#include "perms.h"
struct aa_profile;
struct path;
/*
* We use MAY_EXEC, MAY_WRITE, MAY_READ, MAY_APPEND and the following flags
* for profile permissions
*/
#define AA_MAY_CREATE 0x0010
#define AA_MAY_DELETE 0x0020
#define AA_MAY_META_WRITE 0x0040
#define AA_MAY_META_READ 0x0080
#define AA_MAY_CHMOD 0x0100
#define AA_MAY_CHOWN 0x0200
#define AA_MAY_LOCK 0x0400
#define AA_EXEC_MMAP 0x0800
#define AA_MAY_LINK 0x1000
#define AA_LINK_SUBSET AA_MAY_LOCK /* overlaid */
#define AA_MAY_ONEXEC 0x40000000 /* exec allows onexec */
#define AA_MAY_CHANGE_PROFILE 0x80000000
#define AA_MAY_CHANGEHAT 0x80000000 /* ctrl auditing only */
#define mask_mode_t(X) (X & (MAY_EXEC | MAY_WRITE | MAY_READ | MAY_APPEND))
#define AA_AUDIT_FILE_MASK (MAY_READ | MAY_WRITE | MAY_EXEC | MAY_APPEND |\
AA_MAY_CREATE | AA_MAY_DELETE | \
AA_MAY_META_READ | AA_MAY_META_WRITE | \
AA_MAY_GETATTR | AA_MAY_SETATTR | \
AA_MAY_CHMOD | AA_MAY_CHOWN | AA_MAY_LOCK | \
AA_EXEC_MMAP | AA_MAY_LINK)
#define file_cxt(X) ((struct aa_file_cxt *)(X)->f_security)
/* struct aa_file_cxt - the AppArmor context the file was opened in
* @lock: lock to update the cxt
* @label: label currently cached on the cxt
* @perms: the permission the file was opened with
*/
struct aa_file_cxt {
spinlock_t lock;
struct aa_label __rcu *label;
u32 allow;
};
/**
* aa_alloc_file_cxt - allocate file_cxt
* @label: initial label of task creating the file
* @gfp: gfp flags for allocation
*
* Returns: file_cxt or NULL on failure
*/
static inline struct aa_file_cxt *aa_alloc_file_cxt(struct aa_label *label, gfp_t gfp)
{
struct aa_file_cxt *cxt;
cxt = kzalloc(sizeof(struct aa_file_cxt), gfp);
if (cxt) {
spin_lock_init(&cxt->lock);
rcu_assign_pointer(cxt->label, aa_get_label(label));
}
return cxt;
}
/**
* aa_free_file_cxt - free a file_cxt
* @cxt: file_cxt to free (MAYBE_NULL)
*/
static inline void aa_free_file_cxt(struct aa_file_cxt *cxt)
{
if (cxt) {
aa_put_label(rcu_access_pointer(cxt->label));
kzfree(cxt);
}
}
static inline struct aa_label *aa_get_file_label(struct aa_file_cxt *cxt)
{
return aa_get_label_rcu(&cxt->label);
}
#define inode_cxt(X) (X)->i_security
/*
* The xindex is broken into 3 parts
* - index - an index into either the exec name table or the variable table
......@@ -145,8 +182,8 @@ static inline u16 dfa_map_xindex(u16 mask)
dfa_map_xindex((ACCEPT_TABLE(dfa)[state] >> 14) & 0x3fff)
int aa_audit_file(struct aa_profile *profile, struct file_perms *perms,
gfp_t gfp, int op, u32 request, const char *name,
const char *target, kuid_t ouid, const char *info, int error);
int op, u32 request, const char *name, const char *target,
kuid_t ouid, const char *info, int error);
/**
* struct aa_file_rules - components used for file rule permissions
......@@ -171,15 +208,20 @@ unsigned int aa_str_perms(struct aa_dfa *dfa, unsigned int start,
const char *name, struct path_cond *cond,
struct file_perms *perms);
int aa_path_perm(int op, struct aa_profile *profile, struct path *path,
int __aa_path_perm(int op, struct aa_profile *profile, const char *name,
u32 request, struct path_cond *cond, int flags,
struct file_perms *perms);
int aa_path_perm(int op, struct aa_label *label, struct path *path,
int flags, u32 request, struct path_cond *cond);
int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry,
int aa_path_link(struct aa_label *label, struct dentry *old_dentry,
struct path *new_dir, struct dentry *new_dentry);
int aa_file_perm(int op, struct aa_profile *profile, struct file *file,
int aa_file_perm(int op, struct aa_label *label, 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);
......
......@@ -4,7 +4,7 @@
* This file contains AppArmor ipc mediation function definitions.
*
* Copyright (C) 1998-2008 Novell/SUSE
* Copyright 2009-2010 Canonical Ltd.
* Copyright 2009-2013 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
......@@ -19,10 +19,22 @@
struct aa_profile;
int aa_may_ptrace(struct aa_profile *tracer, struct aa_profile *tracee,
unsigned int mode);
#define AA_PTRACE_TRACE MAY_WRITE
#define AA_PTRACE_READ MAY_READ
#define AA_MAY_BE_TRACED AA_MAY_APPEND
#define AA_MAY_BE_READ AA_MAY_CREATE
#define PTRACE_PERM_SHIFT 2
int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee,
unsigned int mode);
#define AA_PTRACE_PERM_MASK (AA_PTRACE_READ | AA_PTRACE_TRACE | \
AA_MAY_BE_READ | AA_MAY_BE_TRACED)
#define AA_SIGNAL_PERM_MASK (MAY_READ | MAY_WRITE)
#define AA_FS_SIG_MASK "hup int quit ill trap abrt bus fpe kill usr1 " \
"segv usr2 pipe alrm term stkflt chld cont stop stp ttin ttou urg " \
"xcpu xfsz vtalrm prof winch io pwr sys emt lost"
int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee,
u32 request);
int aa_may_signal(struct aa_label *sender, struct aa_label *target, int sig);
#endif /* __AA_IPC_H */
This diff is collapsed.
......@@ -126,6 +126,21 @@ unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state,
void aa_dfa_free_kref(struct kref *kref);
/**
* aa_get_dfa - increment refcount on dfa @p
* @dfa: dfa (MAYBE NULL)
*
* Returns: pointer to @dfa if @dfa is NULL will return NULL
* Requires: @dfa must be held with valid refcount when called
*/
static inline struct aa_dfa *aa_get_dfa(struct aa_dfa *dfa)
{
if (dfa)
kref_get(&(dfa->count));
return dfa;
}
/**
* aa_put_dfa - put a dfa refcount
* @dfa: dfa to put refcount (MAYBE NULL)
......
/*
* AppArmor security module
*
* This file contains AppArmor file mediation function definitions.
*
* Copyright 2012 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_MOUNT_H
#define __AA_MOUNT_H
#include <linux/fs.h>
#include <linux/path.h>
#include "domain.h"
#include "policy.h"
/* mount perms */
#define AA_MAY_PIVOTROOT 0x01
#define AA_MAY_MOUNT 0x02
#define AA_MAY_UMOUNT 0x04
#define AA_AUDIT_DATA 0x40
#define AA_MNT_CONT_MATCH 0x40
#define AA_MS_IGNORE_MASK (MS_KERNMOUNT | MS_NOSEC | MS_ACTIVE | MS_BORN)
int aa_remount(struct aa_label *label, struct path *path, unsigned long flags,
void *data);
int aa_bind_mount(struct aa_label *label, struct path *path,
const char *old_name, unsigned long flags);
int aa_mount_change_type(struct aa_label *label, struct path *path,
unsigned long flags);
int aa_move_mount(struct aa_label *label, struct path *path,
const char *old_name);
int aa_new_mount(struct aa_label *label, const char *dev_name,
struct path *path, const char *type, unsigned long flags,
void *data);
int aa_umount(struct aa_label *label, struct vfsmount *mnt, int flags);
int aa_pivotroot(struct aa_label *label, struct path *old_path,
struct path *new_path);
#endif /* __AA_MOUNT_H */
/*
* AppArmor security module
*
* This file contains AppArmor network mediation definitions.
*
* Copyright (C) 1998-2008 Novell/SUSE
* Copyright 2009-2014 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_NET_H
#define __AA_NET_H
#include <net/sock.h>
#include "apparmorfs.h"
#include "label.h"
#include "perms.h"
#include "policy.h"
#define AA_MAY_SEND AA_MAY_WRITE
#define AA_MAY_RECEIVE AA_MAY_READ
#define AA_MAY_SHUTDOWN AA_MAY_DELETE
#define AA_MAY_CONNECT AA_MAY_OPEN
#define AA_MAY_ACCEPT 0x00100000
#define AA_MAY_BIND 0x00200000
#define AA_MAY_LISTEN 0x00400000
#define AA_MAY_SETOPT 0x01000000
#define AA_MAY_GETOPT 0x02000000
#define NET_PERMS_MASK (AA_MAY_SEND | AA_MAY_RECEIVE | AA_MAY_CREATE | \
AA_MAY_SHUTDOWN | AA_MAY_BIND | AA_MAY_LISTEN | \
AA_MAY_CONNECT | AA_MAY_ACCEPT | AA_MAY_SETATTR | \
AA_MAY_GETATTR | AA_MAY_SETOPT | AA_MAY_GETOPT)
#define NET_FS_PERMS (AA_MAY_SEND | AA_MAY_RECEIVE | AA_MAY_CREATE | \
AA_MAY_SHUTDOWN | AA_MAY_CONNECT | AA_MAY_RENAME |\
AA_MAY_SETATTR | AA_MAY_GETATTR | AA_MAY_CHMOD | \
AA_MAY_CHOWN | AA_MAY_CHGRP | AA_MAY_LOCK | \
AA_MAY_MPROT)
#define NET_PEER_MASK (AA_MAY_SEND | AA_MAY_RECEIVE | AA_MAY_CONNECT | \
AA_MAY_ACCEPT)
struct aa_sk_cxt {
struct aa_label *label;
struct aa_label *peer;
};
#define SK_CXT(X) (X)->sk_security
#define SOCK_CXT(X) SOCK_INODE(X)->i_security
#define DEFINE_AUDIT_NET(NAME, OP, SK, F, T, P) \
struct lsm_network_audit NAME ## _net = { .sk = (SK), \
.family = (F)}; \
DEFINE_AUDIT_DATA(NAME, \
(SK) ? LSM_AUDIT_DATA_NET : LSM_AUDIT_DATA_NONE,\
OP); \
NAME.u.net = &(NAME ## _net); \
aad(&NAME)->net.type = (T); \
aad(&NAME)->net.protocol = (P)
/* struct aa_net - network confinement data
* @allowed: basic network families permissions
* @audit_network: which network permissions to force audit
* @quiet_network: which network permissions to quiet rejects
*/
struct aa_net {
u16 allow[AF_MAX];
u16 audit[AF_MAX];
u16 quiet[AF_MAX];
};
extern struct aa_fs_entry aa_fs_entry_network[];
void audit_net_cb(struct audit_buffer *ab, void *va);
int aa_profile_af_perm(struct aa_profile *profile, int op, u16 family,
int type, int protocol, struct sock *sk);
int aa_af_perm(struct aa_label *label, int op, u32 request, u16 family,
int type, int protocol, struct sock *sk);
int aa_sock_perm(int op, u32 request, struct socket *sock);
int aa_sock_create_perm(struct aa_label *label, int family, int type,
int protocol);
int aa_sock_bind_perm(struct socket *sock, struct sockaddr *address,
int addrlen);
int aa_sock_connect_perm(struct socket *sock, struct sockaddr *address,
int addrlen);
int aa_sock_listen_perm(struct socket *sock, int backlog);
int aa_sock_accept_perm(struct socket *sock, struct socket *newsock);
int aa_sock_msg_perm(int op, u32 request, struct socket *sock,
struct msghdr *msg, int size);
int aa_sock_opt_perm(int op, u32 request, struct socket *sock, int level,
int optname);
int aa_sock_file_perm(struct aa_label *label, int op, u32 request,
struct socket *sock);
static inline void aa_free_net_rules(struct aa_net *new)
{
/* NOP */
}
#endif /* __AA_NET_H */
......@@ -18,15 +18,72 @@
enum path_flags {
PATH_IS_DIR = 0x1, /* path is a directory */
PATH_SOCK_COND = 0x2,
PATH_CONNECT_PATH = 0x4, /* connect disconnected paths to / */
PATH_CHROOT_REL = 0x8, /* do path lookup relative to chroot */
PATH_CHROOT_NSCONNECT = 0x10, /* connect paths that are at ns root */
PATH_DELEGATE_DELETED = 0x08000, /* delegate deleted files */
PATH_MEDIATE_DELETED = 0x10000, /* mediate deleted paths */
PATH_MEDIATE_DELETED = 0x10000, /* mediate deleted paths */
};
int aa_path_name(struct path *path, int flags, char **buffer,
const char **name, const char **info);
int aa_path_name(struct path *path, int flags, char *buffer,
const char **name, const char **info, const char *disconnect);
#define MAX_PATH_BUFFERS 2
/* Per cpu buffers used during mediation */
/* preallocated buffers to use during path lookups */
struct aa_buffers {
char *buf[MAX_PATH_BUFFERS];
};
#include <linux/percpu.h>
#include <linux/preempt.h>
DECLARE_PER_CPU(struct aa_buffers, aa_buffers);
#define COUNT_ARGS(X...) COUNT_ARGS_HELPER ( , ##X ,9,8,7,6,5,4,3,2,1,0)
#define COUNT_ARGS_HELPER(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,n,X...) n
#define CONCAT(X, Y) X ## Y
#define CONCAT_AFTER(X, Y) CONCAT(X, Y)
#define ASSIGN(FN, X, N) do { (X) = FN(N); } while (0)
#define EVAL1(FN, X) ASSIGN(FN, X, 0) /*X = FN(0)*/
#define EVAL2(FN, X, Y...) ASSIGN(FN, X, 1); /*X = FN(1);*/ EVAL1(FN, Y)
#define EVAL(FN, X...) CONCAT_AFTER(EVAL, COUNT_ARGS(X))(FN, X)
#define for_each_cpu_buffer(I) for ((I) = 0; (I) < MAX_PATH_BUFFERS; (I)++)
#ifdef CONFIG_DEBUG_PREEMPT
#define AA_BUG_PREEMPT_ENABLED(X) AA_BUG(preempt_count() <= 0, X)
#else
#define AA_BUG_PREEMPT_ENABLED(X) /* nop */
#endif
#define __get_buffer(N) ({ \
struct aa_buffers *__cpu_var; \
AA_BUG_PREEMPT_ENABLED("__get_buffer without preempt disabled"); \
__cpu_var = &__get_cpu_var(aa_buffers); \
__cpu_var->buf[(N)]; })
#define __get_buffers(X...) \
do { \
EVAL(__get_buffer, X); \
} while (0)
#define __put_buffers(X, Y...) (void)&(X)
#define get_buffers(X...) \
do { \
preempt_disable(); \
__get_buffers(X); \
} while (0)
#define put_buffers(X, Y...) \
do { \
__put_buffers(X, Y); \
preempt_enable(); \
} while (0)
#endif /* __AA_PATH_H */
/*
* AppArmor security module
*
* This file contains AppArmor basic permission sets definitions.
*
* Copyright 2013 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_PERM_H
#define __AA_PERM_H
#include <linux/fs.h>
#include "label.h"
#define AA_MAY_EXEC MAY_EXEC
#define AA_MAY_WRITE MAY_WRITE
#define AA_MAY_READ MAY_READ
#define AA_MAY_APPEND MAY_APPEND
#define AA_MAY_CREATE 0x0010
#define AA_MAY_DELETE 0x0020
#define AA_MAY_OPEN 0x0040
#define AA_MAY_RENAME 0x0080 /* pair */
#define AA_MAY_SETATTR 0x0100 /* meta write */
#define AA_MAY_GETATTR 0x0200 /* meta read */
#define AA_MAY_SETCRED 0x0400 /* security cred/attr */
#define AA_MAY_GETCRED 0x0800
#define AA_MAY_CHMOD 0x1000 /* pair */
#define AA_MAY_CHOWN 0x2000 /* pair */
#define AA_MAY_CHGRP 0x4000 /* pair */
#define AA_MAY_LOCK 0x8000 /* LINK_SUBSET overlaid */
#define AA_EXEC_MMAP 0x00010000
#define AA_MAY_MPROT 0x00020000 /* extend conditions */
#define AA_MAY_LINK 0x00040000 /* pair */
#define AA_MAY_SNAPSHOT 0x00080000 /* pair */
#define AA_MAY_DELEGATE
#define AA_CONT_MATCH 0x08000000
#define AA_MAY_STACK 0x10000000
#define AA_MAY_ONEXEC 0x20000000 /* either stack or change_profile */
#define AA_MAY_CHANGE_PROFILE 0x40000000
#define AA_MAY_CHANGEHAT 0x80000000
#define AA_LINK_SUBSET AA_MAY_LOCK /* overlaid */
#define PERMS_CHRS_MASK (MAY_READ | MAY_WRITE | AA_MAY_CREATE | \
AA_MAY_DELETE | AA_MAY_LINK | AA_MAY_LOCK | \
AA_MAY_EXEC | AA_EXEC_MMAP | AA_MAY_APPEND)
#define PERMS_NAMES_MASK (PERMS_CHRS_MASK | AA_MAY_OPEN | AA_MAY_RENAME | \
AA_MAY_SETATTR | AA_MAY_GETATTR | AA_MAY_SETCRED | \
AA_MAY_GETCRED | AA_MAY_CHMOD | AA_MAY_CHOWN | \
AA_MAY_CHGRP | AA_MAY_MPROT | AA_MAY_SNAPSHOT | \
AA_MAY_STACK | AA_MAY_ONEXEC | \
AA_MAY_CHANGE_PROFILE | AA_MAY_CHANGEHAT)
extern const char aa_file_perm_chrs[];
extern const char *aa_file_perm_names[];
struct aa_perms {
u32 allow;
u32 audit; /* set only when allow is set */
u32 deny; /* explicit deny, or conflict if allow also set */
u32 quiet; /* set only when ~allow | deny */
u32 kill; /* set only when ~allow | deny */
u32 stop; /* set only when ~allow | deny */
u32 complain; /* accumulates only used when ~allow & ~deny */
u32 cond; /* set only when ~allow and ~deny */
u32 hide; /* set only when ~allow | deny */
u32 prompt; /* accumulates only used when ~allow & ~deny */
/* Reserved:
* u32 subtree; / * set only when allow is set * /
*/
};
#define ALL_PERMS_MASK 0xffffffff
#define aa_perms_clear(X) memset((X), 0, sizeof(*(X)));
#define aa_perms_all(X) \
do { \
aa_perms_clear(X); \
(X)->allow = ALL_PERMS_MASK; \
/* the following are only used for denials */ \
(X)->quiet = ALL_PERMS_MASK; \
(X)->hide = ALL_PERMS_MASK; \
} while (0)
#define xcheck(FN1, FN2) \
({ \
int e, error = FN1; \
e = FN2; \
if (e) \
error = e; \
error; \
})
/* TODO: update for labels pointing to labels instead of profiles
* Note: this only works for profiles from a single namespace
*/
#define xcheck_profile_label(P, L, FN, args...) \
({ \
struct aa_profile *__p2; \
fn_for_each((L), __p2, FN((P), __p2, args)); \
})
#define xcheck_ns_labels(L1, L2, FN, args...) \
({ \
struct aa_profile *__p1; \
fn_for_each((L1), __p1, FN(__p1, (L2), args)); \
})
/* todo: fix to handle multiple namespaces */
#define xcheck_labels(L1, L2, FN, args...) \
xcheck_ns_labels((L1), (L2), FN, args)
/* Do the cross check but applying FN at the profiles level */
#define xcheck_labels_profiles(L1, L2, FN, args...) \
xcheck_ns_labels((L1), (L2), xcheck_profile_label, (FN), args)
#define FINAL_CHECK true
void aa_perm_mask_to_str(char *str, const char *chrs, u32 mask);
void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask);
void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
u32 chrsmask, const char **names, u32 namesmask);
void aa_apply_modes_to_perms(struct aa_profile *profile,
struct aa_perms *perms);
void aa_compute_perms(struct aa_dfa *dfa, unsigned int state,
struct aa_perms *perms);
void aa_perms_accum(struct aa_perms *accum, struct aa_perms *addend);
void aa_perms_accum_raw(struct aa_perms *accum, struct aa_perms *addend);
void aa_profile_match_label(struct aa_profile *profile, const char *label,
int type, struct aa_perms *perms);
int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target,
u32 request, int type, u32 *deny,
struct common_audit_data *sa);
int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms,
u32 request, struct common_audit_data *sa,
void (*cb) (struct audit_buffer *, void *));
const char *aa_peer_name(struct aa_profile *peer);
static inline int aa_xlabel_perm(struct aa_profile *profile,
struct aa_profile *target,
int type, u32 request, u32 reverse,
u32 * deny, struct common_audit_data *sa)
{
/* TODO: ??? 2nd aa_profile_label_perm needs to reverse perms */
return xcheck(aa_profile_label_perm(profile, target, request, type,
deny, sa),
aa_profile_label_perm(target, profile, request /*??*/, type,
deny, sa));
}
#endif /* __AA_PERM_H */
This diff is collapsed.
......@@ -18,7 +18,7 @@
#define AA_DO_TEST 1
#define AA_ONEXEC 1
int aa_getprocattr(struct aa_profile *profile, char **string);
int aa_getprocattr(struct aa_label *label, char **string);
int aa_setprocattr_changehat(char *args, size_t size, int test);
int aa_setprocattr_changeprofile(char *fqname, bool onexec, int test);
......
......@@ -37,10 +37,10 @@ struct aa_rlimit {
extern struct aa_fs_entry aa_fs_entry_rlimit[];
int aa_map_resource(int resource);
int aa_task_setrlimit(struct aa_profile *profile, struct task_struct *,
int aa_task_setrlimit(struct aa_label *label, struct task_struct *,
unsigned int resource, struct rlimit *new_rlim);
void __aa_transition_rlimits(struct aa_profile *old, struct aa_profile *new);
void __aa_transition_rlimits(struct aa_label *old, struct aa_label *new);
static inline void aa_free_rlimit_rules(struct aa_rlimit *rlims)
{
......
#include <linux/signal.h>
#define SIGUNKNOWN 0
#define MAXMAPPED_SIG 35
/* provide a mapping of arch signal to internal signal # for mediation
* those that are always an alias SIGCLD for SIGCLHD and SIGPOLL for SIGIO
* map to the same entry those that may/or may not get a separate entry
*/
static const int sig_map[MAXMAPPED_SIG] = {
[0] = MAXMAPPED_SIG, /* existance test */
[SIGHUP] = 1,
[SIGINT] = 2,
[SIGQUIT] = 3,
[SIGILL] = 4,
[SIGTRAP] = 5, /* -, 5, - */
[SIGABRT] = 6, /* SIGIOT: -, 6, - */
[SIGBUS] = 7, /* 10, 7, 10 */
[SIGFPE] = 8,
[SIGKILL] = 9,
[SIGUSR1] = 10, /* 30, 10, 16 */
[SIGSEGV] = 11,
[SIGUSR2] = 12, /* 31, 12, 17 */
[SIGPIPE] = 13,
[SIGALRM] = 14,
[SIGTERM] = 15,
[SIGSTKFLT] = 16, /* -, 16, - */
[SIGCHLD] = 17, /* 20, 17, 18. SIGCHLD -, -, 18 */
[SIGCONT] = 18, /* 19, 18, 25 */
[SIGSTOP] = 19, /* 17, 19, 23 */
[SIGTSTP] = 20, /* 18, 20, 24 */
[SIGTTIN] = 21, /* 21, 21, 26 */
[SIGTTOU] = 22, /* 22, 22, 27 */
[SIGURG] = 23, /* 16, 23, 21 */
[SIGXCPU] = 24, /* 24, 24, 30 */
[SIGXFSZ] = 25, /* 25, 25, 31 */
[SIGVTALRM] = 26, /* 26, 26, 28 */
[SIGPROF] = 27, /* 27, 27, 29 */
[SIGWINCH] = 28, /* 28, 28, 20 */
[SIGIO] = 29, /* SIGPOLL: 23, 29, 22 */
[SIGPWR] = 30, /* 29, 30, 19. SIGINFO 29, -, - */
#ifdef SIGSYS
[SIGSYS] = 31, /* 12, 31, 12. often SIG LOST/UNUSED */
#endif
#ifdef SIGEMT
[SIGEMT] = 32, /* 7, - , 7 */
#endif
#if defined(SIGLOST) && SIGPWR != SIGLOST /* sparc */
[SIGLOST] = 33, /* unused on Linux */
#endif
#if defined(SIGLOST) && defined(SIGSYS) && SIGLOST != SIGSYS
[SIGUNUSED] = 34, /* -, 31, - */
#endif
};
/* this table is ordered post sig_map[sig] mapping */
static const char *const sig_names[MAXMAPPED_SIG + 1] = {
"unknown",
"hup",
"int",
"quit",
"ill",
"trap",
"abrt",
"bus",
"fpe",
"kill",
"usr1",
"segv",
"usr2",
"pipe",
"alrm",
"term",
"stkflt",
"chld",
"cont",
"stop",
"stp",
"ttin",
"ttou",
"urg",
"xcpu",
"xfsz",
"vtalrm",
"prof",
"winch",
"io",
"pwr",
"sys",
"emt",
"lost",
"unused",
"exists", /* always last existance test mapped to MAXMAPPED_SIG */
};
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -33,50 +33,29 @@
*
* Returns: size of string placed in @string else error code on failure
*/
int aa_getprocattr(struct aa_profile *profile, char **string)
int aa_getprocattr(struct aa_label *label, char **string)
{
char *str;
int len = 0, mode_len = 0, ns_len = 0, name_len;
const char *mode_str = aa_profile_mode_names[profile->mode];
const char *ns_name = NULL;
struct aa_namespace *ns = profile->ns;
struct aa_namespace *current_ns = __aa_current_profile()->ns;
char *s;
struct aa_namespace *ns = labels_ns(label);
struct aa_namespace *current_ns = labels_ns(aa_current_label());
int len;
if (!aa_ns_visible(current_ns, ns))
return -EACCES;
ns_name = aa_ns_name(current_ns, ns);
ns_len = strlen(ns_name);
len = aa_label_snprint(NULL, 0, current_ns, label, true);
AA_BUG(len < 0);
/* if the visible ns_name is > 0 increase size for : :// seperator */
if (ns_len)
ns_len += 4;
/* unconfined profiles don't have a mode string appended */
if (!unconfined(profile))
mode_len = strlen(mode_str) + 3; /* + 3 for _() */
name_len = strlen(profile->base.hname);
len = mode_len + ns_len + name_len + 1; /* + 1 for \n */
s = str = kmalloc(len + 1, GFP_KERNEL); /* + 1 \0 */
if (!str)
*string = kmalloc(len + 2, GFP_KERNEL);
if (!*string)
return -ENOMEM;
if (ns_len) {
/* skip over prefix current_ns->base.hname and separating // */
sprintf(s, ":%s://", ns_name);
s += ns_len;
}
if (unconfined(profile))
/* mode string not being appended */
sprintf(s, "%s\n", profile->base.hname);
else
sprintf(s, "%s (%s)\n", profile->base.hname, mode_str);
*string = str;
/* NOTE: len does not include \0 of string, not saved as part of file */
return len;
len = aa_label_snprint(*string, len + 2, current_ns, label, true);
if (len < 0)
return len;
(*string)[len] = '\n';
(*string)[len + 1] = 0;
return len + 1;
}
/**
......@@ -138,12 +117,13 @@ int aa_setprocattr_changehat(char *args, size_t size, int test)
for (count = 0; (hat < end) && count < 16; ++count) {
char *next = hat + strlen(hat) + 1;
hats[count] = hat;
AA_DEBUG("%s: (pid %d) Magic 0x%llx count %d hat '%s'\n"
, __func__, current->pid, token, count, hat);
hat = next;
}
}
AA_DEBUG("%s: Magic 0x%llx Hat '%s'\n",
__func__, token, hat ? hat : NULL);
} else
AA_DEBUG("%s: (pid %d) Magic 0x%llx count %d Hat '%s'\n",
__func__, current->pid, token, count, "<NULL>");
return aa_change_hat(hats, count, token, test);
}
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment