diff options
author | James Morris <james.l.morris@oracle.com> | 2013-05-12 21:28:38 +1000 |
---|---|---|
committer | James Morris <james.l.morris@oracle.com> | 2013-05-12 21:28:38 +1000 |
commit | bd71164abc141ea696014e3e23c561b0d7f1b434 (patch) | |
tree | 3b9c64698800566197bf4ecec604ba8bb1228bd3 /security | |
parent | f722406faae2d073cc1d01063d1123c35425939e (diff) | |
parent | 2654bfbc2bd0e1e64f0b257c21da23f6cec32c6c (diff) |
Merge tag 'aa-3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor into ra-next
Diffstat (limited to 'security')
-rw-r--r-- | security/apparmor/audit.c | 2 | ||||
-rw-r--r-- | security/apparmor/context.c | 44 | ||||
-rw-r--r-- | security/apparmor/domain.c | 26 | ||||
-rw-r--r-- | security/apparmor/include/apparmor.h | 12 | ||||
-rw-r--r-- | security/apparmor/include/context.h | 61 | ||||
-rw-r--r-- | security/apparmor/include/file.h | 14 | ||||
-rw-r--r-- | security/apparmor/include/match.h | 21 | ||||
-rw-r--r-- | security/apparmor/include/policy.h | 16 | ||||
-rw-r--r-- | security/apparmor/include/procattr.h | 1 | ||||
-rw-r--r-- | security/apparmor/include/sid.h | 4 | ||||
-rw-r--r-- | security/apparmor/ipc.c | 13 | ||||
-rw-r--r-- | security/apparmor/lib.c | 20 | ||||
-rw-r--r-- | security/apparmor/lsm.c | 69 | ||||
-rw-r--r-- | security/apparmor/match.c | 23 | ||||
-rw-r--r-- | security/apparmor/path.c | 2 | ||||
-rw-r--r-- | security/apparmor/policy.c | 181 | ||||
-rw-r--r-- | security/apparmor/policy_unpack.c | 4 | ||||
-rw-r--r-- | security/apparmor/procattr.c | 6 | ||||
-rw-r--r-- | security/apparmor/resource.c | 15 |
19 files changed, 286 insertions, 248 deletions
diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c index 3ae28db5a64..031d2d9dd69 100644 --- a/security/apparmor/audit.c +++ b/security/apparmor/audit.c @@ -88,7 +88,7 @@ static const char *const aa_audit_type[] = { "HINT", "STATUS", "ERROR", - "KILLED" + "KILLED", "AUTO" }; diff --git a/security/apparmor/context.c b/security/apparmor/context.c index 8a9b5027c81..d5af1d15f26 100644 --- a/security/apparmor/context.c +++ b/security/apparmor/context.c @@ -69,6 +69,23 @@ void aa_dup_task_context(struct aa_task_cxt *new, const struct aa_task_cxt *old) } /** + * aa_get_task_profile - Get another task's profile + * @task: task to query (NOT NULL) + * + * Returns: counted reference to @task's profile + */ +struct aa_profile *aa_get_task_profile(struct task_struct *task) +{ + struct aa_profile *p; + + rcu_read_lock(); + p = aa_get_profile(__aa_task_profile(task)); + rcu_read_unlock(); + + return p; +} + +/** * aa_replace_current_profile - replace the current tasks profiles * @profile: new profile (NOT NULL) * @@ -76,7 +93,7 @@ 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) { - struct aa_task_cxt *cxt = current_cred()->security; + struct aa_task_cxt *cxt = current_cxt(); struct cred *new; BUG_ON(!profile); @@ -87,17 +104,13 @@ int aa_replace_current_profile(struct aa_profile *profile) if (!new) return -ENOMEM; - cxt = new->security; - if (unconfined(profile) || (cxt->profile->ns != profile->ns)) { + cxt = cred_cxt(new); + if (unconfined(profile) || (cxt->profile->ns != profile->ns)) /* if switching to unconfined or a different profile namespace * clear out context state */ - aa_put_profile(cxt->previous); - aa_put_profile(cxt->onexec); - cxt->previous = NULL; - cxt->onexec = NULL; - cxt->token = 0; - } + aa_clear_task_cxt_trans(cxt); + /* be careful switching cxt->profile, when racing replacement it * is possible that cxt->profile->replacedby is the reference keeping * @profile valid, so make sure to get its reference before dropping @@ -123,7 +136,7 @@ int aa_set_current_onexec(struct aa_profile *profile) if (!new) return -ENOMEM; - cxt = new->security; + cxt = cred_cxt(new); aa_get_profile(profile); aa_put_profile(cxt->onexec); cxt->onexec = profile; @@ -150,7 +163,7 @@ int aa_set_current_hat(struct aa_profile *profile, u64 token) return -ENOMEM; BUG_ON(!profile); - cxt = new->security; + cxt = cred_cxt(new); if (!cxt->previous) { /* transfer refcount */ cxt->previous = cxt->profile; @@ -187,7 +200,7 @@ int aa_restore_previous_profile(u64 token) if (!new) return -ENOMEM; - cxt = new->security; + cxt = cred_cxt(new); if (cxt->token != token) { abort_creds(new); return -EACCES; @@ -205,11 +218,10 @@ int aa_restore_previous_profile(u64 token) aa_get_profile(cxt->profile); aa_put_profile(cxt->previous); } - /* clear exec && prev information when restoring to previous context */ + /* ref has been transfered so avoid putting ref in clear_task_cxt */ cxt->previous = NULL; - cxt->token = 0; - aa_put_profile(cxt->onexec); - cxt->onexec = NULL; + /* clear exec && prev information when restoring to previous context */ + aa_clear_task_cxt_trans(cxt); commit_creds(new); return 0; diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 859abdaac1e..01b7bd669a8 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -62,17 +62,14 @@ static int may_change_ptraced_domain(struct task_struct *task, struct aa_profile *to_profile) { struct task_struct *tracer; - const struct cred *cred = NULL; struct aa_profile *tracerp = NULL; int error = 0; rcu_read_lock(); tracer = ptrace_parent(task); - if (tracer) { + if (tracer) /* released below */ - cred = get_task_cred(tracer); - tracerp = aa_cred_profile(cred); - } + tracerp = aa_get_task_profile(tracer); /* not ptraced */ if (!tracer || unconfined(tracerp)) @@ -82,8 +79,7 @@ static int may_change_ptraced_domain(struct task_struct *task, out: rcu_read_unlock(); - if (cred) - put_cred(cred); + aa_put_profile(tracerp); return error; } @@ -360,7 +356,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) if (bprm->cred_prepared) return 0; - cxt = bprm->cred->security; + cxt = cred_cxt(bprm->cred); BUG_ON(!cxt); profile = aa_get_profile(aa_newest_version(cxt->profile)); @@ -443,6 +439,8 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) } else { error = -ENOENT; info = "profile not found"; + /* remove MAY_EXEC to audit as failure */ + perms.allow &= ~MAY_EXEC; } } } else if (COMPLAIN_MODE(profile)) { @@ -514,11 +512,7 @@ x_clear: cxt->profile = new_profile; /* clear out all temporary/transitional state from the context */ - aa_put_profile(cxt->previous); - aa_put_profile(cxt->onexec); - cxt->previous = NULL; - cxt->onexec = NULL; - cxt->token = 0; + aa_clear_task_cxt_trans(cxt); audit: error = aa_audit_file(profile, &perms, GFP_KERNEL, OP_EXEC, MAY_EXEC, @@ -557,7 +551,7 @@ int apparmor_bprm_secureexec(struct linux_binprm *bprm) void apparmor_bprm_committing_creds(struct linux_binprm *bprm) { struct aa_profile *profile = __aa_current_profile(); - struct aa_task_cxt *new_cxt = bprm->cred->security; + struct aa_task_cxt *new_cxt = cred_cxt(bprm->cred); /* bail out if unconfined or not changing profile */ if ((new_cxt->profile == profile) || @@ -634,7 +628,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest) /* released below */ cred = get_current_cred(); - cxt = cred->security; + cxt = cred_cxt(cred); profile = aa_cred_profile(cred); previous_profile = cxt->previous; @@ -750,7 +744,6 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, bool permtest) { const struct cred *cred; - struct aa_task_cxt *cxt; struct aa_profile *profile, *target = NULL; struct aa_namespace *ns = NULL; struct file_perms perms = {}; @@ -770,7 +763,6 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, } cred = get_current_cred(); - cxt = cred->security; profile = aa_cred_profile(cred); /* diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h index 40aedd9f73e..1ba2ca56a6e 100644 --- a/security/apparmor/include/apparmor.h +++ b/security/apparmor/include/apparmor.h @@ -15,6 +15,7 @@ #ifndef __APPARMOR_H #define __APPARMOR_H +#include <linux/slab.h> #include <linux/fs.h> #include "match.h" @@ -64,9 +65,18 @@ extern int apparmor_initialized __initdata; /* fn's in lib */ char *aa_split_fqname(char *args, char **ns_name); void aa_info_message(const char *str); -void *kvmalloc(size_t size); +void *__aa_kvmalloc(size_t size, gfp_t flags); void kvfree(void *buffer); +static inline void *kvmalloc(size_t size) +{ + return __aa_kvmalloc(size, 0); +} + +static inline void *kvzalloc(size_t size) +{ + return __aa_kvmalloc(size, __GFP_ZERO); +} /** * aa_strneq - compare null terminated @str to a non null terminated substring diff --git a/security/apparmor/include/context.h b/security/apparmor/include/context.h index a9cbee4d9e4..d44ba5802e3 100644 --- a/security/apparmor/include/context.h +++ b/security/apparmor/include/context.h @@ -21,6 +21,9 @@ #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 * @@ -80,23 +83,8 @@ 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); -/** - * __aa_task_is_confined - determine if @task has any confinement - * @task: task to check confinement of (NOT NULL) - * - * If @task != current needs to be called in RCU safe critical section - */ -static inline bool __aa_task_is_confined(struct task_struct *task) -{ - struct aa_task_cxt *cxt = __task_cred(task)->security; - - BUG_ON(!cxt || !cxt->profile); - if (unconfined(aa_newest_version(cxt->profile))) - return 0; - - return 1; -} /** * aa_cred_profile - obtain cred's profiles @@ -108,12 +96,36 @@ static inline bool __aa_task_is_confined(struct task_struct *task) */ static inline struct aa_profile *aa_cred_profile(const struct cred *cred) { - struct aa_task_cxt *cxt = cred->security; + struct aa_task_cxt *cxt = cred_cxt(cred); BUG_ON(!cxt || !cxt->profile); return aa_newest_version(cxt->profile); } /** + * __aa_task_profile - retrieve another task's profile + * @task: task to query (NOT NULL) + * + * Returns: @task's profile 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) +{ + return aa_cred_profile(__task_cred(task)); +} + +/** + * __aa_task_is_confined - determine if @task has any confinement + * @task: task to check confinement of (NOT NULL) + * + * If @task != current needs to be called in RCU safe critical section + */ +static inline bool __aa_task_is_confined(struct task_struct *task) +{ + return !unconfined(__aa_task_profile(task)); +} + +/** * __aa_current_profile - find the current tasks confining profile * * Returns: up to date confining profile or the ns unconfined profile (NOT NULL) @@ -136,7 +148,7 @@ static inline struct aa_profile *__aa_current_profile(void) */ static inline struct aa_profile *aa_current_profile(void) { - const struct aa_task_cxt *cxt = current_cred()->security; + const struct aa_task_cxt *cxt = current_cxt(); struct aa_profile *profile; BUG_ON(!cxt || !cxt->profile); @@ -151,4 +163,17 @@ static inline struct aa_profile *aa_current_profile(void) return profile; } +/** + * aa_clear_task_cxt_trans - clear transition tracking info from the cxt + * @cxt: task context to clear (NOT NULL) + */ +static inline void aa_clear_task_cxt_trans(struct aa_task_cxt *cxt) +{ + aa_put_profile(cxt->previous); + aa_put_profile(cxt->onexec); + cxt->previous = NULL; + cxt->onexec = NULL; + cxt->token = 0; +} + #endif /* __AA_CONTEXT_H */ diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h index 967b2deda37..2c922b86bd4 100644 --- a/security/apparmor/include/file.h +++ b/security/apparmor/include/file.h @@ -186,11 +186,6 @@ static inline void aa_free_file_rules(struct aa_file_rules *rules) aa_free_domain_entries(&rules->trans); } -#define ACC_FMODE(x) (("\000\004\002\006"[(x)&O_ACCMODE]) | (((x) << 1) & 0x40)) - -/* from namei.c */ -#define MAP_OPEN_FLAGS(x) ((((x) + 1) & O_ACCMODE) ? (x) + 1 : (x)) - /** * aa_map_file_perms - map file flags to AppArmor permissions * @file: open file to map flags to AppArmor permissions @@ -199,8 +194,13 @@ static inline void aa_free_file_rules(struct aa_file_rules *rules) */ static inline u32 aa_map_file_to_perms(struct file *file) { - int flags = MAP_OPEN_FLAGS(file->f_flags); - u32 perms = ACC_FMODE(file->f_mode); + int flags = file->f_flags; + u32 perms = 0; + + if (file->f_mode & FMODE_WRITE) + perms |= MAY_WRITE; + if (file->f_mode & FMODE_READ) + perms |= MAY_READ; if ((flags & O_APPEND) && (perms & MAY_WRITE)) perms = (perms & ~MAY_WRITE) | MAY_APPEND; diff --git a/security/apparmor/include/match.h b/security/apparmor/include/match.h index 775843e7f98..001c43aa040 100644 --- a/security/apparmor/include/match.h +++ b/security/apparmor/include/match.h @@ -4,7 +4,7 @@ * This file contains AppArmor policy dfa matching engine definitions. * * Copyright (C) 1998-2008 Novell/SUSE - * Copyright 2009-2010 Canonical Ltd. + * Copyright 2009-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 @@ -16,25 +16,30 @@ #define __AA_MATCH_H #include <linux/kref.h> -#include <linux/workqueue.h> #define DFA_NOMATCH 0 #define DFA_START 1 -#define DFA_VALID_PERM_MASK 0xffffffff -#define DFA_VALID_PERM2_MASK 0xffffffff /** * The format used for transition tables is based on the GNU flex table * file format (--tables-file option; see Table File Format in the flex * info pages and the flex sources for documentation). The magic number * used in the header is 0x1B5E783D instead of 0xF13C57B1 though, because - * the YY_ID_CHK (check) and YY_ID_DEF (default) tables are used - * slightly differently (see the apparmor-parser package). + * new tables have been defined and others YY_ID_CHK (check) and YY_ID_DEF + * (default) tables are used slightly differently (see the apparmor-parser + * package). + * + * + * The data in the packed dfa is stored in network byte order, and the tables + * are arranged for flexibility. We convert the table data to host native + * byte order. + * + * The dfa begins with a table set header, and is followed by the actual + * tables. */ #define YYTH_MAGIC 0x1B5E783D -#define YYTH_DEF_RECURSE 0x1 /* DEF Table is recursive */ struct table_set_header { u32 th_magic; /* YYTH_MAGIC */ @@ -63,7 +68,7 @@ struct table_set_header { #define YYTD_DATA32 4 #define YYTD_DATA64 8 -/* Each ACCEPT2 table gets 6 dedicated flags, YYTD_DATAX define the +/* ACCEPT & ACCEPT2 tables gets 6 dedicated flags, YYTD_DATAX define the * first flags */ #define ACCEPT1_FLAGS(X) ((X) & 0x3f) diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index bda4569fdd8..b25491a3046 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -32,13 +32,13 @@ extern const char *const profile_mode_names[]; #define APPARMOR_NAMES_MAX_INDEX 3 -#define COMPLAIN_MODE(_profile) \ - ((aa_g_profile_mode == APPARMOR_COMPLAIN) || \ - ((_profile)->mode == APPARMOR_COMPLAIN)) +#define PROFILE_MODE(_profile, _mode) \ + ((aa_g_profile_mode == (_mode)) || \ + ((_profile)->mode == (_mode))) -#define KILL_MODE(_profile) \ - ((aa_g_profile_mode == APPARMOR_KILL) || \ - ((_profile)->mode == APPARMOR_KILL)) +#define COMPLAIN_MODE(_profile) PROFILE_MODE((_profile), APPARMOR_COMPLAIN) + +#define KILL_MODE(_profile) PROFILE_MODE((_profile), APPARMOR_KILL) #define PROFILE_IS_HAT(_profile) ((_profile)->flags & PFLAG_HAT) @@ -105,6 +105,7 @@ struct aa_ns_acct { * @acct: accounting for the namespace * @unconfined: special unconfined profile for the namespace * @sub_ns: list of namespaces under the current namespace. + * @uniq_null: uniq value used for null learning profiles * * An aa_namespace defines the set profiles that are searched to determine * which profile to attach to a task. Profiles can not be shared between @@ -127,6 +128,7 @@ struct aa_namespace { struct aa_ns_acct acct; struct aa_profile *unconfined; struct list_head sub_ns; + atomic_t uniq_null; }; /* struct aa_policydb - match engine for a policy @@ -148,7 +150,6 @@ struct aa_policydb { * @rename: optional profile name that this profile renamed * @xmatch: optional extended matching for unconfined executables names * @xmatch_len: xmatch prefix len, used to determine xmatch priority - * @sid: the unique security id number of this profile * @audit: the auditing mode of the profile * @mode: the enforcement mode of the profile * @flags: flags controlling profile behavior @@ -184,7 +185,6 @@ struct aa_profile { struct aa_dfa *xmatch; int xmatch_len; - u32 sid; enum audit_mode audit; enum profile_mode mode; u32 flags; diff --git a/security/apparmor/include/procattr.h b/security/apparmor/include/procattr.h index 544aa6b766a..6bd5f33d953 100644 --- a/security/apparmor/include/procattr.h +++ b/security/apparmor/include/procattr.h @@ -21,6 +21,5 @@ int aa_getprocattr(struct aa_profile *profile, char **string); int aa_setprocattr_changehat(char *args, size_t size, int test); int aa_setprocattr_changeprofile(char *fqname, bool onexec, int test); -int aa_setprocattr_permipc(char *fqname); #endif /* __AA_PROCATTR_H */ diff --git a/security/apparmor/include/sid.h b/security/apparmor/include/sid.h index 020db35c301..513ca0e4896 100644 --- a/security/apparmor/include/sid.h +++ b/security/apparmor/include/sid.h @@ -16,7 +16,9 @@ #include <linux/types.h> -struct aa_profile; +/* sid value that will not be allocated */ +#define AA_SID_INVALID 0 +#define AA_SID_ALLOC AA_SID_INVALID u32 aa_alloc_sid(void); void aa_free_sid(u32 sid); diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c index cf1071b1423..c51d2266587 100644 --- a/security/apparmor/ipc.c +++ b/security/apparmor/ipc.c @@ -95,23 +95,18 @@ int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee, * - tracer profile has CAP_SYS_PTRACE */ - struct aa_profile *tracer_p; - /* cred released below */ - const struct cred *cred = get_task_cred(tracer); + struct aa_profile *tracer_p = aa_get_task_profile(tracer); int error = 0; - tracer_p = aa_cred_profile(cred); if (!unconfined(tracer_p)) { - /* lcred released below */ - const struct cred *lcred = get_task_cred(tracee); - struct aa_profile *tracee_p = aa_cred_profile(lcred); + struct aa_profile *tracee_p = aa_get_task_profile(tracee); error = aa_may_ptrace(tracer, tracer_p, tracee_p, mode); error = aa_audit_ptrace(tracer_p, tracee_p, error); - put_cred(lcred); + aa_put_profile(tracee_p); } - put_cred(cred); + aa_put_profile(tracer_p); return error; } diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index 7430298116d..d40bc592180 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c @@ -45,8 +45,10 @@ char *aa_split_fqname(char *fqname, char **ns_name) *ns_name = skip_spaces(&name[1]); if (split) { /* overwrite ':' with \0 */ - *split = 0; - name = skip_spaces(split + 1); + *split++ = 0; + if (strncmp(split, "//", 2) == 0) + split += 2; + name = skip_spaces(split); } else /* a ns name without a following profile is allowed */ name = NULL; @@ -75,15 +77,16 @@ void aa_info_message(const char *str) } /** - * kvmalloc - do allocation preferring kmalloc but falling back to vmalloc - * @size: size of allocation + * __aa_kvmalloc - do allocation preferring kmalloc but falling back to vmalloc + * @size: how many bytes of memory are required + * @flags: the type of memory to allocate (see kmalloc). * * Return: allocated buffer or NULL if failed * * It is possible that policy being loaded from the user is larger than * what can be allocated by kmalloc, in those cases fall back to vmalloc. */ -void *kvmalloc(size_t size) +void *__aa_kvmalloc(size_t size, gfp_t flags) { void *buffer = NULL; @@ -92,14 +95,17 @@ void *kvmalloc(size_t size) /* do not attempt kmalloc if we need more than 16 pages at once */ if (size <= (16*PAGE_SIZE)) - buffer = kmalloc(size, GFP_NOIO | __GFP_NOWARN); + buffer = kmalloc(size, flags | GFP_NOIO | __GFP_NOWARN); if (!buffer) { /* see kvfree for why size must be at least work_struct size * when allocated via vmalloc */ if (size < sizeof(struct work_struct)) size = sizeof(struct work_struct); - buffer = vmalloc(size); + if (flags & __GFP_ZERO) + buffer = vzalloc(size); + else + buffer = vmalloc(size); } return buffer; } diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index b21830eced4..2e2a0dd4a73 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -48,8 +48,8 @@ int apparmor_initialized __initdata; */ static void apparmor_cred_free(struct cred *cred) { - aa_free_task_context(cred->security); - cred->security = NULL; + aa_free_task_context(cred_cxt(cred)); + cred_cxt(cred) = NULL; } /* @@ -62,7 +62,7 @@ static int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp) if (!cxt) return -ENOMEM; - cred->security = cxt; + cred_cxt(cred) = cxt; return 0; } @@ -77,8 +77,8 @@ static int apparmor_cred_prepare(struct cred *new, const struct cred *old, if (!cxt) return -ENOMEM; - aa_dup_task_context(cxt, old->security); - new->security = cxt; + aa_dup_task_context(cxt, cred_cxt(old)); + cred_cxt(new) = cxt; return 0; } @@ -87,8 +87,8 @@ static int apparmor_cred_prepare(struct cred *new, const struct cred *old, */ static void apparmor_cred_transfer(struct cred *new, const struct cred *old) { - const struct aa_task_cxt *old_cxt = old->security; - struct aa_task_cxt *new_cxt = new->security; + const struct aa_task_cxt *old_cxt = cred_cxt(old); + struct aa_task_cxt *new_cxt = cred_cxt(new); aa_dup_task_context(new_cxt, old_cxt); } @@ -469,7 +469,6 @@ static int apparmor_file_lock(struct file *file, unsigned int cmd) static int common_mmap(int op, struct file *file, unsigned long prot, unsigned long flags) { - struct dentry *dentry; int mask = 0; if (!file || !file->f_security) @@ -486,7 +485,6 @@ static int common_mmap(int op, struct file *file, unsigned long prot, if (prot & PROT_EXEC) mask |= AA_EXEC_MMAP; - dentry = file->f_path.dentry; return common_file_perm(op, file, mask); } @@ -507,11 +505,9 @@ static int apparmor_getprocattr(struct task_struct *task, char *name, char **value) { int error = -ENOENT; - struct aa_profile *profile; /* released below */ const struct cred *cred = get_task_cred(task); - struct aa_task_cxt *cxt = cred->security; - profile = aa_cred_profile(cred); + struct aa_task_cxt *cxt = cred_cxt(cred); if (strcmp(name, "current") == 0) error = aa_getprocattr(aa_newest_version(cxt->profile), @@ -533,6 +529,8 @@ static int apparmor_getprocattr(struct task_struct *task, char *name, static int apparmor_setprocattr(struct task_struct *task, char *name, void *value, size_t size) { + struct common_audit_data sa; + struct apparmor_audit_data aad = {0,}; char *command, *args = value; size_t arg_size; int error; @@ -576,30 +574,31 @@ static int apparmor_setprocattr(struct task_struct *task, char *name, } else if (strcmp(command, "permprofile") == 0) { error = aa_setprocattr_changeprofile(args, !AA_ONEXEC, AA_DO_TEST); - } else if (strcmp(command, "permipc") == 0) { - error = aa_setprocattr_permipc(args); - } else { - struct common_audit_data sa; - struct apparmor_audit_data aad = {0,}; - sa.type = LSM_AUDIT_DATA_NONE; - sa.aad = &aad; - aad.op = OP_SETPROCATTR; - aad.info = name; - aad.error = -EINVAL; - return aa_audit(AUDIT_APPARMOR_DENIED, - __aa_current_profile(), GFP_KERNEL, - &sa, NULL); - } + } else + goto fail; } else if (strcmp(name, "exec") == 0) { - error = aa_setprocattr_changeprofile(args, AA_ONEXEC, - !AA_DO_TEST); - } else { + if (strcmp(command, "exec") == 0) + error = aa_setprocattr_changeprofile(args, AA_ONEXEC, + !AA_DO_TEST); + else + goto fail; + } else /* only support the "current" and "exec" process attributes */ return -EINVAL; - } + if (!error) error = size; return error; + +fail: + sa.type = LSM_AUDIT_DATA_NONE; + sa.aad = &aad; + aad.profile = aa_current_profile(); + aad.op = OP_SETPROCATTR; + aad.info = name; + aad.error = -EINVAL; + aa_audit_msg(AUDIT_APPARMOR_DENIED, &sa, NULL); + return -EINVAL; } static int apparmor_task_setrlimit(struct task_struct *task, @@ -886,7 +885,7 @@ static int __init set_init_cxt(void) return -ENOMEM; cxt->profile = aa_get_profile(root_ns->unconfined); - cred->security = cxt; + cred_cxt(cred) = cxt; return 0; } @@ -915,8 +914,11 @@ static int __init apparmor_init(void) error = register_security(&apparmor_ops); if (error) { + struct cred *cred = (struct cred *)current->real_cred; + aa_free_task_context(cred_cxt(cred)); + cred_cxt(cred) = NULL; AA_ERROR("Unable to register AppArmor\n"); - goto set_init_cxt_out; + goto register_security_out; } /* Report that AppArmor successfully initialized */ @@ -930,9 +932,6 @@ static int __init apparmor_init(void) return error; -set_init_cxt_out: - aa_free_task_context(current->real_cred->security); - register_security_out: aa_free_root_ns(); diff --git a/security/apparmor/match.c b/security/apparmor/match.c index 90971a8c378..727eb4200d5 100644 --- a/security/apparmor/match.c +++ b/security/apparmor/match.c @@ -4,7 +4,7 @@ * This file contains AppArmor dfa based regular expression matching engine * * Copyright (C) 1998-2008 Novell/SUSE - * Copyright 2009-2010 Canonical Ltd. + * Copyright 2009-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 @@ -23,6 +23,8 @@ #include "include/apparmor.h" #include "include/match.h" +#define base_idx(X) ((X) & 0xffffff) + /** * unpack_table - unpack a dfa table (one of accept, default, base, next check) * @blob: data to unpack (NOT NULL) @@ -30,7 +32,7 @@ * * Returns: pointer to table else NULL on failure * - * NOTE: must be freed by kvfree (not kmalloc) + * NOTE: must be freed by kvfree (not kfree) */ static struct table_header *unpack_table(char *blob, size_t bsize) { @@ -57,7 +59,7 @@ static struct table_header *unpack_table(char *blob, size_t bsize) if (bsize < tsize) goto out; - table = kvmalloc(tsize); + table = kvzalloc(tsize); if (table) { *table = th; if (th.td_flags == YYTD_DATA8) @@ -137,8 +139,7 @@ static int verify_dfa(struct aa_dfa *dfa, int flags) for (i = 0; i < state_count; i++) { if (DEFAULT_TABLE(dfa)[i] >= state_count) goto out; - /* TODO: do check that DEF state recursion terminates */ - if (BASE_TABLE(dfa)[i] + 255 >= trans_count) { + if (base_idx(BASE_TABLE(dfa)[i]) + 255 >= trans_count) { printk(KERN_ERR "AppArmor DFA next/check upper " "bounds error\n"); goto out; @@ -314,7 +315,7 @@ unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start, u8 *equiv = EQUIV_TABLE(dfa); /* default is direct to next state */ for (; len; len--) { - pos = base[state] + equiv[(u8) *str++]; + pos = base_idx(base[state]) + equiv[(u8) *str++]; if (check[pos] == state) state = next[pos]; else @@ -323,7 +324,7 @@ unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start, } else { /* default is direct to next state */ for (; len; len--) { - pos = base[state] + (u8) *str++; + pos = base_idx(base[state]) + (u8) *str++; if (check[pos] == state) state = next[pos]; else @@ -364,7 +365,7 @@ unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start, u8 *equiv = EQUIV_TABLE(dfa); /* default is direct to next state */ while (*str) { - pos = base[state] + equiv[(u8) *str++]; + pos = base_idx(base[state]) + equiv[(u8) *str++]; if (check[pos] == state) state = next[pos]; else @@ -373,7 +374,7 @@ unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start, } else { /* default is direct to next state */ while (*str) { - pos = base[state] + (u8) *str++; + pos = base_idx(base[state]) + (u8) *str++; if (check[pos] == state) state = next[pos]; else @@ -409,14 +410,14 @@ unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state, u8 *equiv = EQUIV_TABLE(dfa); /* default is direct to next state */ - pos = base[state] + equiv[(u8) c]; + pos = base_idx(base[state]) + equiv[(u8) c]; if (check[pos] == state) state = next[pos]; else state = def[state]; } else { /* default is direct to next state */ - pos = base[state] + (u8) c; + pos = base_idx(base[state]) + (u8) c; if (check[pos] == state) state = next[pos]; else diff --git a/security/apparmor/path.c b/security/apparmor/path.c index e91ffee8016..35b394a75d7 100644 --- a/security/apparmor/path.c +++ b/security/apparmor/path.c @@ -174,7 +174,7 @@ static int get_name_to_buffer(struct path *path, int flags, char *buffer, if (info && error) { if (error == -ENOENT) *info = "Failed name lookup - deleted entry"; - else if (error == -ESTALE) + else if (error == -EACCES) *info = "Failed name lookup - disconnected path"; else if (error == -ENAMETOOLONG) |