Skip to content

Commit

Permalink
Merge tag 'apparmor-pr-2017-09-22' of git://git.kernel.org/pub/scm/li…
Browse files Browse the repository at this point in the history
…nux/kernel/git/jj/linux-apparmor

Pull apparmor updates from John Johansen:
 "This is the apparmor pull request, similar to SELinux and seccomp.

  It's the same series that I was sent to James' security tree + one
  regression fix that was found after the series was sent to James and
  would have been sent for v4.14-rc2.

  Features:
  - in preparation for secid mapping add support for absolute root view
    based labels
  - add base infastructure for socket mediation
  - add mount mediation
  - add signal mediation

  minor cleanups and changes:
  - be defensive, ensure unconfined profiles have dfas initialized
  - add more debug asserts to apparmorfs
  - enable policy unpacking to audit different reasons for failure
  - cleanup conditional check for label in label_print
  - Redundant condition: prev_ns. in [label.c:1498]

  Bug Fixes:
  - fix regression in apparmorfs DAC access permissions
  - fix build failure on sparc caused by undeclared signals
  - fix sparse report of incorrect type assignment when freeing label proxies
  - fix race condition in null profile creation
  - Fix an error code in aafs_create()
  - Fix logical error in verify_header()
  - Fix shadowed local variable in unpack_trans_table()"

* tag 'apparmor-pr-2017-09-22' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor:
  apparmor: fix apparmorfs DAC access permissions
  apparmor: fix build failure on sparc caused by undeclared signals
  apparmor: fix incorrect type assignment when freeing proxies
  apparmor: ensure unconfined profiles have dfas initialized
  apparmor: fix race condition in null profile creation
  apparmor: move new_null_profile to after profile lookup fns()
  apparmor: add base infastructure for socket mediation
  apparmor: add more debug asserts to apparmorfs
  apparmor: make policy_unpack able to audit different info messages
  apparmor: add support for absolute root view based labels
  apparmor: cleanup conditional check for label in label_print
  apparmor: add mount mediation
  apparmor: add the ability to mediate signals
  apparmor: Redundant condition: prev_ns. in [label.c:1498]
  apparmor: Fix an error code in aafs_create()
  apparmor: Fix logical error in verify_header()
  apparmor: Fix shadowed local variable in unpack_trans_table()
  • Loading branch information
torvalds committed Sep 23, 2017
2 parents c65da8e + bf81100 commit 79444df
Show file tree
Hide file tree
Showing 24 changed files with 2,088 additions and 137 deletions.
1 change: 1 addition & 0 deletions security/apparmor/.gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#
# Generated include files
#
net_names.h
capability_names.h
rlim_names.h
43 changes: 41 additions & 2 deletions security/apparmor/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,44 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o

apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
resource.o secid.o file.o policy_ns.o label.o
resource.o secid.o file.o policy_ns.o label.o mount.o net.o
apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o

clean-files := capability_names.h rlim_names.h
clean-files := capability_names.h rlim_names.h net_names.h

# Build a lower case string table of address family names
# Transform lines from
# #define AF_LOCAL 1 /* POSIX name for AF_UNIX */
# #define AF_INET 2 /* Internet IP Protocol */
# to
# [1] = "local",
# [2] = "inet",
#
# and build the securityfs entries for the mapping.
# Transforms lines from
# #define AF_INET 2 /* Internet IP Protocol */
# to
# #define AA_SFS_AF_MASK "local inet"
quiet_cmd_make-af = GEN $@
cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\
sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e "/AF_ROUTE/d" -e \
's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
echo "};" >> $@ ;\
printf '%s' '\#define AA_SFS_AF_MASK "' >> $@ ;\
sed -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e "/AF_ROUTE/d" -e \
's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/\L\1/p'\
$< | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@

# Build a lower case string table of sock type names
# Transform lines from
# SOCK_STREAM = 1,
# to
# [1] = "stream",
quiet_cmd_make-sock = GEN $@
cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\
sed $^ >>$@ -r -n \
-e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
echo "};" >> $@

# Build a lower case string table of capability names
# Transforms lines from
Expand Down Expand Up @@ -61,10 +94,16 @@ cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \
tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@

$(obj)/capability.o : $(obj)/capability_names.h
$(obj)/net.o : $(obj)/net_names.h
$(obj)/resource.o : $(obj)/rlim_names.h
$(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
$(src)/Makefile
$(call cmd,make-caps)
$(obj)/rlim_names.h : $(srctree)/include/uapi/asm-generic/resource.h \
$(src)/Makefile
$(call cmd,make-rlim)
$(obj)/net_names.h : $(srctree)/include/linux/socket.h \
$(srctree)/include/linux/net.h \
$(src)/Makefile
$(call cmd,make-af)
$(call cmd,make-sock)
45 changes: 39 additions & 6 deletions security/apparmor/apparmorfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "include/audit.h"
#include "include/context.h"
#include "include/crypto.h"
#include "include/ipc.h"
#include "include/policy_ns.h"
#include "include/label.h"
#include "include/policy.h"
Expand Down Expand Up @@ -248,8 +249,10 @@ static struct dentry *aafs_create(const char *name, umode_t mode,

inode_lock(dir);
dentry = lookup_one_len(name, parent, strlen(name));
if (IS_ERR(dentry))
if (IS_ERR(dentry)) {
error = PTR_ERR(dentry);
goto fail_lock;
}

if (d_really_is_positive(dentry)) {
error = -EEXIST;
Expand Down Expand Up @@ -1443,6 +1446,10 @@ void __aafs_profile_migrate_dents(struct aa_profile *old,
{
int i;

AA_BUG(!old);
AA_BUG(!new);
AA_BUG(!mutex_is_locked(&profiles_ns(old)->lock));

for (i = 0; i < AAFS_PROF_SIZEOF; i++) {
new->dents[i] = old->dents[i];
if (new->dents[i])
Expand Down Expand Up @@ -1506,6 +1513,9 @@ int __aafs_profile_mkdir(struct aa_profile *profile, struct dentry *parent)
struct dentry *dent = NULL, *dir;
int error;

AA_BUG(!profile);
AA_BUG(!mutex_is_locked(&profiles_ns(profile)->lock));

if (!parent) {
struct aa_profile *p;
p = aa_deref_parent(profile);
Expand Down Expand Up @@ -1731,6 +1741,7 @@ void __aafs_ns_rmdir(struct aa_ns *ns)

if (!ns)
return;
AA_BUG(!mutex_is_locked(&ns->lock));

list_for_each_entry(child, &ns->base.profiles, base.list)
__aafs_profile_rmdir(child);
Expand Down Expand Up @@ -1903,6 +1914,10 @@ static struct aa_ns *__next_ns(struct aa_ns *root, struct aa_ns *ns)
{
struct aa_ns *parent, *next;

AA_BUG(!root);
AA_BUG(!ns);
AA_BUG(ns != root && !mutex_is_locked(&ns->parent->lock));

/* is next namespace a child */
if (!list_empty(&ns->sub_ns)) {
next = list_first_entry(&ns->sub_ns, typeof(*ns), base.list);
Expand Down Expand Up @@ -1937,6 +1952,9 @@ static struct aa_ns *__next_ns(struct aa_ns *root, struct aa_ns *ns)
static struct aa_profile *__first_profile(struct aa_ns *root,
struct aa_ns *ns)
{
AA_BUG(!root);
AA_BUG(ns && !mutex_is_locked(&ns->lock));

for (; ns; ns = __next_ns(root, ns)) {
if (!list_empty(&ns->base.profiles))
return list_first_entry(&ns->base.profiles,
Expand All @@ -1959,6 +1977,8 @@ static struct aa_profile *__next_profile(struct aa_profile *p)
struct aa_profile *parent;
struct aa_ns *ns = p->ns;

AA_BUG(!mutex_is_locked(&profiles_ns(p)->lock));

/* is next profile a child */
if (!list_empty(&p->base.profiles))
return list_first_entry(&p->base.profiles, typeof(*p),
Expand Down Expand Up @@ -2127,6 +2147,11 @@ static struct aa_sfs_entry aa_sfs_entry_ptrace[] = {
{ }
};

static struct aa_sfs_entry aa_sfs_entry_signal[] = {
AA_SFS_FILE_STRING("mask", AA_SFS_SIG_MASK),
{ }
};

static struct aa_sfs_entry aa_sfs_entry_domain[] = {
AA_SFS_FILE_BOOLEAN("change_hat", 1),
AA_SFS_FILE_BOOLEAN("change_hatv", 1),
Expand All @@ -2151,9 +2176,14 @@ static struct aa_sfs_entry aa_sfs_entry_policy[] = {
{ }
};

static struct aa_sfs_entry aa_sfs_entry_mount[] = {
AA_SFS_FILE_STRING("mask", "mount umount pivot_root"),
{ }
};

static struct aa_sfs_entry aa_sfs_entry_ns[] = {
AA_SFS_FILE_BOOLEAN("profile", 1),
AA_SFS_FILE_BOOLEAN("pivot_root", 1),
AA_SFS_FILE_BOOLEAN("pivot_root", 0),
{ }
};

Expand All @@ -2172,22 +2202,25 @@ static struct aa_sfs_entry aa_sfs_entry_features[] = {
AA_SFS_DIR("policy", aa_sfs_entry_policy),
AA_SFS_DIR("domain", aa_sfs_entry_domain),
AA_SFS_DIR("file", aa_sfs_entry_file),
AA_SFS_DIR("network", aa_sfs_entry_network),
AA_SFS_DIR("mount", aa_sfs_entry_mount),
AA_SFS_DIR("namespaces", aa_sfs_entry_ns),
AA_SFS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
AA_SFS_DIR("rlimit", aa_sfs_entry_rlimit),
AA_SFS_DIR("caps", aa_sfs_entry_caps),
AA_SFS_DIR("ptrace", aa_sfs_entry_ptrace),
AA_SFS_DIR("signal", aa_sfs_entry_signal),
AA_SFS_DIR("query", aa_sfs_entry_query),
{ }
};

static struct aa_sfs_entry aa_sfs_entry_apparmor[] = {
AA_SFS_FILE_FOPS(".access", 0640, &aa_sfs_access),
AA_SFS_FILE_FOPS(".access", 0666, &aa_sfs_access),
AA_SFS_FILE_FOPS(".stacked", 0444, &seq_ns_stacked_fops),
AA_SFS_FILE_FOPS(".ns_stacked", 0444, &seq_ns_nsstacked_fops),
AA_SFS_FILE_FOPS(".ns_level", 0666, &seq_ns_level_fops),
AA_SFS_FILE_FOPS(".ns_name", 0640, &seq_ns_name_fops),
AA_SFS_FILE_FOPS("profiles", 0440, &aa_sfs_profiles_fops),
AA_SFS_FILE_FOPS(".ns_level", 0444, &seq_ns_level_fops),
AA_SFS_FILE_FOPS(".ns_name", 0444, &seq_ns_name_fops),
AA_SFS_FILE_FOPS("profiles", 0444, &aa_sfs_profiles_fops),
AA_SFS_DIR("features", aa_sfs_entry_features),
{ }
};
Expand Down
4 changes: 2 additions & 2 deletions security/apparmor/domain.c
Original file line number Diff line number Diff line change
Expand Up @@ -374,8 +374,8 @@ static const char *next_name(int xtype, const char *name)
*
* Returns: refcounted label, or NULL on failure (MAYBE NULL)
*/
static struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex,
const char **name)
struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex,
const char **name)
{
struct aa_label *label = NULL;
u32 xtype = xindex & AA_X_TYPE_MASK;
Expand Down
30 changes: 30 additions & 0 deletions security/apparmor/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "include/context.h"
#include "include/file.h"
#include "include/match.h"
#include "include/net.h"
#include "include/path.h"
#include "include/policy.h"
#include "include/label.h"
Expand Down Expand Up @@ -566,6 +567,32 @@ static int __file_path_perm(const char *op, struct aa_label *label,
return error;
}

static int __file_sock_perm(const char *op, struct aa_label *label,
struct aa_label *flabel, struct file *file,
u32 request, u32 denied)
{
struct socket *sock = (struct socket *) file->private_data;
int error;

AA_BUG(!sock);

/* revalidation due to label out of date. No revocation at this time */
if (!denied && aa_label_is_subset(flabel, label))
return 0;

/* TODO: improve to skip profiles cached in flabel */
error = aa_sock_file_perm(label, op, request, sock);
if (denied) {
/* TODO: improve to skip profiles checked above */
/* check every profile in file label to is cached */
last_error(error, aa_sock_file_perm(flabel, op, request, sock));
}
if (!error)
update_file_ctx(file_ctx(file), label, request);

return error;
}

/**
* aa_file_perm - do permission revalidation check & audit for @file
* @op: operation being checked
Expand Down Expand Up @@ -610,6 +637,9 @@ int aa_file_perm(const char *op, struct aa_label *label, struct file *file,
error = __file_path_perm(op, label, flabel, file, request,
denied);

else if (S_ISSOCK(file_inode(file)->i_mode))
error = __file_sock_perm(op, label, flabel, file, request,
denied);
done:
rcu_read_unlock();

Expand Down
2 changes: 2 additions & 0 deletions security/apparmor/include/apparmor.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@
#define AA_CLASS_NET 4
#define AA_CLASS_RLIMITS 5
#define AA_CLASS_DOMAIN 6
#define AA_CLASS_MOUNT 7
#define AA_CLASS_PTRACE 9
#define AA_CLASS_SIGNAL 10
#define AA_CLASS_LABEL 16

#define AA_CLASS_LAST AA_CLASS_LABEL
Expand Down
39 changes: 30 additions & 9 deletions security/apparmor/include/audit.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ enum audit_type {
#define OP_FMPROT "file_mprotect"
#define OP_INHERIT "file_inherit"

#define OP_PIVOTROOT "pivotroot"
#define OP_MOUNT "mount"
#define OP_UMOUNT "umount"

#define OP_CREATE "create"
#define OP_POST_CREATE "post_create"
#define OP_BIND "bind"
Expand All @@ -86,6 +90,7 @@ enum audit_type {
#define OP_SHUTDOWN "socket_shutdown"

#define OP_PTRACE "ptrace"
#define OP_SIGNAL "signal"

#define OP_EXEC "exec"

Expand Down Expand Up @@ -116,20 +121,36 @@ struct apparmor_audit_data {
/* these entries require a custom callback fn */
struct {
struct aa_label *peer;
struct {
const char *target;
kuid_t ouid;
} fs;
union {
struct {
kuid_t ouid;
const char *target;
} fs;
struct {
int type, protocol;
struct sock *peer_sk;
void *addr;
int addrlen;
} net;
int signal;
struct {
int rlim;
unsigned long max;
} rlim;
};
};
struct {
const char *name;
long pos;
struct aa_profile *profile;
const char *ns;
long pos;
} iface;
struct {
int rlim;
unsigned long max;
} rlim;
const char *src_name;
const char *type;
const char *trans;
const char *data;
unsigned long flags;
} mnt;
};
};

Expand Down
5 changes: 5 additions & 0 deletions security/apparmor/include/domain.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#include <linux/binfmts.h>
#include <linux/types.h>

#include "label.h"

#ifndef __AA_DOMAIN_H
#define __AA_DOMAIN_H

Expand All @@ -29,6 +31,9 @@ struct aa_domain {
#define AA_CHANGE_ONEXEC 4
#define AA_CHANGE_STACK 8

struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex,
const char **name);

int apparmor_bprm_set_creds(struct linux_binprm *bprm);

void aa_free_domain_entries(struct aa_domain *domain);
Expand Down
6 changes: 6 additions & 0 deletions security/apparmor/include/ipc.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,14 @@ struct aa_profile;

#define AA_PTRACE_PERM_MASK (AA_PTRACE_READ | AA_PTRACE_TRACE | \
AA_MAY_BE_READ | AA_MAY_BE_TRACED)
#define AA_SIGNAL_PERM_MASK (MAY_READ | MAY_WRITE)

#define AA_SFS_SIG_MASK "hup int quit ill trap abrt bus fpe kill usr1 " \
"segv usr2 pipe alrm term stkflt chld cont stop stp ttin ttou urg " \
"xcpu xfsz vtalrm prof winch io pwr sys emt lost"

int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee,
u32 request);
int aa_may_signal(struct aa_label *sender, struct aa_label *target, int sig);

#endif /* __AA_IPC_H */
1 change: 1 addition & 0 deletions security/apparmor/include/label.h
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ bool aa_update_label_name(struct aa_ns *ns, struct aa_label *label, gfp_t gfp);
#define FLAG_SHOW_MODE 1
#define FLAG_VIEW_SUBNS 2
#define FLAG_HIDDEN_UNCONFINED 4
#define FLAG_ABS_ROOT 8
int aa_label_snxprint(char *str, size_t size, struct aa_ns *view,
struct aa_label *label, int flags);
int aa_label_asxprint(char **strp, struct aa_ns *ns, struct aa_label *label,
Expand Down
Loading

0 comments on commit 79444df

Please sign in to comment.