diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-14 00:38:53 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-14 00:38:53 +0200 |
commit | 80a17a5f501ea048d86f81d629c94062b76610d4 (patch) | |
tree | 55dd0a1490d1e6631ca319a1205f974f041b494f /security/apparmor/include | |
parent | Merge tag 'for-linus-20180413' of git://git.kernel.dk/linux-block (diff) | |
parent | apparmor: fix memory leak on buffer on error exit path (diff) | |
download | linux-80a17a5f501ea048d86f81d629c94062b76610d4.tar.xz linux-80a17a5f501ea048d86f81d629c94062b76610d4.zip |
Merge tag 'apparmor-pr-2018-04-10' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor
Pull apparmor updates from John Johansen:
"Features:
- add base infrastructure for socket mediation. ABI bump and
additional checks to ensure only v8 compliant policy uses socket af
mediation.
- improve and cleanup dfa verification
- improve profile attachment logic
- improve overlapping expression handling
- add the xattr matching to the attachment logic
- improve signal mediation handling with stacked labels
- improve handling of no_new_privs in a label stack
Cleanups and changes:
- use dfa to parse string split
- bounded version of label_parse
- proper line wrap nulldfa.in
- split context out into task and cred naming to better match usage
- simplify code in aafs
Bug fixes:
- fix display of .ns_name for containers
- fix resource audit messages when auditing peer
- fix logging of the existence test for signals
- fix resource audit messages when auditing peer
- fix display of .ns_name for containers
- fix an error code in verify_table_headers()
- fix memory leak on buffer on error exit path
- fix error returns checks by making size a ssize_t"
* tag 'apparmor-pr-2018-04-10' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor: (36 commits)
apparmor: fix memory leak on buffer on error exit path
apparmor: fix dangling symlinks to policy rawdata after replacement
apparmor: Fix an error code in verify_table_headers()
apparmor: fix error returns checks by making size a ssize_t
apparmor: update MAINTAINERS file git and wiki locations
apparmor: remove POLICY_MEDIATES_SAFE
apparmor: add base infastructure for socket mediation
apparmor: improve overlapping domain attachment resolution
apparmor: convert attaching profiles via xattrs to use dfa matching
apparmor: Add support for attaching profiles via xattr, presence and value
apparmor: cleanup: simplify code to get ns symlink name
apparmor: cleanup create_aafs() error path
apparmor: dfa split verification of table headers
apparmor: dfa add support for state differential encoding
apparmor: dfa move character match into a macro
apparmor: update domain transitions that are subsets of confinement at nnp
apparmor: move context.h to cred.h
apparmor: move task related defines and fns to task.X files
apparmor: cleanup, drop unused fn __aa_task_is_confined()
apparmor: cleanup fixup description of aa_replace_profiles
...
Diffstat (limited to 'security/apparmor/include')
-rw-r--r-- | security/apparmor/include/apparmor.h | 3 | ||||
-rw-r--r-- | security/apparmor/include/audit.h | 19 | ||||
-rw-r--r-- | security/apparmor/include/cred.h (renamed from security/apparmor/include/context.h) | 63 | ||||
-rw-r--r-- | security/apparmor/include/label.h | 28 | ||||
-rw-r--r-- | security/apparmor/include/match.h | 28 | ||||
-rw-r--r-- | security/apparmor/include/net.h | 106 | ||||
-rw-r--r-- | security/apparmor/include/perms.h | 5 | ||||
-rw-r--r-- | security/apparmor/include/policy.h | 23 | ||||
-rw-r--r-- | security/apparmor/include/policy_unpack.h | 2 | ||||
-rw-r--r-- | security/apparmor/include/sig_names.h | 5 | ||||
-rw-r--r-- | security/apparmor/include/task.h | 94 |
11 files changed, 299 insertions, 77 deletions
diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h index 829082c35faa..73d63b58d875 100644 --- a/security/apparmor/include/apparmor.h +++ b/security/apparmor/include/apparmor.h @@ -24,12 +24,13 @@ #define AA_CLASS_UNKNOWN 1 #define AA_CLASS_FILE 2 #define AA_CLASS_CAP 3 -#define AA_CLASS_NET 4 +#define AA_CLASS_DEPRECATED 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_NET 14 #define AA_CLASS_LABEL 16 #define AA_CLASS_LAST AA_CLASS_LABEL diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h index 4ac095118717..9c9be9c98c15 100644 --- a/security/apparmor/include/audit.h +++ b/security/apparmor/include/audit.h @@ -126,7 +126,20 @@ struct apparmor_audit_data { const char *target; kuid_t ouid; } fs; - int signal; + struct { + int rlim; + unsigned long max; + } rlim; + struct { + int signal; + int unmappedsig; + }; + struct { + int type, protocol; + struct sock *peer_sk; + void *addr; + int addrlen; + } net; }; }; struct { @@ -135,10 +148,6 @@ struct apparmor_audit_data { long pos; } iface; struct { - int rlim; - unsigned long max; - } rlim; - struct { const char *src_name; const char *type; const char *trans; diff --git a/security/apparmor/include/context.h b/security/apparmor/include/cred.h index 6ae07e9aaa17..e287b7d0d4be 100644 --- a/security/apparmor/include/context.h +++ b/security/apparmor/include/cred.h @@ -21,38 +21,9 @@ #include "label.h" #include "policy_ns.h" +#include "task.h" -#define cred_ctx(X) ((X)->security) -#define current_ctx() cred_ctx(current_cred()) - -/** - * struct aa_task_ctx - primary label for confined tasks - * @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 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_ctx { - struct aa_label *label; - struct aa_label *onexec; - struct aa_label *previous; - u64 token; -}; - -struct aa_task_ctx *aa_alloc_task_context(gfp_t flags); -void aa_free_task_context(struct aa_task_ctx *ctx); -void aa_dup_task_context(struct aa_task_ctx *new, - const struct aa_task_ctx *old); -int aa_replace_current_label(struct aa_label *label); -int aa_set_current_onexec(struct aa_label *label, bool stack); -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); +#define cred_label(X) ((X)->security) /** @@ -65,10 +36,10 @@ struct aa_label *aa_get_task_label(struct task_struct *task); */ static inline struct aa_label *aa_cred_raw_label(const struct cred *cred) { - struct aa_task_ctx *ctx = cred_ctx(cred); + struct aa_label *label = cred_label(cred); - AA_BUG(!ctx || !ctx->label); - return ctx->label; + AA_BUG(!label); + return label; } /** @@ -96,17 +67,6 @@ static inline struct aa_label *__aa_task_raw_label(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) -{ - return !unconfined(__aa_task_raw_label(task)); -} - -/** * aa_current_raw_label - find the current tasks confining label * * Returns: up to date confining label or the ns unconfined label (NOT NULL) @@ -213,17 +173,4 @@ static inline struct aa_ns *aa_get_current_ns(void) return ns; } -/** - * aa_clear_task_ctx_trans - clear transition tracking info from the ctx - * @ctx: task context to clear (NOT NULL) - */ -static inline void aa_clear_task_ctx_trans(struct aa_task_ctx *ctx) -{ - aa_put_label(ctx->previous); - aa_put_label(ctx->onexec); - ctx->previous = NULL; - ctx->onexec = NULL; - ctx->token = 0; -} - #endif /* __AA_CONTEXT_H */ diff --git a/security/apparmor/include/label.h b/security/apparmor/include/label.h index af22dcbbcb8a..d871e7ff0952 100644 --- a/security/apparmor/include/label.h +++ b/security/apparmor/include/label.h @@ -327,9 +327,37 @@ void aa_label_audit(struct audit_buffer *ab, struct aa_label *label, gfp_t gfp); void aa_label_seq_print(struct seq_file *f, struct aa_label *label, gfp_t gfp); void aa_label_printk(struct aa_label *label, gfp_t gfp); +struct aa_label *aa_label_strn_parse(struct aa_label *base, const char *str, + size_t n, gfp_t gfp, bool create, + bool force_stack); struct aa_label *aa_label_parse(struct aa_label *base, const char *str, gfp_t gfp, bool create, bool force_stack); +static inline const char *aa_label_strn_split(const char *str, int n) +{ + const char *pos; + unsigned int state; + + state = aa_dfa_matchn_until(stacksplitdfa, DFA_START, str, n, &pos); + if (!ACCEPT_TABLE(stacksplitdfa)[state]) + return NULL; + + return pos - 3; +} + +static inline const char *aa_label_str_split(const char *str) +{ + const char *pos; + unsigned int state; + + state = aa_dfa_match_until(stacksplitdfa, DFA_START, str, &pos); + if (!ACCEPT_TABLE(stacksplitdfa)[state]) + return NULL; + + return pos - 3; +} + + struct aa_perms; int aa_label_match(struct aa_profile *profile, struct aa_label *label, diff --git a/security/apparmor/include/match.h b/security/apparmor/include/match.h index add4c6726558..958d2b52a7b7 100644 --- a/security/apparmor/include/match.h +++ b/security/apparmor/include/match.h @@ -40,6 +40,7 @@ */ #define YYTH_MAGIC 0x1B5E783D +#define YYTH_FLAG_DIFF_ENCODE 1 struct table_set_header { u32 th_magic; /* YYTH_MAGIC */ @@ -101,6 +102,7 @@ struct aa_dfa { }; extern struct aa_dfa *nulldfa; +extern struct aa_dfa *stacksplitdfa; #define byte_to_byte(X) (X) @@ -129,9 +131,32 @@ unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start, const char *str); unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state, const char c); +unsigned int aa_dfa_match_until(struct aa_dfa *dfa, unsigned int start, + const char *str, const char **retpos); +unsigned int aa_dfa_matchn_until(struct aa_dfa *dfa, unsigned int start, + const char *str, int n, const char **retpos); void aa_dfa_free_kref(struct kref *kref); +#define WB_HISTORY_SIZE 8 +struct match_workbuf { + unsigned int count; + unsigned int pos; + unsigned int len; + unsigned int size; /* power of 2, same as history size */ + unsigned int history[WB_HISTORY_SIZE]; +}; +#define DEFINE_MATCH_WB(N) \ +struct match_workbuf N = { \ + .count = 0, \ + .pos = 0, \ + .len = 0, \ + .size = WB_HISTORY_SIZE, \ +} + +unsigned int aa_dfa_leftmatch(struct aa_dfa *dfa, unsigned int start, + const char *str, unsigned int *count); + /** * aa_get_dfa - increment refcount on dfa @p * @dfa: dfa (MAYBE NULL) @@ -159,4 +184,7 @@ static inline void aa_put_dfa(struct aa_dfa *dfa) kref_put(&dfa->count, aa_dfa_free_kref); } +#define MATCH_FLAG_DIFF_ENCODE 0x80000000 +#define MARK_DIFF_ENCODE 0x40000000 + #endif /* __AA_MATCH_H */ diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h new file mode 100644 index 000000000000..ec7228e857a9 --- /dev/null +++ b/security/apparmor/include/net.h @@ -0,0 +1,106 @@ +/* + * AppArmor security module + * + * This file contains AppArmor network mediation definitions. + * + * Copyright (C) 1998-2008 Novell/SUSE + * Copyright 2009-2017 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 <linux/path.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_ctx { + struct aa_label *label; + struct aa_label *peer; +}; + +#define SK_CTX(X) ((X)->sk_security) +#define SOCK_ctx(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) && (F) != AF_UNIX) ? LSM_AUDIT_DATA_NET : \ + LSM_AUDIT_DATA_NONE, \ + OP); \ + NAME.u.net = &(NAME ## _net); \ + aad(&NAME)->net.type = (T); \ + aad(&NAME)->net.protocol = (P) + +#define DEFINE_AUDIT_SK(NAME, OP, SK) \ + DEFINE_AUDIT_NET(NAME, OP, SK, (SK)->sk_family, (SK)->sk_type, \ + (SK)->sk_protocol) + + +#define af_select(FAMILY, FN, DEF_FN) \ +({ \ + int __e; \ + switch ((FAMILY)) { \ + default: \ + __e = DEF_FN; \ + } \ + __e; \ +}) + +extern struct aa_sfs_entry aa_sfs_entry_network[]; + +void audit_net_cb(struct audit_buffer *ab, void *va); +int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa, + u32 request, u16 family, int type); +int aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family, + int type, int protocol); +static inline int aa_profile_af_sk_perm(struct aa_profile *profile, + struct common_audit_data *sa, + u32 request, + struct sock *sk) +{ + return aa_profile_af_perm(profile, sa, request, sk->sk_family, + sk->sk_type); +} +int aa_sk_perm(const char *op, u32 request, struct sock *sk); + +int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request, + struct socket *sock); + +#endif /* __AA_NET_H */ diff --git a/security/apparmor/include/perms.h b/security/apparmor/include/perms.h index d7b7e7115160..38aa6247d00f 100644 --- a/security/apparmor/include/perms.h +++ b/security/apparmor/include/perms.h @@ -138,9 +138,10 @@ extern struct aa_perms allperms; 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_names(struct audit_buffer *ab, const char * const *names, + u32 mask); void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs, - u32 chrsmask, const char **names, u32 namesmask); + u32 chrsmask, const char * const *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, diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 17fe41a9cac3..ab64c6b5db5a 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -30,6 +30,7 @@ #include "file.h" #include "lib.h" #include "label.h" +#include "net.h" #include "perms.h" #include "resource.h" @@ -148,6 +149,10 @@ struct aa_profile { struct aa_policydb policy; struct aa_file_rules file; struct aa_caps caps; + + int xattr_count; + char **xattrs; + struct aa_rlimit rlimits; struct aa_loaddata *rawdata; @@ -209,15 +214,15 @@ static inline struct aa_profile *aa_get_newest_profile(struct aa_profile *p) return labels_profile(aa_get_newest_label(&p->label)); } -#define PROFILE_MEDIATES(P, T) ((P)->policy.start[(T)]) -/* safe version of POLICY_MEDIATES for full range input */ -static inline unsigned int PROFILE_MEDIATES_SAFE(struct aa_profile *profile, - unsigned char class) -{ - if (profile->policy.dfa) - return aa_dfa_match_len(profile->policy.dfa, - profile->policy.start[0], &class, 1); - return 0; +#define PROFILE_MEDIATES(P, T) ((P)->policy.start[(unsigned char) (T)]) +static inline unsigned int PROFILE_MEDIATES_AF(struct aa_profile *profile, + u16 AF) { + unsigned int state = PROFILE_MEDIATES(profile, AA_CLASS_NET); + __be16 be_af = cpu_to_be16(AF); + + if (!state) + return 0; + return aa_dfa_match_len(profile->policy.dfa, state, (char *) &be_af, 2); } /** diff --git a/security/apparmor/include/policy_unpack.h b/security/apparmor/include/policy_unpack.h index be6cd69ac319..8db4ab759e80 100644 --- a/security/apparmor/include/policy_unpack.h +++ b/security/apparmor/include/policy_unpack.h @@ -70,7 +70,7 @@ struct aa_loaddata { int abi; unsigned char *hash; - char data[]; + char *data; }; int aa_unpack(struct aa_loaddata *udata, struct list_head *lh, const char **ns); diff --git a/security/apparmor/include/sig_names.h b/security/apparmor/include/sig_names.h index 92e62fe95292..cbf7a997ed84 100644 --- a/security/apparmor/include/sig_names.h +++ b/security/apparmor/include/sig_names.h @@ -2,6 +2,9 @@ #define SIGUNKNOWN 0 #define MAXMAPPED_SIG 35 +#define MAXMAPPED_SIGNAME (MAXMAPPED_SIG + 1) +#define SIGRT_BASE 128 + /* 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 @@ -56,7 +59,7 @@ static const int sig_map[MAXMAPPED_SIG] = { }; /* this table is ordered post sig_map[sig] mapping */ -static const char *const sig_names[MAXMAPPED_SIG + 1] = { +static const char *const sig_names[MAXMAPPED_SIGNAME] = { "unknown", "hup", "int", diff --git a/security/apparmor/include/task.h b/security/apparmor/include/task.h new file mode 100644 index 000000000000..55edaa1d83f8 --- /dev/null +++ b/security/apparmor/include/task.h @@ -0,0 +1,94 @@ +/* + * AppArmor security module + * + * This file contains AppArmor task related definitions and mediation + * + * Copyright 2017 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_TASK_H +#define __AA_TASK_H + +#define task_ctx(X) ((X)->security) + +/* + * struct aa_task_ctx - information for current task label change + * @nnp: snapshot of label at time of no_new_privs + * @onexec: profile to transition to on next exec (MAY BE NULL) + * @previous: profile the task may return to (MAY BE NULL) + * @token: magic value the task must know for returning to @previous_profile + */ +struct aa_task_ctx { + struct aa_label *nnp; + struct aa_label *onexec; + struct aa_label *previous; + u64 token; +}; + +int aa_replace_current_label(struct aa_label *label); +int aa_set_current_onexec(struct aa_label *label, bool stack); +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_alloc_task_ctx - allocate a new task_ctx + * @flags: gfp flags for allocation + * + * Returns: allocated buffer or NULL on failure + */ +static inline struct aa_task_ctx *aa_alloc_task_ctx(gfp_t flags) +{ + return kzalloc(sizeof(struct aa_task_ctx), flags); +} + +/** + * aa_free_task_ctx - free a task_ctx + * @ctx: task_ctx to free (MAYBE NULL) + */ +static inline void aa_free_task_ctx(struct aa_task_ctx *ctx) +{ + if (ctx) { + aa_put_label(ctx->nnp); + aa_put_label(ctx->previous); + aa_put_label(ctx->onexec); + + kzfree(ctx); + } +} + +/** + * aa_dup_task_ctx - duplicate a task context, incrementing reference counts + * @new: a blank task context (NOT NULL) + * @old: the task context to copy (NOT NULL) + */ +static inline void aa_dup_task_ctx(struct aa_task_ctx *new, + const struct aa_task_ctx *old) +{ + *new = *old; + aa_get_label(new->nnp); + aa_get_label(new->previous); + aa_get_label(new->onexec); +} + +/** + * aa_clear_task_ctx_trans - clear transition tracking info from the ctx + * @ctx: task context to clear (NOT NULL) + */ +static inline void aa_clear_task_ctx_trans(struct aa_task_ctx *ctx) +{ + AA_BUG(!ctx); + + aa_put_label(ctx->previous); + aa_put_label(ctx->onexec); + ctx->previous = NULL; + ctx->onexec = NULL; + ctx->token = 0; +} + +#endif /* __AA_TASK_H */ |