aboutsummaryrefslogtreecommitdiff
path: root/security
diff options
context:
space:
mode:
authorJohn Johansen <john.johansen@canonical.com>2010-07-23 04:57:23 -0700
committerLeann Ogasawara <leann.ogasawara@canonical.com>2010-08-11 07:43:10 -0700
commit23a79fa7d4143b6b270259c19b64d29e9dfc3873 (patch)
tree1554b84a39ffeb3f0a682c1ff0b0c9b15bcddd8e /security
parent3bf4c3a4f65a41062623d9cd50e9ed9f36beebe3 (diff)
UBUNTU: SAUCE: AppArmor: -- sync to AppArmor mainline 2010-07-27
Sync AppArmor mainline upstreaming version 2010-06-27 contains fixes for BugLink: http://bugs.launchpad.net/bugs/599450 BugLink: http://bugs.launchpad.net/bugs/581525 Signed-off-by: John Johansen <john.johansen@canonical.com> Signed-off-by: Leann Ogasawara <leann.ogasawara@canonical.com>
Diffstat (limited to 'security')
-rw-r--r--security/apparmor/Kconfig9
-rw-r--r--security/apparmor/Makefile8
-rw-r--r--security/apparmor/apparmorfs.c75
-rw-r--r--security/apparmor/audit.c59
-rw-r--r--security/apparmor/capability.c12
-rw-r--r--security/apparmor/context.c4
-rw-r--r--security/apparmor/domain.c36
-rw-r--r--security/apparmor/file.c59
-rw-r--r--security/apparmor/include/apparmor.h27
-rw-r--r--security/apparmor/include/apparmorfs.h9
-rw-r--r--security/apparmor/include/audit.h8
-rw-r--r--security/apparmor/include/domain.h2
-rw-r--r--security/apparmor/include/file.h39
-rw-r--r--security/apparmor/include/match.h7
-rw-r--r--security/apparmor/include/path.h1
-rw-r--r--security/apparmor/include/policy.h31
-rw-r--r--security/apparmor/include/procattr.h2
-rw-r--r--security/apparmor/ipc.c8
-rw-r--r--security/apparmor/lib.c88
-rw-r--r--security/apparmor/lsm.c213
-rw-r--r--security/apparmor/match.c68
-rw-r--r--security/apparmor/path.c88
-rw-r--r--security/apparmor/policy.c69
-rw-r--r--security/apparmor/policy_unpack.c103
-rw-r--r--security/apparmor/procattr.c9
-rw-r--r--security/apparmor/resource.c12
26 files changed, 385 insertions, 661 deletions
diff --git a/security/apparmor/Kconfig b/security/apparmor/Kconfig
index 5c57df79ca0..c054cf79f1c 100644
--- a/security/apparmor/Kconfig
+++ b/security/apparmor/Kconfig
@@ -29,12 +29,3 @@ config SECURITY_APPARMOR_BOOTPARAM_VALUE
bootup.
If you are unsure how to answer this question, answer 1.
-
-config SECURITY_APPARMOR_COMPAT_24
- bool "Enable AppArmor 2.4 compatability"
- depends on SECURITY_APPARMOR
- default y
- help
- This option enables compatability with AppArmor 2.4. It is
- recommended if compatability with older versions of AppArmor
- is desired.
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
index e5e8968cb8b..f204869399e 100644
--- a/security/apparmor/Makefile
+++ b/security/apparmor/Makefile
@@ -4,23 +4,17 @@ 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 net.o
-
-apparmor-$(CONFIG_SECURITY_APPARMOR_COMPAT_24) += apparmorfs-24.o
+ resource.o sid.o file.o
clean-files: capability_names.h af_names.h
quiet_cmd_make-caps = GEN $@
cmd_make-caps = echo "static const char *capability_names[] = {" > $@ ; sed -n -e "/CAP_FS_MASK/d" -e "s/^\#define[ \\t]\\+CAP_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\$$/[\\2] = \"\\1\",/p" $< | tr A-Z a-z >> $@ ; echo "};" >> $@
-quiet_cmd_make-af = GEN $@
-cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ; sed -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e "s/^\#define[ \\t]\\+AF_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\\(.*\\)\$$/[\\2] = \"\\1\",/p" $< | tr A-Z a-z >> $@ ; echo "};" >> $@
-
quiet_cmd_make-rlim = GEN $@
cmd_make-rlim = echo "static const char *rlim_names[] = {" > $@ ; sed -n --e "/AF_MAX/d" -e "s/^\# \\?define[ \\t]\\+RLIMIT_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\\(.*\\)\$$/[\\2] = \"\\1\",/p" $< | tr A-Z a-z >> $@ ; echo "};" >> $@ ; echo "static const int rlim_map[] = {" >> $@ ; sed -n -e "/AF_MAX/d" -e "s/^\# \\?define[ \\t]\\+\\(RLIMIT_[A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\\(.*\\)\$$/\\1,/p" $< >> $@ ; echo "};" >> $@
$(obj)/capability.o : $(obj)/capability_names.h
-$(obj)/net.o : $(obj)/af_names.h
$(obj)/resource.o : $(obj)/rlim_names.h
$(obj)/capability_names.h : $(srctree)/include/linux/capability.h
$(call cmd,make-caps)
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 5fb9385bb1f..d8a27a4c84c 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -26,51 +26,12 @@
#include "include/policy.h"
/**
- * kvmalloc - do allocation prefering kmalloc but falling back to vmalloc
- * @size: size of allocation
- *
- * 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.
- */
-static void *kvmalloc(size_t size)
-{
- void *buffer;
-
- if (size == 0)
- return NULL;
-
- buffer = kmalloc(size, GFP_KERNEL | __GFP_NOWARN);
- if (!buffer)
- buffer = vmalloc(size);
- return buffer;
-}
-
-/**
- * kvfree - free an allocation do by kvmalloc
- * @buffer: buffer to free
- *
- * Free a buffer allocated by kvmalloc
- */
-static void kvfree(void *buffer)
-{
- if (!buffer)
- return;
-
- if (is_vmalloc_addr(buffer))
- vfree(buffer);
- else
- kfree(buffer);
-}
-
-/**
* aa_simple_write_to_buffer - common routine for getting policy from user
* @op: operation doing the user buffer copy
* @userbuf: user buffer to copy data from (NOT NULL)
* @alloc_size: size of user buffer
* @copy_size: size of data to copy from user buffer
- * @pos: position write is at in the file
+ * @pos: position write is at in the file (NOT NULL)
*
* Returns: kernel buffer containing copy of user buffer data or an
* ERR_PTR on failure.
@@ -81,11 +42,9 @@ static char *aa_simple_write_to_buffer(int op, const char __user *userbuf,
{
char *data;
- if (*pos != 0) {
+ if (*pos != 0)
/* only writes from pos 0, that is complete writes */
- data = ERR_PTR(-ESPIPE);
- goto out;
- }
+ return ERR_PTR(-ESPIPE);
/*
* Don't allow profile load/replace/remove from profiles that don't
@@ -101,11 +60,9 @@ static char *aa_simple_write_to_buffer(int op, const char __user *userbuf,
if (copy_from_user(data, userbuf, copy_size)) {
kvfree(data);
- data = ERR_PTR(-EFAULT);
- goto out;
+ return ERR_PTR(-EFAULT);
}
-out:
return data;
}
@@ -183,8 +140,6 @@ static const struct file_operations aa_fs_profile_remove = {
/** Base file system setup **/
static struct dentry *aa_fs_dentry;
-struct dentry *aa_fs_null;
-struct vfsmount *aa_fs_mnt;
static void aafs_remove(const char *name)
{
@@ -199,9 +154,9 @@ static void aafs_remove(const char *name)
/**
* aafs_create - create an entry in the apparmor filesystem
- * @name: name of the entry
+ * @name: name of the entry (NOT NULL)
* @mask: file permission mask of the file
- * @fops: file operations for the file
+ * @fops: file operations for the file (NOT NULL)
*
* Used aafs_remove to remove entries created with this fn.
*/
@@ -227,11 +182,7 @@ void aa_destroy_aafs(void)
aafs_remove(".remove");
aafs_remove(".replace");
aafs_remove(".load");
- aafs_remove("profiles");
-#ifdef CONFIG_SECURITY_APPARMOR_COMPAT_24
- aafs_remove("matching");
- aafs_remove("features");
-#endif
+
securityfs_remove(aa_fs_dentry);
aa_fs_dentry = NULL;
}
@@ -262,17 +213,7 @@ int aa_create_aafs(void)
aa_fs_dentry = NULL;
goto error;
}
-#ifdef CONFIG_SECURITY_APPARMOR_COMPAT_24
- error = aafs_create("matching", 0444, &aa_fs_matching_fops);
- if (error)
- goto error;
- error = aafs_create("features", 0444, &aa_fs_features_fops);
- if (error)
- goto error;
-#endif
- error = aafs_create("profiles", 0440, &aa_fs_profiles_fops);
- if (error)
- goto error;
+
error = aafs_create(".load", 0640, &aa_fs_profile_load);
if (error)
goto error;
diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
index 12a86c00a7f..d0311eb71a6 100644
--- a/security/apparmor/audit.c
+++ b/security/apparmor/audit.c
@@ -82,20 +82,19 @@ const char *audit_mode_names[] = {
};
static char *aa_audit_type[] = {
- "APPARMOR_AUDIT",
- "APPARMOR_ALLOWED",
- "APPARMOR_DENIED",
- "APPARMOR_HINT",
- "APPARMOR_STATUS",
- "APPARMOR_ERROR",
- "APPARMOR_KILLED"
+ "AUDIT",
+ "ALLOWED",
+ "DENIED",
+ "HINT",
+ "STATUS",
+ "ERROR",
+ "KILLED"
};
/*
* Currently AppArmor auditing is fed straight into the audit framework.
*
* TODO:
- * convert to LSM audit
* netlink interface for complain mode
* user auditing, - send user auditing to netlink interface
* system control of whether user audit messages go to system log
@@ -103,8 +102,8 @@ static char *aa_audit_type[] = {
/**
* audit_base - core AppArmor function.
- * @ab: audit buffer to fill
- * @sa: audit structure containing data to audit
+ * @ab: audit buffer to fill (NOT NULL)
+ * @ca: audit structure containing data to audit (NOT NULL)
*
* Record common AppArmor audit data from @sa
*/
@@ -114,7 +113,7 @@ static void audit_pre(struct audit_buffer *ab, void *ca)
struct task_struct *tsk = sa->tsk ? sa->tsk : current;
if (aa_g_audit_header) {
- audit_log_format(ab, " type=");
+ audit_log_format(ab, "apparmor=");
audit_log_string(ab, aa_audit_type[sa->aad.type]);
}
@@ -130,8 +129,6 @@ static void audit_pre(struct audit_buffer *ab, void *ca)
audit_log_format(ab, " error=%d", sa->aad.error);
}
- audit_log_format(ab, " pid=%d", tsk->pid);
-
if (sa->aad.profile) {
struct aa_profile *profile = sa->aad.profile;
pid_t pid;
@@ -139,12 +136,11 @@ static void audit_pre(struct audit_buffer *ab, void *ca)
pid = tsk->real_parent->pid;
rcu_read_unlock();
audit_log_format(ab, " parent=%d", pid);
- audit_log_format(ab, " profile=");
if (profile->ns != root_ns) {
- audit_log_format(ab, ":");
+ audit_log_format(ab, " namespace=");
audit_log_untrustedstring(ab, profile->ns->base.hname);
- audit_log_format(ab, "://");
}
+ audit_log_format(ab, " profile=");
audit_log_untrustedstring(ab, profile->base.hname);
}
@@ -155,12 +151,26 @@ static void audit_pre(struct audit_buffer *ab, void *ca)
}
/**
- * aa_audit - Log an audit event to the audit subsystem
+ * aa_audit_msg - Log a message to the audit subsystem
+ * @sa: audit event structure (NOT NULL)
+ * @cb: optional callback fn for type specific fields (MAYBE NULL)
+ */
+void aa_audit_msg(int type, struct common_audit_data *sa,
+ void (*cb) (struct audit_buffer *, void *))
+{
+ sa->aad.type = type;
+ sa->lsm_pre_audit = audit_pre;
+ sa->lsm_post_audit = cb;
+ common_lsm_audit(sa);
+}
+
+/**
+ * aa_audit - Log a profile based audit event to the audit subsystem
* @type: audit type for the message
- * @profile: profile to check against
+ * @profile: profile to check against (NOT NULL)
* @gfp: allocation flags to use
- * @sa: audit event
- * @cb: optional callback fn for type specific fields
+ * @sa: audit event (NOT NULL)
+ * @cb: optional callback fn for type specific fields (MAYBE NULL)
*
* Handle default message switching based off of audit mode flags
*
@@ -170,6 +180,8 @@ int aa_audit(int type, struct aa_profile *profile, gfp_t gfp,
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 (AUDIT_MODE(profile) != AUDIT_ALL)
@@ -185,16 +197,13 @@ int aa_audit(int type, struct aa_profile *profile, gfp_t gfp,
AUDIT_MODE(profile) == AUDIT_QUIET))
return sa->aad.error;
- if (profile && DO_KILL(profile) && type == AUDIT_APPARMOR_DENIED)
+ if (profile && KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED)
type = AUDIT_APPARMOR_KILL;
- sa->aad.type = type;
if (profile && !unconfined(profile))
sa->aad.profile = profile;
- sa->lsm_pre_audit = audit_pre;
- sa->lsm_post_audit = cb;
- common_lsm_audit(sa);
+ aa_audit_msg(type, sa, cb);
if (sa->aad.type == AUDIT_APPARMOR_KILL)
(void)send_sig_info(SIGKILL, NULL, sa->tsk ? sa->tsk : current);
diff --git a/security/apparmor/capability.c b/security/apparmor/capability.c
index 9c28d92ace1..80f710fc2ca 100644
--- a/security/apparmor/capability.c
+++ b/security/apparmor/capability.c
@@ -48,15 +48,15 @@ static void audit_cb(struct audit_buffer *ab, void *va)
/**
* audit_caps - audit a capability
- * @profile: profile confining task
- * @task: task capability test was performed against
+ * @profile: profile confining task (NOT NULL)
+ * @task: task capability test was performed against (NOT NULL)
* @cap: capability tested
* @error: error code returned by test
*
* Do auditing of capability and handle, audit/complain/kill modes switching
* and duplicate message elimination.
*
- * returns: 0 or sa->error on succes, error code on failure
+ * Returns: 0 or sa->error on succes, error code on failure
*/
static int audit_caps(struct aa_profile *profile, struct task_struct *task,
int cap, int error)
@@ -76,7 +76,7 @@ static int audit_caps(struct aa_profile *profile, struct task_struct *task,
!cap_raised(profile->caps.audit, cap)))
return 0;
type = AUDIT_APPARMOR_AUDIT;
- } else if (DO_KILL(profile) ||
+ } else if (KILL_MODE(profile) ||
cap_raised(profile->caps.kill, cap)) {
type = AUDIT_APPARMOR_KILL;
} else if (cap_raised(profile->caps.quiet, cap) &&
@@ -117,8 +117,8 @@ static int profile_capable(struct aa_profile *profile, int cap)
/**
* aa_capable - test permission to use capability
- * @task: task doing capability test against
- * @profile: profile confining @task
+ * @task: task doing capability test against (NOT NULL)
+ * @profile: profile confining @task (NOT NULL)
* @cap: capability to be tested
* @audit: whether an audit record should be generated
*
diff --git a/security/apparmor/context.c b/security/apparmor/context.c
index 6e12185bc67..deb4a30e0f3 100644
--- a/security/apparmor/context.c
+++ b/security/apparmor/context.c
@@ -14,7 +14,7 @@
*
*
* 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.profile, 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
* the task_cxt is reference counted.
@@ -112,7 +112,7 @@ 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)
+ * @profile: system profile to set at exec (MAYBE NULL to clear value)
*
* Returns: 0 or error on failure
*/
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index 2ae4e7aacb6..9efb5d91f22 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -100,7 +100,7 @@ out:
*/
static struct file_perms change_profile_perms(struct aa_profile *profile,
struct aa_namespace *ns,
- const char *name, u16 request,
+ const char *name, u32 request,
unsigned int start)
{
struct file_perms perms;
@@ -109,7 +109,6 @@ static struct file_perms change_profile_perms(struct aa_profile *profile,
if (unconfined(profile)) {
perms.allow = AA_MAY_CHANGE_PROFILE | AA_MAY_ONEXEC;
- perms.xindex = perms.xdelegate = perms.dindex = 0;
perms.audit = perms.quiet = perms.kill = 0;
return perms;
} else if (!profile->file.dfa) {
@@ -155,7 +154,7 @@ static struct aa_profile *__attach_match(const char *name,
if (profile->xmatch && profile->xmatch_len > len) {
unsigned int state = aa_dfa_match(profile->xmatch,
DFA_START, name);
- u16 perm = dfa_user_allow(profile->xmatch, state);
+ u32 perm = dfa_user_allow(profile->xmatch, state);
/* any accepting state means a valid match. */
if (perm & MAY_EXEC) {
candidate = profile;
@@ -237,13 +236,13 @@ static const char *next_name(int xtype, const char *name)
* @profile: current profile (NOT NULL)
* @xindex: index into x transition table
*
- * Returns: refcounted profile, or NULL on failure
+ * Returns: refcounted profile, or NULL on failure (MAYBE NULL)
*/
-static struct aa_profile *x_table_lookup(struct aa_profile *profile, u16 xindex)
+static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
{
struct aa_profile *new_profile = NULL;
struct aa_namespace *ns = profile->ns;
- u16 xtype = xindex & AA_X_TYPE_MASK;
+ u32 xtype = xindex & AA_X_TYPE_MASK;
int index = xindex & AA_X_INDEX_MASK;
const char *name;
@@ -293,7 +292,7 @@ static struct aa_profile *x_table_lookup(struct aa_profile *profile, u16 xindex)
/**
* x_to_profile - get target profile for a given xindex
* @profile: current profile (NOT NULL)
- * @name: to to lookup if specified (NOT NULL)
+ * @name: to to lookup (NOT NULL)
* @xindex: index into x transition table
*
* find profile for a transition index
@@ -301,11 +300,11 @@ static struct aa_profile *x_table_lookup(struct aa_profile *profile, u16 xindex)
* Returns: refcounted profile or NULL if not found available
*/
static struct aa_profile *x_to_profile(struct aa_profile *profile,
- const char *name, u16 xindex)
+ const char *name, u32 xindex)
{
struct aa_profile *new_profile = NULL;
struct aa_namespace *ns = profile->ns;
- u16 xtype = xindex & AA_X_TYPE_MASK;
+ u32 xtype = xindex & AA_X_TYPE_MASK;
switch (xtype) {
case AA_X_NONE:
@@ -407,7 +406,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
* onexec permission is linked to exec with a standard pairing
* exec\0change_profile
*/
- state = aa_dfa_null_transition(profile->file.dfa, state, 0);
+ state = aa_dfa_null_transition(profile->file.dfa, state);
cp = change_profile_perms(profile, cxt->onexec->ns, name,
AA_MAY_ONEXEC, state);
@@ -424,7 +423,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
if (perms.xindex & AA_X_INHERIT) {
/* (p|c|n)ix - don't change profile but do
* use the newest version, which was picked
- * up above when getting profile
+ * up above when getting profile
*/
info = "ix fallback";
new_profile = aa_get_profile(profile);
@@ -583,7 +582,7 @@ static char *new_compound_name(const char *n1, const char *n2)
/**
* aa_change_hat - change hat to/from subprofile
- * @hats: vector of hat names to try changing into (unused if @count == 0)
+ * @hats: vector of hat names to try changing into (MAYBE NULL if @count == 0)
* @count: number of hat names in @hats
* @token: magic value to validate the hat change
* @permtest: true if this is just a permission test
@@ -629,7 +628,6 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)
hat = aa_find_child(root, hats[i]);
if (!hat) {
if (!COMPLAIN_MODE(root) || permtest) {
- info = "hat not found";
if (list_empty(&root->base.profiles))
error = -ECHILD;
else
@@ -708,18 +706,20 @@ out:
/**
* aa_change_profile - perform a one-way profile transition
- * @ns_name: name of the profile namespace to change to
- * @hname: name of profile to change to
+ * @ns_name: name of the profile namespace to change to (MAYBE NULL)
+ * @hname: name of profile to change to (MAYBE NULL)
* @onexec: whether this transition is to take place immediately or at exec
* @permtest: true if this is just a permission test
*
* Change to new profile @name. Unlike with hats, there is no way
- * to change back. If @onexec then the transition is delayed until
+ * to change back. If @name isn't specified the current profile name is
+ * used.
+ * If @onexec then the transition is delayed until
* the next exec.
*
* Returns %0 on success, error otherwise.
*/
-int aa_change_profile(const char *ns_name, const char *hname, int onexec,
+int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
bool permtest)
{
const struct cred *cred;
@@ -729,7 +729,7 @@ int aa_change_profile(const char *ns_name, const char *hname, int onexec,
struct file_perms perms = {};
const char *name = NULL, *info = NULL;
int op, error = 0;
- u16 request;
+ u32 request;
if (!hname && !ns_name)
return -EINVAL;
diff --git a/security/apparmor/file.c b/security/apparmor/file.c
index 6db30491a6e..1b3c0a9edee 100644
--- a/security/apparmor/file.c
+++ b/security/apparmor/file.c
@@ -26,9 +26,8 @@ struct file_perms nullperms;
* audit_file_mask - convert mask to owner::other string
* @buffer: buffer to write string to (NOT NULL)
* @mask: permission mask to convert
- * @owner: if the mask is for owner or other
*/
-static void audit_file_mask(struct audit_buffer *ab, u16 mask)
+static void audit_file_mask(struct audit_buffer *ab, u32 mask)
{
char str[10];
@@ -53,7 +52,7 @@ static void audit_file_mask(struct audit_buffer *ab, u16 mask)
*m++ = 'k';
if (mask & MAY_EXEC)
*m++ = 'x';
- *m++ = '\0';
+ *m = '\0';
audit_log_string(ab, str);
}
@@ -99,15 +98,16 @@ static void file_audit_cb(struct audit_buffer *ab, void *va)
* @ouid: object uid
* @info: extra information message (MAYBE NULL)
* @error: 0 if operation allowed else failure error code
+ *
* Returns: %0 or error on failure
*/
int aa_audit_file(struct aa_profile *profile, struct file_perms *perms,
- gfp_t gfp, int op, u16 request, const char *name,
+ gfp_t gfp, int op, u32 request, const char *name,
const char *target, uid_t ouid, const char *info, int error)
{
int type = AUDIT_APPARMOR_AUTO;
struct common_audit_data sa;
- COMMON_AUDIT_DATA_INIT_NONE(&sa);
+ COMMON_AUDIT_DATA_INIT(&sa, NONE);
sa.aad.op = op,
sa.aad.fs.request = request;
sa.aad.name = name;
@@ -117,7 +117,7 @@ int aa_audit_file(struct aa_profile *profile, struct file_perms *perms,
sa.aad.error = error;
if (likely(!sa.aad.error)) {
- u16 mask = perms->audit;
+ u32 mask = perms->audit;
if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
mask = 0xffff;
@@ -155,9 +155,9 @@ int aa_audit_file(struct aa_profile *profile, struct file_perms *perms,
*
* Returns: new permission mapping
*/
-static u16 map_old_perms(u32 old)
+static u32 map_old_perms(u32 old)
{
- u16 new = old & 0xf;
+ u32 new = old & 0xf;
if (old & MAY_READ)
new |= AA_MAY_META_READ;
if (old & MAY_WRITE)
@@ -173,6 +173,8 @@ static u16 map_old_perms(u32 old)
if (old & 0x40) /* AA_EXEC_MMAP */
new |= AA_EXEC_MMAP;
+ new |= AA_MAY_META_READ;
+
return new;
}
@@ -198,7 +200,6 @@ static struct file_perms compute_perms(struct aa_dfa *dfa, unsigned int state,
* done at profile load
*/
perms.kill = 0;
- perms.dindex = 0;
if (current_fsuid() == cond->uid) {
perms.allow = map_old_perms(dfa_user_allow(dfa, state));
@@ -221,7 +222,7 @@ static struct file_perms compute_perms(struct aa_dfa *dfa, unsigned int state,
/**
* aa_str_perms - find permission that match @name
- * @dfa: to match against (NOT NULL)
+ * @dfa: to match against (MAYBE NULL)
* @state: state to start matching in
* @name: string to match against dfa (NOT NULL)
* @cond: conditions to consider for permission set computation (NOT NULL)
@@ -246,33 +247,6 @@ unsigned int aa_str_perms(struct aa_dfa *dfa, unsigned int start,
}
/**
- * aa_pathstr_perm - do permission check & audit for @name
- * @op: operation being checked
- * @profile: profile being enforced (NOT NULL)
- * @name: path string to check permission for (NOT NULL)
- * @request: requested permissions
- * @cond: conditional info for this request (NOT NULL)
- *
- * Do permission check for paths that are predefined. This fn will
- * be removed once security_sysctl goes away.
- *
- * Returns: %0 else error if access denied or other error
- */
-int aa_pathstr_perm(int op, struct aa_profile *profile, const char *name,
- u16 request, struct path_cond *cond)
-{
- struct file_perms perms = { };
- int error = 0;
-
- aa_str_perms(profile->file.dfa, profile->file.start, name, cond,
- &perms);
- if (request & ~perms.allow)
- error = -EACCES;
- return aa_audit_file(profile, &perms, GFP_KERNEL, op, request, name,
- NULL, cond->uid, NULL, error);
-}
-
-/**
* is_deleted - test if a file has been completely unlinked
* @dentry: dentry of file to test for deletion (NOT NULL)
*
@@ -297,7 +271,7 @@ static inline bool is_deleted(struct dentry *dentry)
* Returns: %0 else error if access denied or other error
*/
int aa_path_perm(int op, struct aa_profile *profile, struct path *path,
- int flags, u16 request, struct path_cond *cond)
+ int flags, u32 request, struct path_cond *cond)
{
char *buffer = NULL;
struct file_perms perms = {};
@@ -345,7 +319,7 @@ int aa_path_perm(int op, struct aa_profile *profile, struct path *path,
*
* Returns: %1 if subset else %0
*/
-static inline bool xindex_is_subset(u16 link, u16 target)
+static inline bool xindex_is_subset(u32 link, u32 target)
{
if (((link & ~AA_X_UNSAFE) != (target & ~AA_X_UNSAFE)) ||
((link & AA_X_UNSAFE) && !(target & AA_X_UNSAFE)))
@@ -384,7 +358,7 @@ int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry,
char *buffer = NULL, *buffer2 = NULL;
const char *lname, *tname = NULL, *info = NULL;
struct file_perms lperms, perms;
- u16 request = AA_MAY_LINK;
+ u32 request = AA_MAY_LINK;
unsigned int state;
int error;
@@ -409,8 +383,7 @@ int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry,
goto audit;
/* test to see if target can be paired with link */
- state = aa_dfa_null_transition(profile->file.dfa, state,
- profile->flags & PFLAG_OLD_NULL_TRANS);
+ state = aa_dfa_null_transition(profile->file.dfa, state);
aa_str_perms(profile->file.dfa, state, tname, &cond, &perms);
/* force audit/quiet masks for link are stored in the second entry
@@ -472,7 +445,7 @@ audit:
* Returns: %0 if access allowed else error
*/
int aa_file_perm(int op, struct aa_profile *profile, struct file *file,
- u16 request)
+ u32 request)
{
struct path_cond cond = {
.uid = file->f_path.dentry->d_inode->i_uid,
diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
index 25c16470ac8..c51e551ec1a 100644
--- a/security/apparmor/include/apparmor.h
+++ b/security/apparmor/include/apparmor.h
@@ -48,30 +48,41 @@ extern unsigned int aa_g_path_max;
/* Flag indicating whether initialization completed */
extern int apparmor_initialized;
-void apparmor_disable(void);
/* fn's in lib */
char *aa_split_fqname(char *args, char **ns_name);
-bool aa_strneq(const char *str, const char *sub, int len);
void aa_info_message(const char *str);
+void *kvmalloc(size_t size);
+void kvfree(void *buffer);
+
+
+/**
+ * aa_strneq - compare null terminated @str to a non null terminated substring
+ * @str: a null terminated string
+ * @sub: a substring, not necessarily null terminated
+ * @len: length of @sub to compare
+ *
+ * The @str string must be full consumed for this to be considered a match
+ */
+static inline bool aa_strneq(const char *str, const char *sub, int len)
+{
+ return !strncmp(str, sub, len) && !str[len];
+}
/**
* aa_dfa_null_transition - step to next state after null character
* @dfa: the dfa to match against
* @start: the state of the dfa to start matching in
- * @old: true if using // as the null transition
*
* aa_dfa_null_transition transitions to the next state after a null
* character which is not used in standard matching and is only
* used to seperate pairs.
*/
static inline unsigned int aa_dfa_null_transition(struct aa_dfa *dfa,
- unsigned int start, bool old)
+ unsigned int start)
{
- if (unlikely(old))
- return aa_dfa_match_len(dfa, start, "//", 2);
- else
- return aa_dfa_match_len(dfa, start, "\0", 1);
+ /* the null transition only needs a single null byte of the string */
+ return aa_dfa_match_len(dfa, start, "", 1);
}
static inline bool mediated_filesystem(struct inode *inode)
diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h
index ba6652f0aac..cfbae70b7cb 100644
--- a/security/apparmor/include/apparmorfs.h
+++ b/security/apparmor/include/apparmorfs.h
@@ -15,15 +15,6 @@
#ifndef __AA_APPARMORFS_H
#define __AA_APPARMORFS_H
-extern struct dentry *aa_fs_null;
-extern struct vfsmount *aa_fs_mnt;
-
extern void aa_destroy_aafs(void);
-#ifdef CONFIG_SECURITY_APPARMOR_COMPAT_24
-extern const struct file_operations aa_fs_matching_fops;
-extern const struct file_operations aa_fs_features_fops;
-extern const struct file_operations aa_fs_profiles_fops;
-#endif
-
#endif /* __AA_APPARMORFS_H */
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
index 24cdfe836b4..1951786d32e 100644
--- a/security/apparmor/include/audit.h
+++ b/security/apparmor/include/audit.h
@@ -107,6 +107,8 @@ enum aa_ops {
/* define a short hand for apparmor_audit_data portion of common_audit_data */
#define aad apparmor_audit_data
+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,
void (*cb) (struct audit_buffer *, void *));
@@ -118,10 +120,4 @@ static inline int complain_error(int error)
return error;
}
-#define COMMON_AUDIT_DATA_INIT_NONE(_d) \
- do { \
- memset((_d), 0, sizeof(struct common_audit_data)); \
- (_d)->type = LSM_AUDIT_DATA_NONE; \
- } while (0)
-
#endif /* __AA_AUDIT_H */
diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h
index b1ba488cf82..de04464f0a3 100644
--- a/security/apparmor/include/domain.h
+++ b/security/apparmor/include/domain.h
@@ -30,7 +30,7 @@ void apparmor_bprm_committed_creds(struct linux_binprm *bprm);
void aa_free_domain_entries(struct aa_domain *domain);
int aa_change_hat(const char *hats[], int count, u64 token, bool permtest);
-int aa_change_profile(const char *ns_name, const char *name, int onexec,
+int aa_change_profile(const char *ns_name, const char *name, bool onexec,
bool permtest);
#endif /* __AA_DOMAIN_H */
diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h
index dc79248272f..bba5ced35bd 100644
--- a/security/apparmor/include/file.h
+++ b/security/apparmor/include/file.h
@@ -35,12 +35,12 @@ struct aa_profile;
#define AA_MAY_CHOWN 0x0200
#define AA_MAY_LOCK 0x0400
#define AA_EXEC_MMAP 0x0800
-
+
#define AA_MAY_LINK 0x1000
-#define AA_MAY_ONEXEC 0x4000 /* exec allows onexec */
-#define AA_MAY_CHANGE_PROFILE 0x8000
#define AA_LINK_SUBSET AA_MAY_LOCK /* overlayed */
-#define AA_MAY_CHANGEHAT 0x8000 /* ctrl auditing only */
+#define AA_MAY_ONEXEC 0x40000000 /* exec allows onexec */
+#define AA_MAY_CHANGE_PROFILE 0x80000000
+#define AA_MAY_CHANGEHAT 0x80000000 /* ctrl auditing only */
#define AA_AUDIT_FILE_MASK (MAY_READ | MAY_WRITE | MAY_EXEC | MAY_APPEND |\
AA_MAY_CREATE | AA_MAY_DELETE | \
@@ -82,19 +82,15 @@ struct path_cond {
* @quiet: mask of permissions to quiet audit messages for
* @kill: mask of permissions that when matched will kill the task
* @xindex: exec transition index if @allow contains MAY_EXEC
- * @xdelegate: used by exec to determine set of delegates allowed
- * @dindex: delegate table index, 0 if no delegation allowed
*
* The @audit and @queit mask should be mutually exclusive.
*/
struct file_perms {
- u16 allow;
- u16 audit;
- u16 quiet;
- u16 kill;
+ u32 allow;
+ u32 audit;
+ u32 quiet;
+ u32 kill;
u16 xindex;
- u16 xdelegate;
- u16 dindex;
};
extern struct file_perms nullperms;
@@ -134,15 +130,15 @@ static inline u16 dfa_map_xindex(u16 mask)
* map old dfa inline permissions to new format
*/
#define dfa_user_allow(dfa, state) (((ACCEPT_TABLE(dfa)[state]) & 0x7f) | \
- ((ACCEPT_TABLE(dfa)[state]) & 0x80000000))
+ ((ACCEPT_TABLE(dfa)[state]) & 0x80000000))
#define dfa_user_audit(dfa, state) ((ACCEPT_TABLE2(dfa)[state]) & 0x7f)
#define dfa_user_quiet(dfa, state) (((ACCEPT_TABLE2(dfa)[state]) >> 7) & 0x7f)
#define dfa_user_xindex(dfa, state) \
(dfa_map_xindex(ACCEPT_TABLE(dfa)[state] & 0x3fff))
#define dfa_other_allow(dfa, state) ((((ACCEPT_TABLE(dfa)[state]) >> 14) & \
- 0x7f) | \
- ((ACCEPT_TABLE(dfa)[state]) & 0x80000000))
+ 0x7f) | \
+ ((ACCEPT_TABLE(dfa)[state]) & 0x80000000))
#define dfa_other_audit(dfa, state) (((ACCEPT_TABLE2(dfa)[state]) >> 14) & 0x7f)
#define dfa_other_quiet(dfa, state) \
((((ACCEPT_TABLE2(dfa)[state]) >> 7) >> 14) & 0x7f)
@@ -150,7 +146,7 @@ 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, u16 request, const char *name,
+ gfp_t gfp, int op, u32 request, const char *name,
const char *target, uid_t ouid, const char *info, int error);
/**
@@ -176,17 +172,14 @@ 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_pathstr_perm(int op, struct aa_profile *profile, const char *name,
- u16 request, struct path_cond *cond);
-
int aa_path_perm(int op, struct aa_profile *profile, struct path *path,
- int flags, u16 request, struct path_cond *cond);
+ int flags, u32 request, struct path_cond *cond);
int aa_path_link(struct aa_profile *profile, 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,
- u16 request);
+ u32 request);
static inline void aa_free_file_rules(struct aa_file_rules *rules)
{
@@ -205,10 +198,10 @@ static inline void aa_free_file_rules(struct aa_file_rules *rules)
*
* Returns: apparmor permission set for the file
*/
-static inline u16 aa_map_file_to_perms(struct file *file)
+static inline u32 aa_map_file_to_perms(struct file *file)
{
int flags = MAP_OPEN_FLAGS(file->f_flags);
- u16 perms = ACC_FMODE(file->f_mode);
+ u32 perms = ACC_FMODE(file->f_mode);
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 cdc5e2cf633..3cd089f7536 100644
--- a/security/apparmor/include/match.h
+++ b/security/apparmor/include/match.h
@@ -110,13 +110,6 @@ static inline size_t table_size(size_t len, size_t el_size)
return ALIGN(sizeof(struct table_header) + len * el_size, 8);
}
-static inline size_t table_alloc_size(size_t size)
-{
- if (size > sizeof(struct work_struct))
- return size;
- return sizeof(struct work_struct);
-}
-
struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags);
unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start,
const char *str, int len);
diff --git a/security/apparmor/include/path.h b/security/apparmor/include/path.h
index 746a322d830..27b327a7fae 100644
--- a/security/apparmor/include/path.h
+++ b/security/apparmor/include/path.h
@@ -27,6 +27,5 @@ enum path_flags {
};
int aa_get_name(struct path *path, int flags, char **buffer, const char **name);
-char *sysctl_pathname(struct ctl_table *table, char *buffer, int buflen);
#endif /* __AA_PATH_H */
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
index 94ca559b472..7d757b8f59d 100644
--- a/security/apparmor/include/policy.h
+++ b/security/apparmor/include/policy.h
@@ -27,22 +27,20 @@
#include "capability.h"
#include "domain.h"
#include "file.h"
-#include "net.h"
#include "resource.h"
extern const char *profile_mode_names[];
#define APPARMOR_NAMES_MAX_INDEX 3
-#define COMPLAIN_MODE(_profile) \
- ((aa_g_profile_mode == APPARMOR_COMPLAIN) || ((_profile) && \
- (_profile)->mode == APPARMOR_COMPLAIN))
+#define COMPLAIN_MODE(_profile) \
+ ((aa_g_profile_mode == APPARMOR_COMPLAIN) || \
+ ((_profile)->mode == APPARMOR_COMPLAIN))
-#define DO_KILL(_profile) \
- ((aa_g_profile_mode == APPARMOR_KILL) || ((_profile) && \
- (_profile)->mode == APPARMOR_KILL))
+#define KILL_MODE(_profile) \
+ ((aa_g_profile_mode == APPARMOR_KILL) || \
+ ((_profile)->mode == APPARMOR_KILL))
-#define PROFILE_IS_HAT(_profile) \
- ((_profile) && (_profile)->flags & PFLAG_HAT)
+#define PROFILE_IS_HAT(_profile) ((_profile)->flags & PFLAG_HAT)
/*
* FIXME: currently need a clean way to replace and remove profiles as a
@@ -64,7 +62,6 @@ enum profile_flags {
PFLAG_IMMUTABLE = 0x10, /* don't allow changes/replacement */
PFLAG_USER_DEFINED = 0x20, /* user based profile */
PFLAG_NO_LIST_REF = 0x40, /* list doesn't keep profile ref */
- PFLAG_MMAP_MIN_ADDR = 0x80, /* profile controls mmap_min_addr */
PFLAG_OLD_NULL_TRANS = 0x100, /* use // as the null transition */
/* These flags must coorespond with PATH_flags */
@@ -149,7 +146,6 @@ struct aa_namespace {
* @size: the memory consumed by this profiles rules
* @file: The set of rules governing basic file access and domain transitions
* @caps: capabilities for the profile
- * @net: network controls for the profile
* @rlimits: rlimits for the profile
*
* The AppArmor profile contains the basic confinement data. Each profile
@@ -184,11 +180,8 @@ struct aa_profile {
u32 path_flags;
int size;
- unsigned long mmap_min_addr;
-
struct aa_file_rules file;
struct aa_caps caps;
- struct aa_net net;
struct aa_rlimit rlimits;
};
@@ -197,7 +190,7 @@ extern enum profile_mode aa_g_profile_mode;
void aa_add_profile(struct aa_policy *common, struct aa_profile *profile);
-bool aa_ns_visible(struct aa_namespace *parent, struct aa_namespace *child);
+bool aa_ns_visible(struct aa_namespace *curr, struct aa_namespace *view);
const char *aa_ns_name(struct aa_namespace *parent, struct aa_namespace *child);
int aa_alloc_root_ns(void);
void aa_free_root_ns(void);
@@ -270,7 +263,8 @@ ssize_t aa_remove_profiles(char *name, size_t size);
static inline struct aa_profile *aa_newest_version(struct aa_profile *profile)
{
if (unlikely(profile && profile->replacedby))
- for (; profile->replacedby; profile = profile->replacedby) ;
+ for (; profile->replacedby; profile = profile->replacedby)
+ ;
return profile;
}
@@ -304,9 +298,8 @@ static inline int AUDIT_MODE(struct aa_profile *profile)
{
if (aa_g_audit != AUDIT_NORMAL)
return aa_g_audit;
- if (profile)
- return profile->audit;
- return AUDIT_NORMAL;
+
+ return profile->audit;
}
bool aa_may_manage_policy(int op);
diff --git a/security/apparmor/include/procattr.h b/security/apparmor/include/procattr.h
index 6c6f271ae80..88025222cd7 100644
--- a/security/apparmor/include/procattr.h
+++ b/security/apparmor/include/procattr.h
@@ -20,7 +20,7 @@
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, int onexec, 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/ipc.c b/security/apparmor/ipc.c
index d667f89bb24..9013a78a166 100644
--- a/security/apparmor/ipc.c
+++ b/security/apparmor/ipc.c
@@ -40,7 +40,7 @@ static int aa_audit_ptrace(struct aa_profile *profile,
struct aa_profile *target, int error)
{
struct common_audit_data sa;
- COMMON_AUDIT_DATA_INIT_NONE(&sa);
+ COMMON_AUDIT_DATA_INIT(&sa, NONE);
sa.aad.op = OP_PTRACE;
sa.aad.target = target;
sa.aad.error = error;
@@ -66,7 +66,7 @@ int aa_may_ptrace(struct task_struct *tracer_task, struct aa_profile *tracer,
* Test mode for PTRACE_MODE_READ || PTRACE_MODE_ATTACH
*/
- if (!tracer || tracer == tracee)
+ if (unconfined(tracer) || tracer == tracee)
return 0;
/* log this capability request */
return aa_capable(tracer_task, tracer, CAP_SYS_PTRACE, 1);
@@ -74,8 +74,8 @@ int aa_may_ptrace(struct task_struct *tracer_task, struct aa_profile *tracer,
/**
* aa_ptrace - do ptrace permission check and auditing
- * @tracer: task doing the tracing
- * @tracee: task being traced
+ * @tracer: task doing the tracing (NOT NULL)
+ * @tracee: task being traced (NOT NULL)
* @mode: ptrace mode either PTRACE_MODE_READ || PTRACE_MODE_ATTACH
*
* Returns: %0 else error code if permission denied or error
diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c
index 035d8ee3268..51837b5a10a 100644
--- a/security/apparmor/lib.c
+++ b/security/apparmor/lib.c
@@ -14,14 +14,15 @@
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/vmalloc.h>
#include "include/audit.h"
/**
* aa_split_fqname - split a fqname into a profile and namespace name
- * @fqname: a full qualified name in namespace profile format
- * @ns_name: pointer to portion of the string containing the ns name
+ * @fqname: a full qualified name in namespace profile format (NOT NULL)
+ * @ns_name: pointer to portion of the string containing the ns name (NOT NULL)
*
* Returns: profile name or NULL if one is not specified
*
@@ -55,30 +56,75 @@ char *aa_split_fqname(char *fqname, char **ns_name)
}
/**
- * aa_strneq - compare null terminated @str to a non null terminated substring
- * @str: a null terminated string
- * @sub: a substring, not necessarily null terminated
- * @len: length of @sub to compare
+ * aa_info_message - log a none profile related status message
+ * @str: message to log
+ */
+void aa_info_message(const char *str)
+{
+ if (audit_enabled) {
+ struct common_audit_data sa;
+ COMMON_AUDIT_DATA_INIT(&sa, NONE);
+ sa.aad.info = str;
+ printk(KERN_INFO "AppArmor: %s\n", str);
+ aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL);
+ }
+}
+
+/**
+ * kvmalloc - do allocation prefering kmalloc but falling back to vmalloc
+ * @size: size of allocation
+ *
+ * Return: allocated buffer or NULL if failed
*
- * The @str string must be full consumed for this to be considered a match
+ * 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.
*/
-bool aa_strneq(const char *str, const char *sub, int len)
+void *kvmalloc(size_t size)
{
- int res = strncmp(str, sub, len);
- if (res)
- return 0;
- if (str[len] == 0)
- return 1;
- return 0;
+ void *buffer = NULL;
+
+ if (size == 0)
+ return NULL;
+
+ /* 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);
+ if (!buffer) {
+ if (size < sizeof(struct work_struct))
+ size = sizeof(struct work_struct);
+ buffer = vmalloc(size);
+ }
+ return buffer;
}
-void aa_info_message(const char *str)
+/**
+ * do_vfree - workqueue routine for freeing vmalloced memory
+ * @work: data to be freed
+ *
+ * The work_struct is overlayed to the data being freed, as at the point
+ * the work is scheduled the data is no longer valid, be its freeing
+ * needs to be delayed until safe.
+ */
+static void do_vfree(struct work_struct *work)
{
- struct common_audit_data sa;
- COMMON_AUDIT_DATA_INIT_NONE(&sa);
- sa.aad.info = str,
- printk(KERN_INFO "AppArmor: %s\n", str);
- if (audit_enabled)
- aa_audit(AUDIT_APPARMOR_STATUS, NULL, GFP_KERNEL, &sa, NULL);
+ vfree(work);
}
+/**
+ * kvfree - free an allocation do by kvmalloc
+ * @buffer: buffer to free (MAYBE_NULL)
+ *
+ * Free a buffer allocated by kvmalloc
+ */
+void kvfree(void *buffer)
+{
+ if (is_vmalloc_addr(buffer)) {
+ /* Data is no longer valid so just use the allocated space
+ * as the work_struct
+ */
+ struct work_struct *work = (struct work_struct *) buffer;
+ INIT_WORK(work, do_vfree);
+ schedule_work(work);
+ } else
+ kfree(buffer);
+}
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 5e3f180ac2b..b4828d74a1d 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -31,7 +31,6 @@
#include "include/context.h"
#include "include/file.h"
#include "include/ipc.h"
-#include "include/net.h"
#include "include/path.h"
#include "include/policy.h"
#include "include/procattr.h"
@@ -96,17 +95,19 @@ static void apparmor_cred_transfer(struct cred *new, const struct cred *old)
static int apparmor_ptrace_access_check(struct task_struct *child,
unsigned int mode)
{
- int rc;
-
- rc = cap_ptrace_access_check(child, mode);
- if (rc)
- return rc;
+ int error = cap_ptrace_access_check(child, mode);
+ if (error)
+ return error;
return aa_ptrace(current, child, mode);
}
static int apparmor_ptrace_traceme(struct task_struct *parent)
{
+ int error = cap_ptrace_traceme(parent);
+ if (error)
+ return error;
+
return aa_ptrace(parent, current, PTRACE_MODE_ATTACH);
}
@@ -125,8 +126,10 @@ static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective,
*inheritable = cred->cap_inheritable;
*permitted = cred->cap_permitted;
- if (!unconfined(profile))
+ if (!unconfined(profile)) {
*effective = cap_intersect(*effective, profile->caps.allow);
+ *permitted = cap_intersect(*permitted, profile->caps.allow);
+ }
rcu_read_unlock();
return 0;
@@ -138,51 +141,11 @@ static int apparmor_capable(struct task_struct *task, const struct cred *cred,
struct aa_profile *profile;
/* cap_capable returns 0 on success, else -EPERM */
int error = cap_capable(task, cred, cap, audit);
-
- profile = aa_cred_profile(cred);
- if (!error && !unconfined(profile))
- error = aa_capable(task, profile, cap, audit);
-
- return error;
-}
-
-static int apparmor_sysctl(struct ctl_table *table, int sysctl_op)
-{
- int error = 0;
- struct aa_profile *profile = aa_current_profile();
-
- if (!unconfined(profile)) {
- char *buffer, *name;
- int mask;
-
- mask = 0;
- if (sysctl_op & 4)
- mask |= MAY_READ;
- if (sysctl_op & 2)
- mask |= MAY_WRITE;
-
- error = -ENOMEM;
- /* freed below */
- buffer = (char *)__get_free_page(GFP_KERNEL);
- if (!buffer)
- goto out;
-
- /*
- * TODO: convert this over to using a global or per
- * namespace control instead of a hard coded /proc
- */
- name = sysctl_pathname(table, buffer, PAGE_SIZE);
- if (name && name - buffer >= 5) {
- struct path_cond cond = { 0, S_IFREG };
- name -= 5;
- memcpy(name, "/proc", 5);
- error = aa_pathstr_perm(OP_SYSCTL, profile, name, mask,
- &cond);
- }
- free_page((unsigned long)buffer);
+ if (!error) {
+ profile = aa_cred_profile(cred);
+ if (!unconfined(profile))
+ error = aa_capable(task, profile, cap, audit);
}
-
-out:
return error;
}
@@ -195,7 +158,7 @@ out:
*
* Returns: %0 else error code if error or permission denied
*/
-static int common_perm(int op, struct path *path, u16 mask,
+static int common_perm(int op, struct path *path, u32 mask,
struct path_cond *cond)
{
struct aa_profile *profile;
@@ -219,7 +182,7 @@ static int common_perm(int op, struct path *path, u16 mask,
* Returns: %0 else error code if error or permission denied
*/
static int common_perm_dir_dentry(int op, struct path *dir,
- struct dentry *dentry, u16 mask,
+ struct dentry *dentry, u32 mask,
struct path_cond *cond)
{
struct path path = { dir->mnt, dentry };
@@ -230,14 +193,14 @@ static int common_perm_dir_dentry(int op, struct path *dir,
/**
* common_perm_mnt_dentry - common permission wrapper when mnt, dentry
* @op: operation being checked
- * @mnt: mount point of dentry
+ * @mnt: mount point of dentry (NOT NULL)
* @dentry: dentry to check (NOT NULL)
* @mask: requested permissions mask
*
* Returns: %0 else error code if error or permission denied
*/
static int common_perm_mnt_dentry(int op, struct vfsmount *mnt,
- struct dentry *dentry, u16 mask)
+ struct dentry *dentry, u32 mask)
{
struct path path = { mnt, dentry };
struct path_cond cond = { dentry->d_inode->i_uid,
@@ -257,7 +220,7 @@ static int common_perm_mnt_dentry(int op, struct vfsmount *mnt,
* Returns: %0 else error code if error or permission denied
*/
static int common_perm_rm(int op, struct path *dir,
- struct dentry *dentry, u16 mask)
+ struct dentry *dentry, u32 mask)
{
struct inode *inode = dentry->d_inode;
struct path_cond cond = { };
@@ -282,7 +245,7 @@ static int common_perm_rm(int op, struct path *dir,
* Returns: %0 else error code if error or permission denied
*/
static int common_perm_create(int op, struct path *dir, struct dentry *dentry,
- u16 mask, umode_t mode)
+ u32 mask, umode_t mode)
{
struct path_cond cond = { current_fsuid(), mode };
@@ -461,7 +424,7 @@ static void apparmor_file_free_security(struct file *file)
aa_free_file_context(cxt);
}
-static int common_file_perm(int op, struct file *file, u16 mask)
+static int common_file_perm(int op, struct file *file, u32 mask)
{
struct aa_file_cxt *fcxt = file->f_security;
struct aa_profile *profile, *fprofile = aa_cred_profile(file->f_cred);
@@ -496,7 +459,7 @@ static int apparmor_file_permission(struct file *file, int mask)
static int apparmor_file_lock(struct file *file, unsigned int cmd)
{
- u16 mask = AA_MAY_LOCK;
+ u32 mask = AA_MAY_LOCK;
if (cmd == F_WRLCK)
mask |= MAY_WRITE;
@@ -579,19 +542,27 @@ 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)
{
- char *command, *args;
+ char *command, *args = value;
size_t arg_size;
int error;
- if (size == 0 || size >= PAGE_SIZE)
+ if (size == 0)
return -EINVAL;
+ /* args points to a PAGE_SIZE buffer, AppArmor requires that
+ * the buffer must be null terminated or have size <= PAGE_SIZE -1
+ * so that AppArmor can null terminate them
+ */
+ if (args[size - 1] != '\0') {
+ if (size == PAGE_SIZE)
+ return -EINVAL;
+ args[size] = '\0';
+ }
/* task can only write its own attributes */
if (current != task)
return -EACCES;
args = value;
- args[size] = '\0';
args = strim(args);
command = strsep(&args, " ");
if (!args)
@@ -618,7 +589,7 @@ static int apparmor_setprocattr(struct task_struct *task, char *name,
error = aa_setprocattr_permipc(args);
} else {
struct common_audit_data sa;
- COMMON_AUDIT_DATA_INIT_NONE(&sa);
+ COMMON_AUDIT_DATA_INIT(&sa, NONE);
sa.aad.op = OP_SETPROCATTR;
sa.aad.info = name;
sa.aad.error = -EINVAL;
@@ -649,111 +620,12 @@ static int apparmor_task_setrlimit(unsigned int resource,
return error;
}
-static int apparmor_socket_create(int family, int type, int protocol, int kern)
-{
- struct aa_profile *profile;
- int error = 0;
-
- if (kern)
- return 0;
-
- profile = __aa_current_profile();
- if (!unconfined(profile))
- error = aa_net_perm(OP_CREATE, profile, family, type, protocol,
- NULL);
- return error;
-}
-
-static int apparmor_socket_bind(struct socket *sock,
- struct sockaddr *address, int addrlen)
-{
- struct sock *sk = sock->sk;
-
- return aa_revalidate_sk(OP_BIND, sk);
-}
-
-static int apparmor_socket_connect(struct socket *sock,
- struct sockaddr *address, int addrlen)
-{
- struct sock *sk = sock->sk;
-
- return aa_revalidate_sk(OP_CONNECT, sk);
-}
-
-static int apparmor_socket_listen(struct socket *sock, int backlog)
-{
- struct sock *sk = sock->sk;
-
- return aa_revalidate_sk(OP_LISTEN, sk);
-}
-
-static int apparmor_socket_accept(struct socket *sock, struct socket *newsock)
-{
- struct sock *sk = sock->sk;
-
- return aa_revalidate_sk(OP_ACCEPT, sk);
-}
-
-static int apparmor_socket_sendmsg(struct socket *sock,
- struct msghdr *msg, int size)
-{
- struct sock *sk = sock->sk;
-
- return aa_revalidate_sk(OP_SENDMSG, sk);
-}
-
-static int apparmor_socket_recvmsg(struct socket *sock,
- struct msghdr *msg, int size, int flags)
-{
- struct sock *sk = sock->sk;
-
- return aa_revalidate_sk(OP_RECVMSG, sk);
-}
-
-static int apparmor_socket_getsockname(struct socket *sock)
-{
- struct sock *sk = sock->sk;
-
- return aa_revalidate_sk(OP_GETSOCKNAME, sk);
-}
-
-static int apparmor_socket_getpeername(struct socket *sock)
-{
- struct sock *sk = sock->sk;
-
- return aa_revalidate_sk(OP_GETPEERNAME, sk);
-}
-
-static int apparmor_socket_getsockopt(struct socket *sock, int level,
- int optname)
-{
- struct sock *sk = sock->sk;
-
- return aa_revalidate_sk(OP_GETSOCKOPT, sk);
-}
-
-static int apparmor_socket_setsockopt(struct socket *sock, int level,
- int optname)
-{
- struct sock *sk = sock->sk;
-
- return aa_revalidate_sk(OP_SETSOCKOPT, sk);
-}
-
-static int apparmor_socket_shutdown(struct socket *sock, int how)
-{
- struct sock *sk = sock->sk;
-
- return aa_revalidate_sk(OP_SOCK_SHUTDOWN, sk);
-}
-
static struct security_operations apparmor_ops = {
.name = "apparmor",
.ptrace_access_check = apparmor_ptrace_access_check,
.ptrace_traceme = apparmor_ptrace_traceme,
.capget = apparmor_capget,
- .sysctl = apparmor_sysctl,
.capable = apparmor_capable,
.path_link = apparmor_path_link,
@@ -779,19 +651,6 @@ static struct security_operations apparmor_ops = {
.getprocattr = apparmor_getprocattr,
.setprocattr = apparmor_setprocattr,
- .socket_create = apparmor_socket_create,
- .socket_bind = apparmor_socket_bind,
- .socket_connect = apparmor_socket_connect,
- .socket_listen = apparmor_socket_listen,
- .socket_accept = apparmor_socket_accept,
- .socket_sendmsg = apparmor_socket_sendmsg,
- .socket_recvmsg = apparmor_socket_recvmsg,
- .socket_getsockname = apparmor_socket_getsockname,
- .socket_getpeername = apparmor_socket_getpeername,
- .socket_getsockopt = apparmor_socket_getsockopt,
- .socket_setsockopt = apparmor_socket_setsockopt,
- .socket_shutdown = apparmor_socket_shutdown,
-
.cred_alloc_blank = apparmor_cred_alloc_blank,
.cred_free = apparmor_cred_free,
.cred_prepare = apparmor_cred_prepare,
@@ -850,7 +709,7 @@ module_param_call(audit, param_set_audit, param_get_audit,
/* Determines if audit header is included in audited messages. This
* provides more context if the audit daemon is not running
*/
-int aa_g_audit_header;
+int aa_g_audit_header = 1;
module_param_named(audit_header, aa_g_audit_header, aabool,
S_IRUSR | S_IWUSR);
@@ -1032,7 +891,7 @@ static int __init apparmor_init(void)
int error;
if (!apparmor_enabled || !security_module_enable(&apparmor_ops)) {
- aa_info_message("AppArmor disabled by boot time parameter\n");
+ aa_info_message("AppArmor disabled by boot time parameter");
apparmor_enabled = 0;
return 0;
}
diff --git a/security/apparmor/match.c b/security/apparmor/match.c
index e4bddf6dea1..8e7523ab392 100644
--- a/security/apparmor/match.c
+++ b/security/apparmor/match.c
@@ -20,55 +20,22 @@
#include <linux/err.h>
#include <linux/kref.h>
+#include "include/apparmor.h"
#include "include/match.h"
/**
- * do_vfree - workqueue routine for freeing vmalloced memory
- * @work: data to be freed
- *
- * The work_struct is overlayed to the data being freed, as at the point
- * the work is scheduled the data is no longer valid, be its freeing
- * needs to be delayed until safe.
- */
-static void do_vfree(struct work_struct *work)
-{
- vfree(work);
-}
-
-/**
- * free_table - free a table allocated by unpack table
- * @table: table to unpack (MAYBE NULL)
- */
-static void free_table(struct table_header *table)
-{
- if (!table)
- return;
-
- if (is_vmalloc_addr(table)) {
- /* Data is no longer valid so just use the allocated space
- * as the work_struct
- */
- struct work_struct *work = (struct work_struct *) table;
- INIT_WORK(work, do_vfree);
- schedule_work(work);
- } else
- kzfree(table);
-}
-
-/**
* unpack_table - unpack a dfa table (one of accept, default, base, next check)
- * @blob: data to unpack
+ * @blob: data to unpack (NOT NULL)
* @bsize: size of blob
*
* Returns: pointer to table else NULL on failure
*
- * NOTE: must be freed by free_table (not kmalloc)
+ * NOTE: must be freed by kvfree (not kmalloc)
*/
static struct table_header *unpack_table(char *blob, size_t bsize)
{
struct table_header *table = NULL;
struct table_header th;
- int unmap_alias = 0;
size_t tsize;
if (bsize < sizeof(struct table_header))
@@ -90,13 +57,7 @@ static struct table_header *unpack_table(char *blob, size_t bsize)
if (bsize < tsize)
goto out;
- /* freed by free_table */
- table = kmalloc(table_alloc_size(tsize), GFP_KERNEL | __GFP_NOWARN);
- if (!table) {
- table = vmalloc(tsize);
- if (table)
- unmap_alias = 1;
- }
+ table = kvmalloc(tsize);
if (table) {
*table = th;
if (th.td_flags == YYTD_DATA8)
@@ -113,17 +74,19 @@ static struct table_header *unpack_table(char *blob, size_t bsize)
}
out:
- if (unmap_alias)
+ /* if table was vmalloced make sure the page tables are synced
+ * before it is used, as it goes live to all cpus.
+ */
+ if (is_vmalloc_addr(table))
vm_unmap_aliases();
return table;
fail:
- free_table(table);
+ kvfree(table);
return NULL;
}
/**
- * verify_dfa - verify that all the transitions and states in the dfa tables
- * are in bounds.
+ * verify_dfa - verify that transitions and states in the tables are in bounds.
* @dfa: dfa to test (NOT NULL)
* @flags: flags controlling what type of accept table are acceptable
*
@@ -175,8 +138,11 @@ static int verify_dfa(struct aa_dfa *dfa, int flags)
if (DEFAULT_TABLE(dfa)[i] >= state_count)
goto out;
/* TODO: do check that DEF state recursion terminates */
- if (BASE_TABLE(dfa)[i] >= trans_count + 256)
+ if (BASE_TABLE(dfa)[i] + 255 >= trans_count) {
+ printk(KERN_ERR "AppArmor DFA next/check upper "
+ "bounds error\n");
goto out;
+ }
}
for (i = 0; i < trans_count; i++) {
@@ -204,11 +170,11 @@ static void dfa_free(struct aa_dfa *dfa)
int i;
for (i = 0; i < ARRAY_SIZE(dfa->tables); i++) {
- free_table(dfa->tables[i]);
+ kvfree(dfa->tables[i]);
dfa->tables[i] = NULL;
}
+ kfree(dfa);
}
- kfree(dfa);
}
/**
@@ -309,7 +275,7 @@ struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags)
return dfa;
fail:
- free_table(table);
+ kvfree(table);
dfa_free(dfa);
return ERR_PTR(error);
}
diff --git a/security/apparmor/path.c b/security/apparmor/path.c
index a360793d20a..a19ba058993 100644
--- a/security/apparmor/path.c
+++ b/security/apparmor/path.c
@@ -12,6 +12,7 @@
* License.
*/
+#include <linux/magic.h>
#include <linux/mnt_namespace.h>
#include <linux/mount.h>
#include <linux/namei.h>
@@ -25,12 +26,26 @@
#include "include/path.h"
#include "include/policy.h"
+
+/* modified from dcache.c */
+static int prepend(char **buffer, int buflen, const char *str, int namelen)
+{
+ buflen -= namelen;
+ if (buflen < 0)
+ return -ENAMETOOLONG;
+ *buffer -= namelen;
+ memcpy(*buffer, str, namelen);
+ return 0;
+}
+
+#define CHROOT_NSCONNECT (PATH_CHROOT_REL | PATH_CHROOT_NSCONNECT)
+
/**
* d_namespace_path - lookup a name associated with a given path
* @path: path to lookup (NOT NULL)
* @buf: buffer to store path to (NOT NULL)
* @buflen: length of @buf
- * @name: return pointer for start of path name with in @buf (NOT NULL)
+ * @name: Returns - pointer for start of path name with in @buf (NOT NULL)
* @flags: flags controling path lookup
*
* Handle path name lookup.
@@ -108,8 +123,9 @@ static int d_namespace_path(struct path *path, char *buf, int buflen,
/* Determine if the path is connected to the expected root */
connected = tmp.dentry == root.dentry && tmp.mnt == root.mnt;
- /* If the path is not connected, then remove any leading / that
- * __d_path may have returned.
+ /* If the path is not connected,
+ * check if it is a sysctl and handle specially else remove any
+ * leading / that __d_path may have returned.
* Unless
* specifically directed to connect the path,
* OR
@@ -118,15 +134,25 @@ static int d_namespace_path(struct path *path, char *buf, int buflen,
* of chroot) and specifically directed to connect paths to
* namespace root.
*/
- if (!connected &&
- !(flags & PATH_CONNECT_PATH) &&
- !((flags & PATH_CHROOT_REL) && (flags & PATH_CHROOT_NSCONNECT) &&
- (tmp.mnt == current->nsproxy->mnt_ns->root &&
- tmp.dentry == current->nsproxy->mnt_ns->root->mnt_root))) {
- /* disconnected path, don't return pathname starting with '/' */
- error = -ESTALE;
- if (*res == '/')
- *name = res + 1;
+ if (!connected) {
+ /* is the disconnect path a sysctl? */
+ if (tmp.dentry->d_sb->s_magic == PROC_SUPER_MAGIC &&
+ strncmp(*name, "/sys/", 5) == 0) {
+ /* TODO: convert over to using a per namespace
+ * control instead of hard coded /proc
+ */
+ error = prepend(name, *name - buf, "/proc", 5);
+ } else if (!(flags & PATH_CONNECT_PATH) &&
+ !(((flags & CHROOT_NSCONNECT) == CHROOT_NSCONNECT) &&
+ (tmp.mnt == current->nsproxy->mnt_ns->root &&
+ tmp.dentry == tmp.mnt->mnt_root))) {
+ /* disconnected path, don't return pathname starting
+ * with '/'
+ */
+ error = -ESTALE;
+ if (*res == '/')
+ *name = res + 1;
+ }
}
out:
@@ -141,7 +167,7 @@ out:
* @flags: flags controlling path lookup
* @buffer: buffer to put name in (NOT NULL)
* @size: size of buffer
- * @name: on return contains position of path name in @buffer (NOT NULL)
+ * @name: Returns - contains position of path name in @buffer (NOT NULL)
*
* Returns: %0 else error on failure
*/
@@ -166,7 +192,7 @@ static int get_name_to_buffer(struct path *path, int flags, char *buffer,
* @path: path the file (NOT NULL)
* @flags: flags controling path name generation
* @buffer: buffer that aa_get_name() allocated (NOT NULL)
- * @name: the generated path name if !error
+ * @name: Returns - the generated path name if !error (NOT NULL)
*
* @name is a pointer to the beginning of the pathname (which usually differs
* from the beginning of the buffer), or NULL. If there is an error @name
@@ -207,37 +233,3 @@ int aa_get_name(struct path *path, int flags, char **buffer, const char **name)
return error;
}
-
-/**
- * sysctl_pathname - generate a pathname for a sysctl
- * @table: sysctl name table (NOT NULL)
- * @buffer: buffer to put name in (NOT NULL)
- * @buflen: length of @buffer
- *
- * Returns: sysctl path name in @buffer or NULL on error
- */
-char *sysctl_pathname(struct ctl_table *table, char *buffer, int buflen)
-{
- if (buflen < 1)
- return NULL;
- buffer += --buflen;
- *buffer = '\0';
-
- while (table) {
- int namelen = strlen(table->procname);
-
- if (buflen < namelen + 1)
- return NULL;
- buflen -= namelen + 1;
- buffer -= namelen;
- memcpy(buffer, table->procname, namelen);
- *--buffer = '/';
- table = table->parent;
- }
- if (buflen < 4)
- return NULL;
- buffer -= 4;
- memcpy(buffer, "/sys", 4);
-
- return buffer;
-}
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index a0add9d9db3..7fecdf2d2df 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -130,7 +130,7 @@ static bool policy_init(struct aa_policy *policy, const char *prefix,
{
/* freed by policy_free */
if (prefix) {
- policy->hname = kmalloc(strlen(prefix) + strlen(name) +3,
+ policy->hname = kmalloc(strlen(prefix) + strlen(name) + 3,
GFP_KERNEL);
if (policy->hname)
sprintf(policy->hname, "%s//%s", prefix, name);
@@ -222,38 +222,45 @@ static struct aa_policy *__policy_strn_find(struct list_head *head,
static const char *hidden_ns_name = "---";
/**
- * aa_ns_visible - test if @child is visible from @parent
- * @parent: namespace to treat as the parent
- * @child: namespace to test if visible from @parent
+ * aa_ns_visible - test if @view is visible from @curr
+ * @curr: namespace to treat as the parent (NOT NULL)
+ * @view: namespace to test if visible from @curr (NOT NULL)
*
- * Returns: true if @child is visible from @parent else false
+ * Returns: true if @view is visible from @curr else false
*/
-bool aa_ns_visible(struct aa_namespace *parent, struct aa_namespace *child)
+bool aa_ns_visible(struct aa_namespace *curr, struct aa_namespace *view)
{
- if (parent == child)
+ if (curr == view)
return true;
- for ( ; child; child = child->parent) {
- if (child->parent == parent)
+ for ( ; view; view = view->parent) {
+ if (view->parent == curr)
return true;
}
return false;
}
-const char *aa_ns_name(struct aa_namespace *parent, struct aa_namespace *child)
+/**
+ * aa_na_name - Find the ns name to display for @view from @curr
+ * @curr - current namespace (NOT NULL)
+ * @view - namespace attempting to view (NOT NULL)
+ *
+ * Returns: name of @view visible from @curr
+ */
+const char *aa_ns_name(struct aa_namespace *curr, struct aa_namespace *view)
{
- /* if child == parent then the namespace name isn't displayed */
- if (parent == child)
+ /* if view == curr then the namespace name isn't displayed */
+ if (curr == view)
return "";
- if (aa_ns_visible(parent, child)) {
- /* at this point if a ns is visible it is in a child ns
- * thus the parent ns.hname is a prefix of its name.
+ if (aa_ns_visible(curr, view)) {
+ /* at this point if a ns is visible it is in a view ns
+ * thus the curr ns.hname is a prefix of its name.
* Only output the virtualized portion of the name
- * Add + 2 to skip over // seperating parent hname prefix
- * from the visible tail of the childs hname
+ * Add + 2 to skip over // seperating curr hname prefix
+ * from the visible tail of the views hname
*/
- return child->base.hname + strlen(parent->base.hname) + 2;
+ return view->base.hname + strlen(curr->base.hname) + 2;
} else
return hidden_ns_name;
}
@@ -375,7 +382,7 @@ struct aa_namespace *aa_find_namespace(struct aa_namespace *root,
/**
* aa_prepare_namespace - find an existing or create a new namespace of @name
- * @name: the namespace to find or add (NOT NULL)
+ * @name: the namespace to find or add (MAYBE NULL)
*
* Returns: refcounted namespace or NULL if failed to create one
*/
@@ -559,7 +566,7 @@ static void destroy_namespace(struct aa_namespace *ns)
/**
* __remove_namespace - remove a namespace and all its children
* @ns: namespace to be removed (NOT NULL)
- *
+ *
* Requires: ns->parent->lock be held and ns removed from parent.
*/
static void __remove_namespace(struct aa_namespace *ns)
@@ -619,11 +626,11 @@ int __init aa_alloc_root_ns(void)
/**
* aa_free_root_ns - free the root profile namespace
*/
-void aa_free_root_ns(void)
+void __init aa_free_root_ns(void)
{
struct aa_namespace *ns = root_ns;
root_ns = NULL;
-
+
destroy_namespace(ns);
aa_put_namespace(ns);
}
@@ -738,7 +745,6 @@ static void free_profile(struct aa_profile *profile)
aa_free_file_rules(&profile->file);
aa_free_cap_rules(&profile->caps);
- aa_free_net_rules(&profile->net);
aa_free_rlimit_rules(&profile->rlimits);
aa_free_sid(profile->sid);
@@ -761,7 +767,7 @@ void aa_free_profile_kref(struct kref *kref)
free_profile(p);
}
-/* TODO: profile count accounting - setup in remove */
+/* TODO: profile accounting - setup in remove */
/**
* __find_child - find a profile on @head list with a name matching @name
@@ -883,8 +889,8 @@ static struct aa_profile *__lookup_profile(struct aa_policy *base,
/**
* aa_lookup_profile - find a profile by its full or partial name
- * @ns: the namespace to start from
- * @hname: name to do lookup on. Does not contain namespace prefix
+ * @ns: the namespace to start from (NOT NULL)
+ * @hname: name to do lookup on. Does not contain namespace prefix (NOT NULL)
*
* Returns: refcounted profile or NULL if not found
*/
@@ -904,7 +910,7 @@ struct aa_profile *aa_lookup_profile(struct aa_namespace *ns, const char *hname)
* replacement_allowed - test to see if replacement is allowed
* @profile: profile to test if it can be replaced (MAYBE NULL)
* @noreplace: true if replacement shouldn't be allowed but addition is okay
- * @info: return pointer to info about why replacement failed
+ * @info: Returns - info about why replacement failed (NOT NULL)
*
* Returns: %0 if replacement allowed else error code
*/
@@ -947,8 +953,8 @@ static void __add_new_profile(struct aa_namespace *ns, struct aa_policy *policy,
* aa_audit_policy - Do auditing of policy changes
* @op: policy operation being performed
* @gfp: memory allocation flags
- * @name: name of profile being manipulated
- * @info: any extra information to be audited
+ * @name: name of profile being manipulated (NOT NULL)
+ * @info: any extra information to be audited (MAYBE NULL)
* @error: error code
*
* Returns: the error to be returned after audit is done
@@ -957,7 +963,7 @@ static int audit_policy(int op, gfp_t gfp, const char *name, const char *info,
int error)
{
struct common_audit_data sa;
- COMMON_AUDIT_DATA_INIT_NONE(&sa);
+ COMMON_AUDIT_DATA_INIT(&sa, NONE);
sa.aad.op = op;
sa.aad.name = name;
sa.aad.info = info;
@@ -1015,6 +1021,7 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace)
new_profile = aa_unpack(udata, size, &ns_name);
if (IS_ERR(new_profile)) {
error = PTR_ERR(new_profile);
+ new_profile = NULL;
goto fail;
}
@@ -1097,7 +1104,7 @@ out:
return size;
fail:
- error = audit_policy(op, GFP_KERNEL, name, info, error);
+ error = audit_policy(op, GFP_KERNEL, name, info, error);
goto out;
}
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index 4b9a615c7a7..5b5dacb9623 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -81,10 +81,10 @@ static void audit_cb(struct audit_buffer *ab, void *va)
/**
* audit_iface - do audit message for policy unpacking/load/replace/remove
- * @new: profile if it has been allocated
- * @name: name of the profile being manipulated
- * @info: any extra info about the failure
- * @e: buffer position info
+ * @new: profile if it has been allocated (MAYBE NULL)
+ * @name: name of the profile being manipulated (MAYBE NULL)
+ * @info: any extra info about the failure (MAYBE NULL)
+ * @e: buffer position info (NOT NULL)
* @error: error code
*
* Returns: %0 or error
@@ -94,7 +94,7 @@ static int audit_iface(struct aa_profile *new, const char *name,
{
struct aa_profile *profile = __aa_current_profile();
struct common_audit_data sa;
- COMMON_AUDIT_DATA_INIT_NONE(&sa);
+ COMMON_AUDIT_DATA_INIT(&sa, NONE);
sa.aad.iface.pos = e->pos - e->start;
sa.aad.iface.target = new;
sa.aad.name = name;
@@ -113,8 +113,8 @@ static bool inbounds(struct aa_ext *e, size_t size)
/**
* aa_u16_chunck - test and do bounds checking for a u16 size based chunk
- * @e: serialized data read head
- * @chunk: start address for chunk of data
+ * @e: serialized data read head (NOT NULL)
+ * @chunk: start address for chunk of data (NOT NULL)
*
* Returns: the size of chunk found with the read head at the end of the chunk.
*/
@@ -189,19 +189,6 @@ fail:
return 0;
}
-static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name)
-{
- if (unpack_nameX(e, AA_U16, name)) {
- if (!inbounds(e, sizeof(u16)))
- return 0;
- if (data)
- *data = le16_to_cpu(get_unaligned((u16 *) e->pos));
- e->pos += sizeof(u16);
- return 1;
- }
- return 0;
-}
-
static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
{
if (unpack_nameX(e, AA_U32, name)) {
@@ -299,6 +286,13 @@ static int unpack_strdup(struct aa_ext *e, char **string, const char *name)
return res;
}
+/**
+ * verify_accept - verify the accept tables of a dfa
+ * @dfa: dfa to verify accept tables of (NOT NULL)
+ * @flags: flags governing dfa
+ *
+ * Returns: 1 if valid accept tables else 0 if error
+ */
static bool verify_accept(struct aa_dfa *dfa, int flags)
{
int i;
@@ -318,7 +312,7 @@ static bool verify_accept(struct aa_dfa *dfa, int flags)
/**
* unpack_dfa - unpack a file rule dfa
- * @e: serialized data extent information
+ * @e: serialized data extent information (NOT NULL)
*
* returns dfa or ERR_PTR or NULL if no dfa
*/
@@ -359,6 +353,13 @@ fail:
return ERR_PTR(-EPROTO);
}
+/**
+ * unpack_trans_table - unpack a profile transition table
+ * @e: serialized data extent information (NOT NULL)
+ * @profile: profile to add the accept table to (NOT NULL)
+ *
+ * Returns: 1 if table succesfully unpacked
+ */
static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile)
{
void *pos = e->pos;
@@ -452,19 +453,17 @@ fail:
/**
* unpack_profile - unpack a serialized profile
- * @e: serialized data extent information
+ * @e: serialized data extent information (NOT NULL)
*
* NOTE: unpack profile sets audit struct if there is a failure
*/
static struct aa_profile *unpack_profile(struct aa_ext *e)
{
struct aa_profile *profile = NULL;
- const char *name = NULL, *info = NULL;
- size_t size = 0;
- int i, error = -EPROTO;
+ const char *name = NULL;
+ int error = -EPROTO;
kernel_cap_t tmpcap;
u32 tmp;
- u64 tmp64;
/* check that we have the right struct being passed */
if (!unpack_nameX(e, AA_STRUCT, "profile"))
@@ -519,17 +518,6 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
/* set a default value if path_flags field is not present */
profile->path_flags = PFLAG_MEDIATE_DELETED;
- /* mmap_min_addr is optional */
- if (unpack_u64(e, &tmp64, "mmap_min_addr")) {
- profile->mmap_min_addr = (unsigned long)tmp64;
- if (((u64) profile->mmap_min_addr) == tmp64) {
- profile->flags |= PFLAG_MMAP_MIN_ADDR;
- } else {
- info = "invalid set mmap_min_addr";
- goto fail;
- }
- }
-
if (!unpack_u32(e, &(profile->caps.allow.cap[0]), NULL))
goto fail;
if (!unpack_u32(e, &(profile->caps.audit.cap[0]), NULL))
@@ -564,29 +552,6 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
if (!unpack_rlimits(e, profile))
goto fail;
- size = unpack_array(e, "net_allowed_af");
- if (size) {
- if (size > AF_MAX)
- goto fail;
-
- for (i = 0; i < size; i++) {
- if (!unpack_u16(e, &profile->net.allow[i], NULL))
- goto fail;
- if (!unpack_u16(e, &profile->net.audit[i], NULL))
- goto fail;
- if (!unpack_u16(e, &profile->net.quiet[i], NULL))
- goto fail;
- }
- if (!unpack_nameX(e, AA_ARRAYEND, NULL))
- goto fail;
- /*
- * allow unix domain and netlink sockets they are handled
- * by IPC
- */
- }
- profile->net.allow[AF_UNIX] = 0xffff;
- profile->net.allow[AF_NETLINK] = 0xffff;
-
/* get file rules */
profile->file.dfa = unpack_dfa(e);
if (IS_ERR(profile->file.dfa)) {
@@ -620,8 +585,8 @@ fail:
/**
* verify_head - unpack serialized stream header
- * @e: serialized data read head
- * @ns: Returns namespace if one is specified else NULL
+ * @e: serialized data read head (NOT NULL)
+ * @ns: Returns - namespace if one is specified else NULL (NOT NULL)
*
* Returns: error or 0 if header is good
*/
@@ -648,12 +613,6 @@ static int verify_header(struct aa_ext *e, const char **ns)
return 0;
}
-/**
- * verify_profile - Do post unpack analysis to verify profile consistency
- * @profile: profile to verify
- *
- * Returns: 0 if passes verification else error
- */
static bool verify_xindex(int xindex, int table_size)
{
int index, xtype;
@@ -677,6 +636,12 @@ static bool verify_dfa_xindex(struct aa_dfa *dfa, int table_size)
return 1;
}
+/**
+ * verify_profile - Do post unpack analysis to verify profile consistency
+ * @profile: profile to verify (NOT NULL)
+ *
+ * Returns: 0 if passes verification else error
+ */
static int verify_profile(struct aa_profile *profile)
{
if (aa_g_paranoid_load) {
@@ -696,7 +661,7 @@ static int verify_profile(struct aa_profile *profile)
* aa_unpack - unpack packed binary profile data loaded from user space
* @udata: user data copied to kmem (NOT NULL)
* @size: the size of the user data
- * @ns: Returns namespace profile is in if specified else NULL
+ * @ns: Returns namespace profile is in if specified else NULL (NOT NULL)
*
* Unpack user data and return refcounted allocated profile or ERR_PTR
*
diff --git a/security/apparmor/procattr.c b/security/apparmor/procattr.c
index fffc3cea326..8a2d22cbd4c 100644
--- a/security/apparmor/procattr.c
+++ b/security/apparmor/procattr.c
@@ -21,7 +21,7 @@
/**
* aa_getprocattr - Return the profile information for @profile
* @profile: the profile to print profile info about (NOT NULL)
- * @string: the string that will contain the profile and namespace info (!NULL)
+ * @string: Returns - string containing the profile info (NOT NULL)
*
* Returns: length of @string on success else error on failure
*
@@ -128,7 +128,10 @@ int aa_setprocattr_changehat(char *args, size_t size, int test)
if (hat) {
/* set up hat name vector, args guarenteed null terminated
- * at args[size]
+ * at args[size] by setprocattr.
+ *
+ * If there are multiple hat names in the buffer each is
+ * separated by a \0. Ie. userspace writes them pre tokenized
*/
char *end = args + size;
for (count = 0; (hat < end) && count < 16; ++count) {
@@ -152,7 +155,7 @@ int aa_setprocattr_changehat(char *args, size_t size, int test)
*
* Returns: %0 or error code if change_profile fails
*/
-int aa_setprocattr_changeprofile(char *fqname, int onexec, int test)
+int aa_setprocattr_changeprofile(char *fqname, bool onexec, int test)
{
char *name, *ns_name;
diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c
index ca8773ab68f..ad69bf3782b 100644
--- a/security/apparmor/resource.c
+++ b/security/apparmor/resource.c
@@ -35,7 +35,9 @@ static void audit_cb(struct audit_buffer *ab, void *va)
/**
* audit_resource - audit setting resource limit
* @profile: profile being enforced (NOT NULL)
- * @sa: audit data (NOT NULL)
+ * @resoure: rlimit being auditing
+ * @value: value being set
+ * @error: error value
*
* Returns: 0 or sa->error else other error code on failure
*/
@@ -44,7 +46,7 @@ static int audit_resource(struct aa_profile *profile, unsigned int resource,
{
struct common_audit_data sa;
- COMMON_AUDIT_DATA_INIT_NONE(&sa);
+ COMMON_AUDIT_DATA_INIT(&sa, NONE);
sa.aad.op = OP_SETRLIMIT,
sa.aad.rlim.rlim = resource;
sa.aad.rlim.max = value;
@@ -93,7 +95,7 @@ int aa_task_setrlimit(struct aa_profile *profile, unsigned int resource,
/**
* __aa_transition_rlimits - apply new profile rlimits
- * @old: old profile on task (MAYBE NULL)
+ * @old: old profile on task (NOT NULL)
* @new: new profile with rlimits to apply (NOT NULL)
*/
void __aa_transition_rlimits(struct aa_profile *old, struct aa_profile *new)
@@ -105,7 +107,7 @@ void __aa_transition_rlimits(struct aa_profile *old, struct aa_profile *new)
/* for any rlimits the profile controlled reset the soft limit
* to the less of the tasks hard limit and the init tasks soft limit
*/
- if (old && old->rlimits.mask) {
+ if (old->rlimits.mask) {
for (i = 0, mask = 1; i < RLIM_NLIMITS; i++, mask <<= 1) {
if (old->rlimits.mask & mask) {
rlim = current->signal->rlim + i;
@@ -117,7 +119,7 @@ void __aa_transition_rlimits(struct aa_profile *old, struct aa_profile *new)
}
/* set any new hard limits as dictated by the new profile */
- if (!(new && new->rlimits.mask))
+ if (!new->rlimits.mask)
return;
for (i = 0, mask = 1; i < RLIM_NLIMITS; i++, mask <<= 1) {
if (!(new->rlimits.mask & mask))