Commit 7e688095 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of...

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6: (90 commits)
  AppArmor: fix build warnings for non-const use of get_task_cred
  selinux: convert the policy type_attr_map to flex_array
  AppArmor: Enable configuring and building of the AppArmor security module
  TOMOYO: Use pathname specified by policy rather than execve()
  AppArmor: update path_truncate method to latest version
  AppArmor: core policy routines
  AppArmor: policy routines for loading and unpacking policy
  AppArmor: mediation of non file objects
  AppArmor: LSM interface, and security module initialization
  AppArmor: Enable configuring and building of the AppArmor security module
  AppArmor: update Maintainer and Documentation
  AppArmor: functions for domain transitions
  AppArmor: file enforcement routines
  AppArmor: userspace interfaces
  AppArmor: dfa match engine
  AppArmor: contexts used in attaching policy to system objects
  AppArmor: basic auditing infrastructure.
  AppArmor: misc. base functions and defines
  TOMOYO: Update version to 2.3.0
  TOMOYO: Fix quota check.
  ...
parents 3a09b1be 77c80e6b
--- What is AppArmor? ---
AppArmor is MAC style security extension for the Linux kernel. It implements
a task centered policy, with task "profiles" being created and loaded
from user space. Tasks on the system that do not have a profile defined for
them run in an unconfined state which is equivalent to standard Linux DAC
permissions.
--- How to enable/disable ---
set CONFIG_SECURITY_APPARMOR=y
If AppArmor should be selected as the default security module then
set CONFIG_DEFAULT_SECURITY="apparmor"
and CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1
Build the kernel
If AppArmor is not the default security module it can be enabled by passing
security=apparmor on the kernel's command line.
If AppArmor is the default security module it can be disabled by passing
apparmor=0, security=XXXX (where XXX is valid security module), on the
kernel's command line
For AppArmor to enforce any restrictions beyond standard Linux DAC permissions
policy must be loaded into the kernel from user space (see the Documentation
and tools links).
--- Documentation ---
Documentation can be found on the wiki.
--- Links ---
Mailing List - apparmor@lists.ubuntu.com
Wiki - http://apparmor.wiki.kernel.org/
User space tools - https://launchpad.net/apparmor
Kernel module - git://git.kernel.org/pub/scm/linux/kernel/git/jj/apparmor-dev.git
......@@ -93,6 +93,7 @@ parameter is applicable:
Documentation/scsi/.
SECURITY Different security models are enabled.
SELINUX SELinux support is enabled.
APPARMOR AppArmor support is enabled.
SERIAL Serial support is enabled.
SH SuperH architecture is enabled.
SMP The kernel is an SMP kernel.
......@@ -2312,6 +2313,13 @@ and is between 256 and 4096 characters. It is defined in the file
If enabled at boot time, /selinux/disable can be used
later to disable prior to initial policy load.
apparmor= [APPARMOR] Disable or enable AppArmor at boot time
Format: { "0" | "1" }
See security/apparmor/Kconfig help text
0 -- disable.
1 -- enable.
Default value is set via kernel config option.
serialnumber [BUGS=X86-32]
shapers= [NET]
......
......@@ -3,8 +3,8 @@
TOMOYO is a name-based MAC extension (LSM module) for the Linux kernel.
LiveCD-based tutorials are available at
http://tomoyo.sourceforge.jp/en/1.6.x/1st-step/ubuntu8.04-live/
http://tomoyo.sourceforge.jp/en/1.6.x/1st-step/centos5-live/ .
http://tomoyo.sourceforge.jp/1.7/1st-step/ubuntu10.04-live/
http://tomoyo.sourceforge.jp/1.7/1st-step/centos5-live/ .
Though these tutorials use non-LSM version of TOMOYO, they are useful for you
to know what TOMOYO is.
......@@ -13,12 +13,12 @@ to know what TOMOYO is.
Build the kernel with CONFIG_SECURITY_TOMOYO=y and pass "security=tomoyo" on
kernel's command line.
Please see http://tomoyo.sourceforge.jp/en/2.2.x/ for details.
Please see http://tomoyo.sourceforge.jp/2.3/ for details.
--- Where is documentation? ---
User <-> Kernel interface documentation is available at
http://tomoyo.sourceforge.jp/en/2.2.x/policy-reference.html .
http://tomoyo.sourceforge.jp/2.3/policy-reference.html .
Materials we prepared for seminars and symposiums are available at
http://sourceforge.jp/projects/tomoyo/docs/?category_id=532&language_id=1 .
......@@ -50,6 +50,6 @@ multiple LSM modules at the same time. We feel sorry that you have to give up
SELinux/SMACK/AppArmor etc. when you want to use TOMOYO.
We hope that LSM becomes stackable in future. Meanwhile, you can use non-LSM
version of TOMOYO, available at http://tomoyo.sourceforge.jp/en/1.6.x/ .
version of TOMOYO, available at http://tomoyo.sourceforge.jp/1.7/ .
LSM version of TOMOYO is a subset of non-LSM version of TOMOYO. We are planning
to port non-LSM version's functionalities to LSM versions.
......@@ -5061,6 +5061,14 @@ S: Supported
F: include/linux/selinux*
F: security/selinux/
APPARMOR SECURITY MODULE
M: John Johansen <john.johansen@canonical.com>
L: apparmor@lists.ubuntu.com (subscribers-only, general discussion)
W: apparmor.wiki.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jj/apparmor-dev.git
S: Supported
F: security/apparmor/
SENSABLE PHANTOM
M: Jiri Slaby <jirislaby@gmail.com>
S: Maintained
......@@ -5605,7 +5613,7 @@ L: tomoyo-users-en@lists.sourceforge.jp (subscribers-only, for developers and us
L: tomoyo-dev@lists.sourceforge.jp (subscribers-only, for developers in Japanese)
L: tomoyo-users@lists.sourceforge.jp (subscribers-only, for users in Japanese)
W: http://tomoyo.sourceforge.jp/
T: quilt http://svn.sourceforge.jp/svnroot/tomoyo/trunk/2.2.x/tomoyo-lsm/patches/
T: quilt http://svn.sourceforge.jp/svnroot/tomoyo/trunk/2.3.x/tomoyo-lsm/patches/
S: Maintained
F: security/tomoyo/
......
......@@ -1016,7 +1016,7 @@ static int fuse_permission(struct inode *inode, int mask)
exist. So if permissions are revoked this won't be
noticed immediately, only after the attribute
timeout has expired */
} else if (mask & MAY_ACCESS) {
} else if (mask & (MAY_ACCESS | MAY_CHDIR)) {
err = fuse_access(inode, mask);
} else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) {
if (!(inode->i_mode & S_IXUGO)) {
......
......@@ -282,8 +282,7 @@ int inode_permission(struct inode *inode, int mask)
if (retval)
return retval;
return security_inode_permission(inode,
mask & (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND));
return security_inode_permission(inode, mask);
}
/**
......@@ -1484,8 +1483,7 @@ static int handle_truncate(struct path *path)
*/
error = locks_verify_locked(inode);
if (!error)
error = security_path_truncate(path, 0,
ATTR_MTIME|ATTR_CTIME|ATTR_OPEN);
error = security_path_truncate(path);
if (!error) {
error = do_truncate(path->dentry, 0,
ATTR_MTIME|ATTR_CTIME|ATTR_OPEN,
......
......@@ -1953,7 +1953,7 @@ int nfs_permission(struct inode *inode, int mask)
if ((mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0)
goto out;
/* Is this sys_access() ? */
if (mask & MAY_ACCESS)
if (mask & (MAY_ACCESS | MAY_CHDIR))
goto force_lookup;
switch (inode->i_mode & S_IFMT) {
......
......@@ -110,7 +110,7 @@ static long do_sys_truncate(const char __user *pathname, loff_t length)
error = locks_verify_truncate(inode, NULL, length);
if (!error)
error = security_path_truncate(&path, length, 0);
error = security_path_truncate(&path);
if (!error)
error = do_truncate(path.dentry, length, 0, NULL);
......@@ -165,8 +165,7 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
error = locks_verify_truncate(inode, file, length);
if (!error)
error = security_path_truncate(&file->f_path, length,
ATTR_MTIME|ATTR_CTIME);
error = security_path_truncate(&file->f_path);
if (!error)
error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file);
out_putf:
......@@ -367,7 +366,7 @@ SYSCALL_DEFINE1(chdir, const char __user *, filename)
if (error)
goto out;
error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
if (error)
goto dput_and_out;
......@@ -396,7 +395,7 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd)
if (!S_ISDIR(inode->i_mode))
goto out_putf;
error = inode_permission(inode, MAY_EXEC | MAY_ACCESS);
error = inode_permission(inode, MAY_EXEC | MAY_CHDIR);
if (!error)
set_fs_pwd(current->fs, &file->f_path);
out_putf:
......@@ -414,7 +413,7 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename)
if (error)
goto out;
error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
if (error)
goto dput_and_out;
......
......@@ -49,9 +49,6 @@ typedef struct __user_cap_data_struct {
} __user *cap_user_data_t;
#define XATTR_CAPS_SUFFIX "capability"
#define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX
#define VFS_CAP_REVISION_MASK 0xFF000000
#define VFS_CAP_REVISION_SHIFT 24
#define VFS_CAP_FLAGS_MASK ~VFS_CAP_REVISION_MASK
......
......@@ -53,6 +53,7 @@ struct inodes_stat_t {
#define MAY_APPEND 8
#define MAY_ACCESS 16
#define MAY_OPEN 32
#define MAY_CHDIR 64
/*
* flags in file.f_mode. Note that FMODE_READ and FMODE_WRITE must correspond
......
......@@ -90,9 +90,41 @@ struct common_audit_data {
u32 requested;
u32 audited;
u32 denied;
/*
* auditdeny is a bit tricky and unintuitive. See the
* comments in avc.c for it's meaning and usage.
*/
u32 auditdeny;
struct av_decision *avd;
int result;
} selinux_audit_data;
#endif
#ifdef CONFIG_SECURITY_APPARMOR
struct {
int error;
int op;
int type;
void *profile;
const char *name;
const char *info;
union {
void *target;
struct {
long pos;
void *target;
} iface;
struct {
int rlim;
unsigned long max;
} rlim;
struct {
const char *target;
u32 request;
u32 denied;
uid_t ouid;
} fs;
};
} apparmor_audit_data;
#endif
};
/* these callback will be implemented by a specific LSM */
......
......@@ -470,8 +470,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @path_truncate:
* Check permission before truncating a file.
* @path contains the path structure for the file.
* @length is the new length of the file.
* @time_attrs is the flags passed to do_truncate().
* Return 0 if permission is granted.
* @inode_getattr:
* Check permission before obtaining file attributes.
......@@ -1412,8 +1410,7 @@ struct security_operations {
int (*path_rmdir) (struct path *dir, struct dentry *dentry);
int (*path_mknod) (struct path *dir, struct dentry *dentry, int mode,
unsigned int dev);
int (*path_truncate) (struct path *path, loff_t length,
unsigned int time_attrs);
int (*path_truncate) (struct path *path);
int (*path_symlink) (struct path *dir, struct dentry *dentry,
const char *old_name);
int (*path_link) (struct dentry *old_dentry, struct path *new_dir,
......@@ -2806,8 +2803,7 @@ int security_path_mkdir(struct path *dir, struct dentry *dentry, int mode);
int security_path_rmdir(struct path *dir, struct dentry *dentry);
int security_path_mknod(struct path *dir, struct dentry *dentry, int mode,
unsigned int dev);
int security_path_truncate(struct path *path, loff_t length,
unsigned int time_attrs);
int security_path_truncate(struct path *path);
int security_path_symlink(struct path *dir, struct dentry *dentry,
const char *old_name);
int security_path_link(struct dentry *old_dentry, struct path *new_dir,
......@@ -2841,8 +2837,7 @@ static inline int security_path_mknod(struct path *dir, struct dentry *dentry,
return 0;
}
static inline int security_path_truncate(struct path *path, loff_t length,
unsigned int time_attrs)
static inline int security_path_truncate(struct path *path)
{
return 0;
}
......
......@@ -33,6 +33,20 @@
#define XATTR_USER_PREFIX "user."
#define XATTR_USER_PREFIX_LEN (sizeof (XATTR_USER_PREFIX) - 1)
/* Security namespace */
#define XATTR_SELINUX_SUFFIX "selinux"
#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
#define XATTR_SMACK_SUFFIX "SMACK64"
#define XATTR_SMACK_IPIN "SMACK64IPIN"
#define XATTR_SMACK_IPOUT "SMACK64IPOUT"
#define XATTR_NAME_SMACK XATTR_SECURITY_PREFIX XATTR_SMACK_SUFFIX
#define XATTR_NAME_SMACKIPIN XATTR_SECURITY_PREFIX XATTR_SMACK_IPIN
#define XATTR_NAME_SMACKIPOUT XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT
#define XATTR_CAPS_SUFFIX "capability"
#define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX
struct inode;
struct dentry;
......
......@@ -140,6 +140,7 @@ config LSM_MMAP_MIN_ADDR
source security/selinux/Kconfig
source security/smack/Kconfig
source security/tomoyo/Kconfig
source security/apparmor/Kconfig
source security/integrity/ima/Kconfig
......@@ -148,6 +149,7 @@ choice
default DEFAULT_SECURITY_SELINUX if SECURITY_SELINUX
default DEFAULT_SECURITY_SMACK if SECURITY_SMACK
default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO
default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR
default DEFAULT_SECURITY_DAC
help
......@@ -163,6 +165,9 @@ choice
config DEFAULT_SECURITY_TOMOYO
bool "TOMOYO" if SECURITY_TOMOYO=y
config DEFAULT_SECURITY_APPARMOR
bool "AppArmor" if SECURITY_APPARMOR=y
config DEFAULT_SECURITY_DAC
bool "Unix Discretionary Access Controls"
......@@ -173,6 +178,7 @@ config DEFAULT_SECURITY
default "selinux" if DEFAULT_SECURITY_SELINUX
default "smack" if DEFAULT_SECURITY_SMACK
default "tomoyo" if DEFAULT_SECURITY_TOMOYO
default "apparmor" if DEFAULT_SECURITY_APPARMOR
default "" if DEFAULT_SECURITY_DAC
endmenu
......
......@@ -6,6 +6,7 @@ obj-$(CONFIG_KEYS) += keys/
subdir-$(CONFIG_SECURITY_SELINUX) += selinux
subdir-$(CONFIG_SECURITY_SMACK) += smack
subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo
subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor
# always enable default capabilities
obj-y += commoncap.o
......@@ -19,6 +20,7 @@ obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o
obj-$(CONFIG_AUDIT) += lsm_audit.o
obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/built-in.o
obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/built-in.o
obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o
# Object integrity file lists
......
#
# Generated include files
#
af_names.h
capability_names.h
config SECURITY_APPARMOR
bool "AppArmor support"
depends on SECURITY
select AUDIT
select SECURITY_PATH
select SECURITYFS
select SECURITY_NETWORK
default n
help
This enables the AppArmor security module.
Required userspace tools (if they are not included in your
distribution) and further information may be found at
http://apparmor.wiki.kernel.org
If you are unsure how to answer this question, answer N.
config SECURITY_APPARMOR_BOOTPARAM_VALUE
int "AppArmor boot parameter default value"
depends on SECURITY_APPARMOR
range 0 1
default 1
help
This option sets the default value for the kernel parameter
'apparmor', which allows AppArmor to be enabled or disabled
at boot. If this option is set to 0 (zero), the AppArmor
kernel parameter will default to 0, disabling AppArmor at
boot. If this option is set to 1 (one), the AppArmor
kernel parameter will default to 1, enabling AppArmor at
boot.
If you are unsure how to answer this question, answer 1.
# Makefile for AppArmor Linux Security Module
#
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
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-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)/resource.o : $(obj)/rlim_names.h
$(obj)/capability_names.h : $(srctree)/include/linux/capability.h
$(call cmd,make-caps)
$(obj)/af_names.h : $(srctree)/include/linux/socket.h
$(call cmd,make-af)
$(obj)/rlim_names.h : $(srctree)/include/asm-generic/resource.h
$(call cmd,make-rlim)
/*
* AppArmor security module
*
* This file contains AppArmor /sys/kernel/security/apparmor interface functions
*
* Copyright (C) 1998-2008 Novell/SUSE
* Copyright 2009-2010 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2 of the
* License.
*/
#include <linux/security.h>
#include <linux/vmalloc.h>
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
#include <linux/namei.h>
#include "include/apparmor.h"
#include "include/apparmorfs.h"
#include "include/audit.h"
#include "include/context.h"
#include "include/policy.h"
/**
* 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 (NOT NULL)
*
* Returns: kernel buffer containing copy of user buffer data or an
* ERR_PTR on failure.
*/
static char *aa_simple_write_to_buffer(int op, const char __user *userbuf,
size_t alloc_size, size_t copy_size,
loff_t *pos)
{
char *data;
if (*pos != 0)
/* only writes from pos 0, that is complete writes */
return ERR_PTR(-ESPIPE);
/*
* Don't allow profile load/replace/remove from profiles that don't
* have CAP_MAC_ADMIN
*/
if (!aa_may_manage_policy(op))
return ERR_PTR(-EACCES);
/* freed by caller to simple_write_to_buffer */
data = kvmalloc(alloc_size);
if (data == NULL)
return ERR_PTR(-ENOMEM);
if (copy_from_user(data, userbuf, copy_size)) {
kvfree(data);
return ERR_PTR(-EFAULT);
}
return data;
}
/* .load file hook fn to load policy */
static ssize_t profile_load(struct file *f, const char __user *buf, size_t size,
loff_t *pos)
{
char *data;
ssize_t error;
data = aa_simple_write_to_buffer(OP_PROF_LOAD, buf, size, size, pos);
error = PTR_ERR(data);
if (!IS_ERR(data)) {
error = aa_replace_profiles(data, size, PROF_ADD);
kvfree(data);
}
return error;
}
static const struct file_operations aa_fs_profile_load = {
.write = profile_load
};
/* .replace file hook fn to load and/or replace policy */
static ssize_t profile_replace(struct file *f, const char __user *buf,
size_t size, loff_t *pos)
{
char *data;
ssize_t error;
data = aa_simple_write_to_buffer(OP_PROF_REPL, buf, size, size, pos);
error = PTR_ERR(data);
if (!IS_ERR(data)) {
error = aa_replace_profiles(data, size, PROF_REPLACE);
kvfree(data);
}
return error;
}
static const struct file_operations aa_fs_profile_replace = {
.write = profile_replace
};
/* .remove file hook fn to remove loaded policy */
static ssize_t profile_remove(struct file *f, const char __user *buf,
size_t size, loff_t *pos)
{
char *data;
ssize_t error;
/*
* aa_remove_profile needs a null terminated string so 1 extra
* byte is allocated and the copied data is null terminated.
*/
data = aa_simple_write_to_buffer(OP_PROF_RM, buf, size + 1, size, pos);
error = PTR_ERR(data);
if (!IS_ERR(data)) {
data[size] = 0;
error = aa_remove_profiles(data, size);
kvfree(data);
}
return error;
}
static const struct file_operations aa_fs_profile_remove = {
.write = profile_remove
};
/** Base file system setup **/
static struct dentry *aa_fs_dentry __initdata;
static void __init aafs_remove(const char *name)
{
struct dentry *dentry;
dentry = lookup_one_len(name, aa_fs_dentry, strlen(name));
if (!IS_ERR(dentry)) {
securityfs_remove(dentry);
dput(dentry);
}
}
/**
* aafs_create - create an entry in the apparmor filesystem
* @name: name of the entry (NOT NULL)
* @mask: file permission mask of the file
* @fops: file operations for the file (NOT NULL)
*
* Used aafs_remove to remove entries created with this fn.
*/
static int __init aafs_create(const char *name, int mask,
const struct file_operations *fops)
{
struct dentry *dentry;
dentry = securityfs_create_file(name, S_IFREG | mask, aa_fs_dentry,
NULL, fops);
return IS_ERR(dentry) ? PTR_ERR(dentry) : 0;
}
/**
* aa_destroy_aafs - cleanup and free aafs
*
* releases dentries allocated by aa_create_aafs
*/
void __init aa_destroy_aafs(void)
{
if (aa_fs_dentry) {
aafs_remove(".remove");
aafs_remove(".replace");
aafs_remove(".load");
securityfs_remove(aa_fs_dentry);
aa_fs_dentry = NULL;
}
}
/**
* aa_create_aafs - create the apparmor security filesystem
*
* dentries created here are released by aa_destroy_aafs
*
* Returns: error on failure
*/
int __init aa_create_aafs(void)
{
int error;
if (!apparmor_initialized)
return 0;
if (aa_fs_dentry) {
AA_ERROR("%s: AppArmor securityfs already exists\n", __func__);
return -EEXIST;
}
aa_fs_dentry = securityfs_create_dir("apparmor", NULL);
if (IS_ERR(aa_fs_dentry)) {
error = PTR_ERR(aa_fs_dentry);
aa_fs_dentry = NULL;
goto error;
}
error = aafs_create(".load", 0640, &aa_fs_profile_load);
if (error)
goto error;
error = aafs_create(".replace", 0640, &aa_fs_profile_replace);
if (error)
goto error;
error = aafs_create(".remove", 0640, &aa_fs_profile_remove);
if (error)
goto error;
/* TODO: add support for apparmorfs_null and apparmorfs_mnt */
/* Report that AppArmor fs is enabled */
aa_info_message("AppArmor Filesystem Enabled");
return 0;
error:
aa_destroy_aafs();
AA_ERROR("Error creating AppArmor securityfs\n");
return error;
}
fs_initcall(aa_create_aafs);
/*
* AppArmor security module
*
* This file contains AppArmor auditing functions
*
* Copyright (C) 1998-2008 Novell/SUSE
* Copyright 2009-2010 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2 of the
* License.
*/
#include <linux/audit.h>
#include <linux/socket.h>
#include "include/apparmor.h"
#include "include/audit.h"
#include "include/policy.h"
const char *op_table[] = {
"null",
"sysctl",
"capable",
"unlink",
"mkdir",
"rmdir",
"mknod",
"truncate",
"link",
"symlink",
"rename_src",
"rename_dest",
"chmod",
"chown",
"getattr",
"open",
"file_perm",
"file_lock",
"file_mmap",
"file_mprotect",
"create",
"post_create",
"bind",
"connect",
"listen",
"accept",
"sendmsg",
"recvmsg",
"getsockname",
"getpeername",
"getsockopt",
"setsockopt",
"socket_shutdown",
"ptrace",
"exec",
"change_hat",
"change_profile",
"change_onexec",
"setprocattr",
"setrlimit",
"profile_replace",
"profile_load",
"profile_remove"
};
const char *audit_mode_names[] = {
"normal",
"quiet_denied",
"quiet",
"noquiet",
"all"
};
static char *aa_audit_type[] = {
"AUDIT",
"ALLOWED",
"DENIED",
"HINT",
"STATUS",
"ERROR",
"KILLED"
};
/*
* Currently AppArmor auditing is fed straight into the audit framework.
*
* TODO:
* netlink interface for complain mode
* user auditing, - send user auditing to netlink interface
* system control of whether user audit messages go to system log
*/
/**
* audit_base - core AppArmor function.
* @ab: audit buffer to fill (NOT NULL)
* @ca: audit structure containing data to audit (NOT NULL)
*
* Record common AppArmor audit data from @sa
*/
static void audit_pre(struct audit_buffer *ab, void *ca)
{
struct common_audit_data *sa = ca;
struct task_struct *tsk = sa->tsk ? sa->tsk : current;
if (aa_g_audit_header) {
audit_log_format(ab, "apparmor=");
audit_log_string(ab, aa_audit_type[sa->aad.type]);
}
if (sa->aad.op) {
audit_log_format(ab, " operation=");
audit_log_string(ab, op_table[sa->aad.op]);
}
if (sa->aad.info) {
audit_log_format(ab, " info=");
audit_log_string(ab, sa->aad.info);
if (sa->aad.error)
audit_log_format(ab, " error=%d", sa->aad.error);
}
if (sa->aad.profile) {
struct aa_profile *profile = sa->aad.profile;
pid_t pid;
rcu_read_lock();
pid = tsk->real_parent->pid;
rcu_read_unlock();
audit_log_format(ab, " parent=%d", pid);
if (profile->ns != root_ns) {
audit_log_format(ab, " namespace=");
audit_log_untrustedstring(ab, profile->ns->base.hname);
}
audit_log_format(ab, " profile=");
audit_log_untrustedstring(ab, profile->base.hname);
}
if (sa->aad.name) {
audit_log_format(ab, " name=");
audit_log_untrustedstring(ab, sa->aad.name);
}
}
/**
* 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 (NOT NULL)
* @gfp: allocation flags to use
* @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
*
* Returns: error on failure
*/
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)
return 0;
type = AUDIT_APPARMOR_AUDIT;
} else if (COMPLAIN_MODE(profile))
type = AUDIT_APPARMOR_ALLOWED;
else
type = AUDIT_APPARMOR_DENIED;
}
if (AUDIT_MODE(profile) == AUDIT_QUIET ||
(type == AUDIT_APPARMOR_DENIED &&
AUDIT_MODE(profile) == AUDIT_QUIET))
return sa->aad.error;
if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED)
type = AUDIT_APPARMOR_KILL;
if (!unconfined(profile))
sa->aad.profile = profile;
aa_audit_msg(type, sa, cb);
if (sa->aad.type == AUDIT_APPARMOR_KILL)
(void)send_sig_info(SIGKILL, NULL, sa->tsk ? sa->tsk : current);
if (sa->aad.type == AUDIT_APPARMOR_ALLOWED)
return complain_error(sa->aad.error);
return sa->aad.error;
}
/*
* AppArmor security module
*
* This file contains AppArmor capability mediation functions
*
* Copyright (C) 1998-2008 Novell/SUSE
* Copyright 2009-2010 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2 of the
* License.
*/
#include <linux/capability.h>
#include <linux/errno.h>
#include <linux/gfp.h>
#include "include/apparmor.h"
#include "include/capability.h"
#include "include/context.h"
#include "include/policy.h"
#include "include/audit.h"
/*
* Table of capability names: we generate it from capabilities.h.
*/
#include "capability_names.h"
struct audit_cache {
struct aa_profile *profile;
kernel_cap_t caps;
};
static DEFINE_PER_CPU(struct audit_cache, audit_cache);
/**
* audit_cb - call back for capability components of audit struct
* @ab - audit buffer (NOT NULL)
* @va - audit struct to audit data from (NOT NULL)
*/
static void audit_cb(struct audit_buffer *ab, void *va)
{
struct common_audit_data *sa = va;
audit_log_format(ab, " capname=");
audit_log_untrustedstring(ab, capability_names[sa->u.cap]);
}
/**
* audit_caps - audit a capability
* @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 success, error code on failure
*/
static int audit_caps(struct aa_profile *profile, struct task_struct *task,
int cap, int error)
{
struct audit_cache *ent;
int type = AUDIT_APPARMOR_AUTO;
struct common_audit_data sa;
COMMON_AUDIT_DATA_INIT(&sa, CAP);
sa.tsk = task;
sa.u.cap = cap;
sa.aad.op = OP_CAPABLE;
sa.aad.error = error;
if (likely(!error)) {
/* test if auditing is being forced */
if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
!cap_raised(profile->caps.audit, cap)))
return 0;
type = AUDIT_APPARMOR_AUDIT;
} else if (KILL_MODE(profile) ||
cap_raised(profile->caps.kill, cap)) {
type = AUDIT_APPARMOR_KILL;
} else if (cap_raised(profile->caps.quiet, cap) &&
AUDIT_MODE(profile) != AUDIT_NOQUIET &&
AUDIT_MODE(profile) != AUDIT_ALL) {
/* quiet auditing */
return error;
}
/* Do simple duplicate message elimination */
ent = &get_cpu_var(audit_cache);
if (profile == ent->profile && cap_raised(ent->caps, cap)) {
put_cpu_var(audit_cache);
if (COMPLAIN_MODE(profile))
return complain_error(error);
return error;
} else {
aa_put_profile(ent->profile);
ent->profile = aa_get_profile(profile);
cap_raise(ent->caps, cap);
}
put_cpu_var(audit_cache);
return aa_audit(type, profile, GFP_ATOMIC, &sa, audit_cb);
}
/**
* profile_capable - test if profile allows use of capability @cap
* @profile: profile being enforced (NOT NULL, NOT unconfined)
* @cap: capability to test if allowed
*
* Returns: 0 if allowed else -EPERM
*/
static int profile_capable(struct aa_profile *profile, int cap)
{
return cap_raised(profile->caps.allow, cap) ? 0 : -EPERM;
}
/**
* aa_capable - test permission to use capability
* @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
*
* Look up capability in profile capability set.
*
* Returns: 0 on success, or else an error code.
*/
int aa_capable(struct task_struct *task, struct aa_profile *profile, int cap,
int audit)
{
int error = profile_capable(profile, cap);
if (!audit) {
if (COMPLAIN_MODE(profile))
return complain_error(error);
return error;
}
return audit_caps(profile, task, cap, error);
}
/*
* AppArmor security module
*
* This file contains AppArmor functions used to manipulate object security
* contexts.
*
* Copyright (C) 1998-2008 Novell/SUSE
* Copyright 2009-2010 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2 of the
* License.
*
*
* 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
* 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.
*
* TODO
* If a task uses change_hat it currently does not return to the old
* cred or task context but instead creates a new one. Ideally the task
* should return to the previous cred if it has not been modified.
*
*/
#include "include/context.h"
#include "include/policy.h"
/**
* aa_alloc_task_context - allocate a new task_cxt
* @flags: gfp flags for allocation
*
* Returns: allocated buffer or NULL on failure
*/
struct aa_task_cxt *aa_alloc_task_context(gfp_t flags)
{
return kzalloc(sizeof(struct aa_task_cxt), flags);
}
/**
* aa_free_task_context - free a task_cxt
* @cxt: task_cxt to free (MAYBE NULL)
*/
void aa_free_task_context(struct aa_task_cxt *cxt)
{
if (cxt) {
aa_put_profile(cxt->profile);
aa_put_profile(cxt->previous);
aa_put_profile(cxt->onexec);
kzfree(cxt);
}
}
/**
* aa_dup_task_context - duplicate a task context, incrementing reference counts
* @new: a blank task context (NOT NULL)
* @old: the task context to copy (NOT NULL)
*/
void aa_dup_task_context(struct aa_task_cxt *new, const struct aa_task_cxt *old)
{
*new = *old;
aa_get_profile(new->profile);
aa_get_profile(new->previous);
aa_get_profile(new->onexec);
}
/**
* aa_replace_current_profile - replace the current tasks profiles
* @profile: new profile (NOT NULL)
*
* Returns: 0 or error on failure
*/
int aa_replace_current_profile(struct aa_profile *profile)
{
struct aa_task_cxt *cxt = current_cred()->security;
struct cred *new;
BUG_ON(!profile);
if (cxt->profile == profile)
return 0;
new = prepare_creds();
if (!new)
return -ENOMEM;
cxt = new->security;
if (unconfined(profile) || (cxt->profile->ns != profile->ns)) {
/* if switching to unconfined or a different profile namespace
* clear out context state
*/
aa_put_profile(cxt->previous);
aa_put_profile(cxt->onexec);
cxt->previous = NULL;
cxt->onexec = NULL;
cxt->token = 0;
}
/* be careful switching cxt->profile, when racing replacement it
* is possible that cxt->profile->replacedby is the reference keeping
* @profile valid, so make sure to get its reference before dropping
* the reference on cxt->profile */
aa_get_profile(profile);
aa_put_profile(cxt->profile);
cxt->profile = profile;
commit_creds(new);
return 0;
}
/**
* aa_set_current_onexec - set the tasks change_profile to happen onexec
* @profile: system profile to set at exec (MAYBE NULL to clear value)
*
* Returns: 0 or error on failure
*/
int aa_set_current_onexec(struct aa_profile *profile)
{
struct aa_task_cxt *cxt;
struct cred *new = prepare_creds();
if (!new)
return -ENOMEM;
cxt = new->security;
aa_get_profile(profile);
aa_put_profile(cxt->onexec);
cxt->onexec = profile;
commit_creds(new);
return 0;
}
/**
* aa_set_current_hat - set the current tasks hat
* @profile: profile to set as the current hat (NOT NULL)
* @token: token value that must be specified to change from the hat
*
* Do switch of tasks hat. If the task is currently in a hat
* validate the token to match.
*
* Returns: 0 or error on failure
*/
int aa_set_current_hat(struct aa_profile *profile, u64 token)
{
struct aa_task_cxt *cxt;
struct cred *new = prepare_creds();
if (!new)
return -ENOMEM;
BUG_ON(!profile);
cxt = new->security;
if (!cxt->previous) {
/* transfer refcount */
cxt->previous = cxt->profile;
cxt->token = token;
} else if (cxt->token == token) {
aa_put_profile(cxt->profile);
} else {
/* previous_profile && cxt->token != token */
abort_creds(new);
return -EACCES;
}
cxt->profile = aa_get_profile(aa_newest_version(profile));
/* clear exec on switching context */
aa_put_profile(cxt->onexec);
cxt->onexec = NULL;
commit_creds(new);
return 0;
}
/**
* aa_restore_previous_profile - exit from hat context restoring the profile
* @token: the token that must be matched to exit hat context
*
* Attempt to return out of a hat to the previous profile. The token
* must match the stored token value.
*
* Returns: 0 or error of failure
*/
int aa_restore_previous_profile(u64 token)
{
struct aa_task_cxt *cxt;
struct cred *new = prepare_creds();
if (!new)
return -ENOMEM;
cxt = new->security;
if (cxt->token != token) {
abort_creds(new);
return -EACCES;
}
/* ignore restores when there is no saved profile */
if (!cxt->previous) {
abort_creds(new);
return 0;
}
aa_put_profile(cxt->profile);
cxt->profile = aa_newest_version(cxt->previous);
BUG_ON(!cxt->profile);
if (unlikely(cxt->profile != cxt->previous)) {
aa_get_profile(cxt->profile);
aa_put_profile(cxt->previous);
}
/* clear exec && prev information when restoring to previous context */
cxt->previous = NULL;
cxt->token = 0;
aa_put_profile(cxt->onexec);
cxt->onexec = NULL;
commit_creds(new);
return 0;
}
This diff is collapsed.
This diff is collapsed.
/*
* AppArmor security module
*
* This file contains AppArmor basic global and lib definitions
*
* Copyright (C) 1998-2008 Novell/SUSE
* Copyright 2009-2010 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2 of the
* License.
*/
#ifndef __APPARMOR_H
#define __APPARMOR_H
#include <linux/fs.h>
#include "match.h"
/* Control parameters settable through module/boot flags */
extern enum audit_mode aa_g_audit;
extern int aa_g_audit_header;
extern int aa_g_debug;
extern int aa_g_lock_policy;
extern int aa_g_logsyscall;
extern int aa_g_paranoid_load;
extern unsigned int aa_g_path_max;
/*
* DEBUG remains global (no per profile flag) since it is mostly used in sysctl
* which is not related to profile accesses.
*/
#define AA_DEBUG(fmt, args...) \
do { \
if (aa_g_debug && printk_ratelimit()) \
printk(KERN_DEBUG "AppArmor: " fmt, ##args); \
} while (0)
#define AA_ERROR(fmt, args...) \
do { \
if (printk_ratelimit()) \
printk(KERN_ERR "AppArmor: " fmt, ##args); \
} while (0)
/* Flag indicating whether initialization completed */
extern int apparmor_initialized __initdata;
/* fn's in lib */
char *aa_split_fqname(char *args, char **ns_name);
void aa_info_message(const char *str);
void *kvmalloc(size_t size);
void 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
*
* 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 separate pairs.
*/
static inline unsigned int aa_dfa_null_transition(struct aa_dfa *dfa,
unsigned int start)
{
/* the null transition only needs the string's null terminator byte */
return aa_dfa_match_len(dfa, start, "", 1);
}
static inline bool mediated_filesystem(struct inode *inode)
{
return !(inode->i_sb->s_flags & MS_NOUSER);
}
#endif /* __APPARMOR_H */
/*
* AppArmor security module
*
* This file contains AppArmor filesystem definitions.
*
* Copyright (C) 1998-2008 Novell/SUSE
* Copyright 2009-2010 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2 of the
* License.
*/
#ifndef __AA_APPARMORFS_H
#define __AA_APPARMORFS_H
extern void __init aa_destroy_aafs(void);
#endif /* __AA_APPARMORFS_H */
/*
* AppArmor security module
*
* This file contains AppArmor auditing function definitions.
*
* Copyright (C) 1998-2008 Novell/SUSE
* Copyright 2009-2010 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2 of the
* License.
*/
#ifndef __AA_AUDIT_H
#define __AA_AUDIT_H
#include <linux/audit.h>
#include <linux/fs.h>
#include <linux/lsm_audit.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include "file.h"
struct aa_profile;
extern const char *audit_mode_names[];
#define AUDIT_MAX_INDEX 5
#define AUDIT_APPARMOR_AUTO 0 /* auto choose audit message type */
enum audit_mode {
AUDIT_NORMAL, /* follow normal auditing of accesses */
AUDIT_QUIET_DENIED, /* quiet all denied access messages */
AUDIT_QUIET, /* quiet all messages */
AUDIT_NOQUIET, /* do not quiet audit messages */
AUDIT_ALL /* audit all accesses */
};
enum audit_type {
AUDIT_APPARMOR_AUDIT,
AUDIT_APPARMOR_ALLOWED,
AUDIT_APPARMOR_DENIED,
AUDIT_APPARMOR_HINT,
AUDIT_APPARMOR_STATUS,
AUDIT_APPARMOR_ERROR,
AUDIT_APPARMOR_KILL
};
extern const char *op_table[];
enum aa_ops {
OP_NULL,
OP_SYSCTL,
OP_CAPABLE,
OP_UNLINK,
OP_MKDIR,
OP_RMDIR,
OP_MKNOD,
OP_TRUNC,
OP_LINK,
OP_SYMLINK,
OP_RENAME_SRC,
OP_RENAME_DEST,
OP_CHMOD,
OP_CHOWN,
OP_GETATTR,
OP_OPEN,
OP_FPERM,
OP_FLOCK,
OP_FMMAP,
OP_FMPROT,
OP_CREATE,
OP_POST_CREATE,
OP_BIND,
OP_CONNECT,
OP_LISTEN,
OP_ACCEPT,
OP_SENDMSG,
OP_RECVMSG,
OP_GETSOCKNAME,
OP_GETPEERNAME,
OP_GETSOCKOPT,
OP_SETSOCKOPT,
OP_SOCK_SHUTDOWN,
OP_PTRACE,
OP_EXEC,
OP_CHANGE_HAT,
OP_CHANGE_PROFILE,
OP_CHANGE_ONEXEC,
OP_SETPROCATTR,
OP_SETRLIMIT,
OP_PROF_REPL,
OP_PROF_LOAD,
OP_PROF_RM,
};
/* 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 *));
static inline int complain_error(int error)
{
if (error == -EPERM || error == -EACCES)
return 0;
return error;
}
#endif /* __AA_AUDIT_H */
/*
* AppArmor security module
*
* This file contains AppArmor capability mediation definitions.
*
* Copyright (C) 1998-2008 Novell/SUSE
* Copyright 2009-2010 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2 of the
* License.
*/
#ifndef __AA_CAPABILITY_H
#define __AA_CAPABILITY_H
#include <linux/sched.h>
struct aa_profile;
/* aa_caps - confinement data for capabilities
* @allowed: capabilities mask
* @audit: caps that are to be audited
* @quiet: caps that should not be audited
* @kill: caps that when requested will result in the task being killed
* @extended: caps that are subject finer grained mediation
*/
struct aa_caps {
kernel_cap_t allow;
kernel_cap_t audit;
kernel_cap_t quiet;
kernel_cap_t kill;
kernel_cap_t extended;
};
int aa_capable(struct task_struct *task, struct aa_profile *profile, int cap,
int audit);
static inline void aa_free_cap_rules(struct aa_caps *caps)
{
/* NOP */
}
#endif /* __AA_CAPBILITY_H */
/*
* AppArmor security module
*
* This file contains AppArmor contexts used to associate "labels" to objects.
*
* Copyright (C) 1998-2008 Novell/SUSE
* Copyright 2009-2010 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2 of the
* License.
*/
#ifndef __AA_CONTEXT_H
#define __AA_CONTEXT_H
#include <linux/cred.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include "policy.h"
/* struct aa_file_cxt - the AppArmor context the file was opened in
* @perms: the permission the file was opened with
*
* The file_cxt could currently be directly stored in file->f_security
* as the profile reference is now stored in the f_cred. However the
* cxt struct will expand in the future so we keep the struct.
*/
struct aa_file_cxt {
u16 allow;
};
/**
* aa_alloc_file_context - allocate file_cxt
* @gfp: gfp flags for allocation
*
* Returns: file_cxt or NULL on failure
*/
static inline struct aa_file_cxt *aa_alloc_file_context(gfp_t gfp)
{
return kzalloc(sizeof(struct aa_file_cxt), gfp);
}
/**
* aa_free_file_context - free a file_cxt
* @cxt: file_cxt to free (MAYBE_NULL)
*/
static inline void aa_free_file_context(struct aa_file_cxt *cxt)
{
if (cxt)
kzfree(cxt);
}
/**
* struct aa_task_cxt - primary label for confined tasks
* @profile: the current profile (NOT NULL)
* @exec: profile to transition to on next exec (MAYBE NULL)
* @previous: profile the task may return to (MAYBE NULL)
* @token: magic value the task must know for returning to @previous_profile
*
* Contains the task's current profile (which could change due to
* change_hat). Plus the hat_magic needed during change_hat.
*
* TODO: make so a task can be confined by a stack of contexts
*/
struct aa_task_cxt {
struct aa_profile *profile;
struct aa_profile *onexec;
struct aa_profile *previous;
u64 token;
};
struct aa_task_cxt *aa_alloc_task_context(gfp_t flags);
void aa_free_task_context(struct aa_task_cxt *cxt);
void aa_dup_task_context(struct aa_task_cxt *new,
const struct aa_task_cxt *old);
int aa_replace_current_profile(struct aa_profile *profile);
int aa_set_current_onexec(struct aa_profile *profile);
int aa_set_current_hat(struct aa_profile *profile, u64 token);
int aa_restore_previous_profile(u64 cookie);
/**
* __aa_task_is_confined - determine if @task has any confinement
* @task: task to check confinement of (NOT NULL)
*
* If @task != current needs to be called in RCU safe critical section
*/
static inline bool __aa_task_is_confined(struct task_struct *task)
{
struct aa_task_cxt *cxt = __task_cred(task)->security;
BUG_ON(!cxt || !cxt->profile);
if (unconfined(aa_newest_version(cxt->profile)))
return 0;
return 1;
}
/**
* aa_cred_profile - obtain cred's profiles
* @cred: cred to obtain profiles from (NOT NULL)
*
* Returns: confining profile
*
* does NOT increment reference count
*/
static inline struct aa_profile *aa_cred_profile(const struct cred *cred)
{
struct aa_task_cxt *cxt = cred->security;
BUG_ON(!cxt || !cxt->profile);
return aa_newest_version(cxt->profile);
}
/**
* __aa_current_profile - find the current tasks confining profile
*
* Returns: up to date confining profile or the ns unconfined profile (NOT NULL)
*
* This fn will not update the tasks cred to the most up to date version
* of the profile so it is safe to call when inside of locks.
*/
static inline struct aa_profile *__aa_current_profile(void)
{
return aa_cred_profile(current_cred());
}
/**
* aa_current_profile - find the current tasks confining profile and do updates
*
* Returns: up to date confining profile or the ns unconfined profile (NOT NULL)
*
* This fn will update the tasks cred structure if the profile has been
* replaced. Not safe to call inside locks
*/
static inline struct aa_profile *aa_current_profile(void)
{
const struct aa_task_cxt *cxt = current_cred()->security;
struct aa_profile *profile;
BUG_ON(!cxt || !cxt->profile);
profile = aa_newest_version(cxt->profile);
/*
* Whether or not replacement succeeds, use newest profile so
* there is no need to update it after replacement.
*/
if (unlikely((cxt->profile != profile)))
aa_replace_current_profile(profile);
return profile;
}
#endif /* __AA_CONTEXT_H */
/*
* AppArmor security module
*
* This file contains AppArmor security domain transition function definitions.
*
* Copyright (C) 1998-2008 Novell/SUSE
* Copyright 2009-2010 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2 of the
* License.
*/
#include <linux/binfmts.h>
#include <linux/types.h>
#ifndef __AA_DOMAIN_H
#define __AA_DOMAIN_H
struct aa_domain {
int size;
char **table;
};
int apparmor_bprm_set_creds(struct linux_binprm *bprm);
int apparmor_bprm_secureexec(struct linux_binprm *bprm);
void apparmor_bprm_committing_creds(struct linux_binprm *bprm);
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, bool onexec,
bool permtest);
#endif /* __AA_DOMAIN_H */
/*
* AppArmor security module
*
* This file contains AppArmor file mediation function definitions.
*
* Copyright (C) 1998-2008 Novell/SUSE
* Copyright 2009-2010 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2 of the
* License.
*/
#ifndef __AA_FILE_H
#define __AA_FILE_H
#include <linux/path.h>
#include "domain.h"
#include "match.h"
struct aa_profile;
/*
* We use MAY_EXEC, MAY_WRITE, MAY_READ, MAY_APPEND and the following flags
* for profile permissions
*/
#define AA_MAY_CREATE 0x0010
#define AA_MAY_DELETE 0x0020
#define AA_MAY_META_WRITE 0x0040
#define AA_MAY_META_READ 0x0080
#define AA_MAY_CHMOD 0x0100
#define AA_MAY_CHOWN 0x0200
#define AA_MAY_LOCK 0x0400
#define AA_EXEC_MMAP 0x0800
#define AA_MAY_LINK 0x1000
#define AA_LINK_SUBSET AA_MAY_LOCK /* overlaid */
#define AA_MAY_ONEXEC 0x40000000 /* exec allows onexec */
#define AA_MAY_CHANGE_PROFILE 0x80000000
#define AA_MAY_CHANGEHAT 0x80000000 /* ctrl auditing only */
#define AA_AUDIT_FILE_MASK (MAY_READ | MAY_WRITE | MAY_EXEC | MAY_APPEND |\
AA_MAY_CREATE | AA_MAY_DELETE | \
AA_MAY_META_READ | AA_MAY_META_WRITE | \
AA_MAY_CHMOD | AA_MAY_CHOWN | AA_MAY_LOCK | \
AA_EXEC_MMAP | AA_MAY_LINK)
/*
* The xindex is broken into 3 parts
* - index - an index into either the exec name table or the variable table
* - exec type - which determines how the executable name and index are used
* - flags - which modify how the destination name is applied
*/
#define AA_X_INDEX_MASK 0x03ff
#define AA_X_TYPE_MASK 0x0c00
#define AA_X_TYPE_SHIFT 10
#define AA_X_NONE 0x0000
#define AA_X_NAME 0x0400 /* use executable name px */
#define AA_X_TABLE 0x0800 /* use a specified name ->n# */
#define AA_X_UNSAFE 0x1000
#define AA_X_CHILD 0x2000 /* make >AA_X_NONE apply to children */
#define AA_X_INHERIT 0x4000
#define AA_X_UNCONFINED 0x8000
/* AA_SECURE_X_NEEDED - is passed in the bprm->unsafe field */
#define AA_SECURE_X_NEEDED 0x8000
/* need to make conditional which ones are being set */
struct path_cond {
uid_t uid;
umode_t mode;
};
/* struct file_perms - file permission
* @allow: mask of permissions that are allowed
* @audit: mask of permissions to force an audit message for
* @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
*
* The @audit and @queit mask should be mutually exclusive.
*/
struct file_perms {
u32 allow;
u32 audit;
u32 quiet;
u32 kill;
u16 xindex;
};
extern struct file_perms nullperms;
#define COMBINED_PERM_MASK(X) ((X).allow | (X).audit | (X).quiet | (X).kill)
/* FIXME: split perms from dfa and match this to description
* also add delegation info.
*/
static inline u16 dfa_map_xindex(u16 mask)
{
u16 old_index = (mask >> 10) & 0xf;
u16 index = 0;
if (mask & 0x100)
index |= AA_X_UNSAFE;
if (mask & 0x200)
index |= AA_X_INHERIT;
if (mask & 0x80)
index |= AA_X_UNCONFINED;
if (old_index == 1) {
index |= AA_X_UNCONFINED;
} else if (old_index == 2) {
index |= AA_X_NAME;
} else if (old_index == 3) {
index |= AA_X_NAME | AA_X_CHILD;
} else {
index |= AA_X_TABLE;
index |= old_index - 4;
}
return index;
}
/*
* map old dfa inline permissions to new format
*/
#define dfa_user_allow(dfa, state) (((ACCEPT_TABLE(dfa)[state]) & 0x7f) | \
((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))
#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)
#define dfa_other_xindex(dfa, state) \
dfa_map_xindex((ACCEPT_TABLE(dfa)[state] >> 14) & 0x3fff)
int aa_audit_file(struct aa_profile *profile, struct file_perms *perms,
gfp_t gfp, int op, u32 request, const char *name,
const char *target, uid_t ouid, const char *info, int error);
/**
* struct aa_file_rules - components used for file rule permissions
* @dfa: dfa to match path names and conditionals against
* @perms: permission table indexed by the matched state accept entry of @dfa
* @trans: transition table for indexed by named x transitions
*
* File permission are determined by matching a path against @dfa and then
* then using the value of the accept entry for the matching state as
* an index into @perms. If a named exec transition is required it is
* looked up in the transition table.
*/
struct aa_file_rules {
unsigned int start;
struct aa_dfa *dfa;
/* struct perms perms; */
struct aa_domain trans;
/* TODO: add delegate table */
};
unsigned int aa_str_perms(struct aa_dfa *dfa, unsigned int start,
const char *name, struct path_cond *cond,
struct file_perms *perms);
int aa_path_perm(int op, struct aa_profile *profile, struct path *path,
int 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,
u32 request);
static inline void aa_free_file_rules(struct aa_file_rules *rules)
{
aa_put_dfa(rules->dfa);
aa_free_domain_entries(&rules->trans);
}
#define ACC_FMODE(x) (("\000\004\002\006"[(x)&O_ACCMODE]) | (((x) << 1) & 0x40))
/* from namei.c */
#define MAP_OPEN_FLAGS(x) ((((x) + 1) & O_ACCMODE) ? (x) + 1 : (x))
/**
* aa_map_file_perms - map file flags to AppArmor permissions
* @file: open file to map flags to AppArmor permissions
*
* Returns: apparmor permission set for the file
*/
static inline u32 aa_map_file_to_perms(struct file *file)
{
int flags = MAP_OPEN_FLAGS(file->f_flags);
u32 perms = ACC_FMODE(file->f_mode);
if ((flags & O_APPEND) && (perms & MAY_WRITE))
perms = (perms & ~MAY_WRITE) | MAY_APPEND;
/* trunc implies write permission */
if (flags & O_TRUNC)
perms |= MAY_WRITE;
if (flags & O_CREAT)
perms |= AA_MAY_CREATE;
return perms;
}
#endif /* __AA_FILE_H */
/*
* AppArmor security module
*
* This file contains AppArmor ipc mediation function definitions.
*
* Copyright (C) 1998-2008 Novell/SUSE
* Copyright 2009-2010 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2 of the
* License.
*/
#ifndef __AA_IPC_H
#define __AA_IPC_H
#include <linux/sched.h>
struct aa_profile;
int aa_may_ptrace(struct task_struct *tracer_task, struct aa_profile *tracer,
struct aa_profile *tracee, unsigned int mode);
int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee,
unsigned int mode);
#endif /* __AA_IPC_H */
/*
* AppArmor security module
*
* This file contains AppArmor policy dfa matching engine definitions.
*
* Copyright (C) 1998-2008 Novell/SUSE
* Copyright 2009-2010 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2 of the
* License.
*/
#ifndef __AA_MATCH_H
#define __AA_MATCH_H
#include <linux/workqueue.h>
#define DFA_NOMATCH 0
#define DFA_START 1
#define DFA_VALID_PERM_MASK 0xffffffff
#define DFA_VALID_PERM2_MASK 0xffffffff
/**
* The format used for transition tables is based on the GNU flex table
* file format (--tables-file option; see Table File Format in the flex
* info pages and the flex sources for documentation). The magic number
* used in the header is 0x1B5E783D insted of 0xF13C57B1 though, because
* the YY_ID_CHK (check) and YY_ID_DEF (default) tables are used
* slightly differently (see the apparmor-parser package).
*/
#define YYTH_MAGIC 0x1B5E783D
#define YYTH_DEF_RECURSE 0x1 /* DEF Table is recursive */
struct table_set_header {
u32 th_magic; /* YYTH_MAGIC */
u32 th_hsize;
u32 th_ssize;
u16 th_flags;
char th_version[];
};
/* The YYTD_ID are one less than flex table mappings. The flex id
* has 1 subtracted at table load time, this allows us to directly use the
* ID's as indexes.
*/
#define YYTD_ID_ACCEPT 0
#define YYTD_ID_BASE 1
#define YYTD_ID_CHK 2
#define YYTD_ID_DEF 3
#define YYTD_ID_EC 4
#define YYTD_ID_META 5
#define YYTD_ID_ACCEPT2 6
#define YYTD_ID_NXT 7
#define YYTD_ID_TSIZE 8
#define YYTD_DATA8 1
#define YYTD_DATA16 2
#define YYTD_DATA32 4
#define YYTD_DATA64 8
/* Each ACCEPT2 table gets 6 dedicated flags, YYTD_DATAX define the
* first flags
*/
#define ACCEPT1_FLAGS(X) ((X) & 0x3f)
#define ACCEPT2_FLAGS(X) ACCEPT1_FLAGS((X) >> YYTD_ID_ACCEPT2)
#define TO_ACCEPT1_FLAG(X) ACCEPT1_FLAGS(X)
#define TO_ACCEPT2_FLAG(X) (ACCEPT1_FLAGS(X) << YYTD_ID_ACCEPT2)
#define DFA_FLAG_VERIFY_STATES 0x1000
struct table_header {
u16 td_id;
u16 td_flags;
u32 td_hilen;
u32 td_lolen;
char td_data[];
};
#define DEFAULT_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_DEF]->td_data))
#define BASE_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_BASE]->td_data))
#define NEXT_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_NXT]->td_data))
#define CHECK_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_CHK]->td_data))
#define EQUIV_TABLE(DFA) ((u8 *)((DFA)->tables[YYTD_ID_EC]->td_data))
#define ACCEPT_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT]->td_data))
#define ACCEPT_TABLE2(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT2]->td_data))
struct aa_dfa {
struct kref count;
u16 flags;
struct table_header *tables[YYTD_ID_TSIZE];
};
#define byte_to_byte(X) (X)
#define UNPACK_ARRAY(TABLE, BLOB, LEN, TYPE, NTOHX) \
do { \
typeof(LEN) __i; \
TYPE *__t = (TYPE *) TABLE; \
TYPE *__b = (TYPE *) BLOB; \
for (__i = 0; __i < LEN; __i++) { \
__t[__i] = NTOHX(__b[__i]); \
} \
} while (0)
static inline size_t table_size(size_t len, size_t el_size)
{
return ALIGN(sizeof(struct table_header) + len * el_size, 8);
}
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);
unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start,
const char *str);
void aa_dfa_free_kref(struct kref *kref);
/**
* aa_put_dfa - put a dfa refcount
* @dfa: dfa to put refcount (MAYBE NULL)
*
* Requires: if @dfa != NULL that a valid refcount be held
*/
static inline void aa_put_dfa(struct aa_dfa *dfa)
{
if (dfa)
kref_put(&dfa->count, aa_dfa_free_kref);
}
#endif /* __AA_MATCH_H */
/*
* AppArmor security module
*
* This file contains AppArmor basic path manipulation function definitions.
*
* Copyright (C) 1998-2008 Novell/SUSE
* Copyright 2009-2010 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2 of the
* License.
*/
#ifndef __AA_PATH_H
#define __AA_PATH_H
enum path_flags {
PATH_IS_DIR = 0x1, /* path is a directory */
PATH_CONNECT_PATH = 0x4, /* connect disconnected paths to / */
PATH_CHROOT_REL = 0x8, /* do path lookup relative to chroot */
PATH_CHROOT_NSCONNECT = 0x10, /* connect paths that are at ns root */
PATH_DELEGATE_DELETED = 0x08000, /* delegate deleted files */
PATH_MEDIATE_DELETED = 0x10000, /* mediate deleted paths */
};
int aa_get_name(struct path *path, int flags, char **buffer, const char **name);
#endif /* __AA_PATH_H */
/*
* AppArmor security module
*
* This file contains AppArmor policy definitions.
*
* Copyright (C) 1998-2008 Novell/SUSE
* Copyright 2009-2010 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2 of the
* License.
*/
#ifndef __AA_POLICY_H
#define __AA_POLICY_H
#include <linux/capability.h>
#include <linux/cred.h>
#include <linux/kref.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/socket.h>
#include "apparmor.h"
#include "audit.h"
#include "capability.h"
#include "domain.h"
#include "file.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)->mode == APPARMOR_COMPLAIN))
#define KILL_MODE(_profile) \
((aa_g_profile_mode == APPARMOR_KILL) || \
((_profile)->mode == APPARMOR_KILL))
#define PROFILE_IS_HAT(_profile) ((_profile)->flags & PFLAG_HAT)
/*
* FIXME: currently need a clean way to replace and remove profiles as a
* set. It should be done at the namespace level.
* Either, with a set of profiles loaded at the namespace level or via
* a mark and remove marked interface.
*/
enum profile_mode {
APPARMOR_ENFORCE, /* enforce access rules */
APPARMOR_COMPLAIN, /* allow and log access violations */
APPARMOR_KILL, /* kill task on access violation */
};
enum profile_flags {
PFLAG_HAT = 1, /* profile is a hat */
PFLAG_UNCONFINED = 2, /* profile is an unconfined profile */
PFLAG_NULL = 4, /* profile is null learning profile */
PFLAG_IX_ON_NAME_ERROR = 8, /* fallback to ix on name lookup fail */
PFLAG_IMMUTABLE = 0x10, /* don't allow changes/replacement */
PFLAG_USER_DEFINED = 0x20, /* user based profile - lower privs */
PFLAG_NO_LIST_REF = 0x40, /* list doesn't keep profile ref */
PFLAG_OLD_NULL_TRANS = 0x100, /* use // as the null transition */
/* These flags must correspond with PATH_flags */
PFLAG_MEDIATE_DELETED = 0x10000, /* mediate instead delegate deleted */
};
struct aa_profile;
/* struct aa_policy - common part of both namespaces and profiles
* @name: name of the object
* @hname - The hierarchical name
* @count: reference count of the obj
* @list: list policy object is on
* @profiles: head of the profiles list contained in the object
*/
struct aa_policy {
char *name;
char *hname;
struct kref count;
struct list_head list;
struct list_head profiles;
};
/* struct aa_ns_acct - accounting of profiles in namespace
* @max_size: maximum space allowed for all profiles in namespace
* @max_count: maximum number of profiles that can be in this namespace
* @size: current size of profiles
* @count: current count of profiles (includes null profiles)
*/
struct aa_ns_acct {
int max_size;
int max_count;
int size;
int count;
};
/* struct aa_namespace - namespace for a set of profiles
* @base: common policy
* @parent: parent of namespace
* @lock: lock for modifying the object
* @acct: accounting for the namespace
* @unconfined: special unconfined profile for the namespace
* @sub_ns: list of namespaces under the current namespace.
*
* An aa_namespace defines the set profiles that are searched to determine
* which profile to attach to a task. Profiles can not be shared between
* aa_namespaces and profile names within a namespace are guaranteed to be
* unique. When profiles in separate namespaces have the same name they
* are NOT considered to be equivalent.
*
* Namespaces are hierarchical and only namespaces and profiles below the
* current namespace are visible.
*
* Namespace names must be unique and can not contain the characters :/\0
*
* FIXME TODO: add vserver support of namespaces (can it all be done in
* userspace?)
*/
struct aa_namespace {
struct aa_policy base;
struct aa_namespace *parent;
rwlock_t lock;
struct aa_ns_acct acct;
struct aa_profile *unconfined;
struct list_head sub_ns;
};
/* struct aa_profile - basic confinement data
* @base - base components of the profile (name, refcount, lists, lock ...)
* @parent: parent of profile
* @ns: namespace the profile is in
* @replacedby: is set to the profile that replaced this profile
* @rename: optional profile name that this profile renamed
* @xmatch: optional extended matching for unconfined executables names
* @xmatch_len: xmatch prefix len, used to determine xmatch priority
* @sid: the unique security id number of this profile
* @audit: the auditing mode of the profile
* @mode: the enforcement mode of the profile
* @flags: flags controlling profile behavior
* @path_flags: flags controlling path generation behavior
* @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
* @rlimits: rlimits for the profile
*
* The AppArmor profile contains the basic confinement data. Each profile
* has a name, and exists in a namespace. The @name and @exec_match are
* used to determine profile attachment against unconfined tasks. All other
* attachments are determined by profile X transition rules.
*
* The @replacedby field is write protected by the profile lock. Reads
* are assumed to be atomic, and are done without locking.
*
* Profiles have a hierarchy where hats and children profiles keep
* a reference to their parent.
*
* Profile names can not begin with a : and can not contain the \0
* character. If a profile name begins with / it will be considered when
* determining profile attachment on "unconfined" tasks.
*/
struct aa_profile {
struct aa_policy base;
struct aa_profile *parent;
struct aa_namespace *ns;
struct aa_profile *replacedby;
const char *rename;
struct aa_dfa *xmatch;
int xmatch_len;
u32 sid;
enum audit_mode audit;
enum profile_mode mode;
u32 flags;
u32 path_flags;
int size;
struct aa_file_rules file;
struct aa_caps caps;
struct aa_rlimit rlimits;
};
extern struct aa_namespace *root_ns;
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 *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);
void aa_free_namespace_kref(struct kref *kref);
struct aa_namespace *aa_find_namespace(struct aa_namespace *root,
const char *name);
static inline struct aa_policy *aa_get_common(struct aa_policy *c)
{
if (c)
kref_get(&c->count);
return c;
}
/**
* aa_get_namespace - increment references count on @ns
* @ns: namespace to increment reference count of (MAYBE NULL)
*
* Returns: pointer to @ns, if @ns is NULL returns NULL
* Requires: @ns must be held with valid refcount when called
*/
static inline struct aa_namespace *aa_get_namespace(struct aa_namespace *ns)
{
if (ns)
kref_get(&(ns->base.count));
return ns;
}
/**
* aa_put_namespace - decrement refcount on @ns
* @ns: namespace to put reference of
*
* Decrement reference count of @ns and if no longer in use free it
*/
static inline void aa_put_namespace(struct aa_namespace *ns)
{
if (ns)
kref_put(&ns->base.count, aa_free_namespace_kref);
}
struct aa_profile *aa_alloc_profile(const char *name);
struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat);
void aa_free_profile_kref(struct kref *kref);
struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name);
struct aa_profile *aa_lookup_profile(struct aa_namespace *ns, const char *name);
struct aa_profile *aa_match_profile(struct aa_namespace *ns, const char *name);
ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace);
ssize_t aa_remove_profiles(char *name, size_t size);
#define PROF_ADD 1
#define PROF_REPLACE 0
#define unconfined(X) ((X)->flags & PFLAG_UNCONFINED)
/**
* aa_newest_version - find the newest version of @profile
* @profile: the profile to check for newer versions of (NOT NULL)
*
* Returns: newest version of @profile, if @profile is the newest version
* return @profile.
*
* NOTE: the profile returned is not refcounted, The refcount on @profile
* must be held until the caller decides what to do with the returned newest
* version.
*/
static inline struct aa_profile *aa_newest_version(struct aa_profile *profile)
{
while (profile->replacedby)
profile = profile->replacedby;
return profile;
}
/**
* aa_get_profile - increment refcount on profile @p
* @p: profile (MAYBE NULL)
*
* Returns: pointer to @p if @p is NULL will return NULL
* Requires: @p must be held with valid refcount when called
*/
static inline struct aa_profile *aa_get_profile(struct aa_profile *p)
{
if (p)
kref_get(&(p->base.count));
return p;
}
/**
* aa_put_profile - decrement refcount on profile @p
* @p: profile (MAYBE NULL)
*/
static inline void aa_put_profile(struct aa_profile *p)
{
if (p)
kref_put(&p->base.count, aa_free_profile_kref);
}
static inline int AUDIT_MODE(struct aa_profile *profile)
{
if (aa_g_audit != AUDIT_NORMAL)
return aa_g_audit;
return profile->audit;
}
bool aa_may_manage_policy(int op);
#endif /* __AA_POLICY_H */
/*
* AppArmor security module
*
* This file contains AppArmor policy loading interface function definitions.
*
* Copyright (C) 1998-2008 Novell/SUSE
* Copyright 2009-2010 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2 of the
* License.
*/
#ifndef __POLICY_INTERFACE_H
#define __POLICY_INTERFACE_H
struct aa_profile *aa_unpack(void *udata, size_t size, const char **ns);
#endif /* __POLICY_INTERFACE_H */
/*
* AppArmor security module
*
* This file contains AppArmor /proc/<pid>/attr/ interface function definitions.
*
* Copyright (C) 1998-2008 Novell/SUSE
* Copyright 2009-2010 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2 of the
* License.
*/
#ifndef __AA_PROCATTR_H
#define __AA_PROCATTR_H
#define AA_DO_TEST 1
#define AA_ONEXEC 1
int aa_getprocattr(struct aa_profile *profile, char **string);
int aa_setprocattr_changehat(char *args, size_t size, int test);
int aa_setprocattr_changeprofile(char *fqname, bool onexec, int test);
int aa_setprocattr_permipc(char *fqname);
#endif /* __AA_PROCATTR_H */
/*
* AppArmor security module
*
* This file contains AppArmor resource limits function definitions.
*
* Copyright (C) 1998-2008 Novell/SUSE
* Copyright 2009-2010 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2 of the
* License.
*/
#ifndef __AA_RESOURCE_H
#define __AA_RESOURCE_H
#include <linux/resource.h>
#include <linux/sched.h>
struct aa_profile;
/* struct aa_rlimit - rlimit settings for the profile
* @mask: which hard limits to set
* @limits: rlimit values that override task limits
*
* AppArmor rlimits are used to set confined task rlimits. Only the
* limits specified in @mask will be controlled by apparmor.
*/
struct aa_rlimit {
unsigned int mask;
struct rlimit limits[RLIM_NLIMITS];
};
int aa_map_resource(int resource);
int aa_task_setrlimit(struct aa_profile *profile, unsigned int resource,
struct rlimit *new_rlim);
void __aa_transition_rlimits(struct aa_profile *old, struct aa_profile *new);
static inline void aa_free_rlimit_rules(struct aa_rlimit *rlims)
{
/* NOP */
}
#endif /* __AA_RESOURCE_H */
/*
* AppArmor security module
*
* This file contains AppArmor security identifier (sid) definitions
*
* Copyright 2009-2010 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2 of the
* License.
*/
#ifndef __AA_SID_H
#define __AA_SID_H
#include <linux/types.h>
struct aa_profile;
u32 aa_alloc_sid(void);
void aa_free_sid(u32 sid);
#endif /* __AA_SID_H */
/*
* AppArmor security module
*
* This file contains AppArmor ipc mediation
*
* Copyright (C) 1998-2008 Novell/SUSE
* Copyright 2009-2010 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2 of the
* License.
*/
#include <linux/gfp.h>
#include <linux/ptrace.h>
#include "include/audit.h"
#include "include/capability.h"
#include "include/context.h"
#include "include/policy.h"
/* call back to audit ptrace fields */
static void audit_cb(struct audit_buffer *ab, void *va)
{
struct common_audit_data *sa = va;
audit_log_format(ab, " target=");
audit_log_untrustedstring(ab, sa->aad.target);
}
/**
* aa_audit_ptrace - do auditing for ptrace
* @profile: profile being enforced (NOT NULL)
* @target: profile being traced (NOT NULL)
* @error: error condition
*
* Returns: %0 or error code
*/
static int aa_audit_ptrace(struct aa_profile *profile,
struct aa_profile *target, int error)
{
struct common_audit_data sa;
COMMON_AUDIT_DATA_INIT(&sa, NONE);
sa.aad.op = OP_PTRACE;
sa.aad.target = target;
sa.aad.error = error;
return aa_audit(AUDIT_APPARMOR_AUTO, profile, GFP_ATOMIC, &sa,
audit_cb);
}
/**
* aa_may_ptrace - test if tracer task can trace the tracee
* @tracer_task: task who will do the tracing (NOT NULL)
* @tracer: profile of the task doing the tracing (NOT NULL)
* @tracee: task to be traced
* @mode: whether PTRACE_MODE_READ || PTRACE_MODE_ATTACH
*
* Returns: %0 else error code if permission denied or error
*/
int aa_may_ptrace(struct task_struct *tracer_task, struct aa_profile *tracer,
struct aa_profile *tracee, unsigned int mode)
{
/* TODO: currently only based on capability, not extended ptrace
* rules,
* Test mode for PTRACE_MODE_READ || PTRACE_MODE_ATTACH
*/
if (unconfined(tracer) || tracer == tracee)
return 0;
/* log this capability request */
return aa_capable(tracer_task, tracer, CAP_SYS_PTRACE, 1);
}
/**
* aa_ptrace - do ptrace permission check and auditing
* @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
*/
int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee,
unsigned int mode)
{
/*
* tracer can ptrace tracee when
* - tracer is unconfined ||
* - tracer is in complain mode
* - tracer has rules allowing it to trace tracee currently this is:
* - confined by the same profile ||
* - tracer profile has CAP_SYS_PTRACE
*/
struct aa_profile *tracer_p;
/* cred released below */
const struct cred *cred = get_task_cred(tracer);
int error = 0;
tracer_p = aa_cred_profile(cred);
if (!unconfined(tracer_p)) {
/* lcred released below */
const struct cred *lcred = get_task_cred(tracee);
struct aa_profile *tracee_p = aa_cred_profile(lcred);
error = aa_may_ptrace(tracer, tracer_p, tracee_p, mode);
error = aa_audit_ptrace(tracer_p, tracee_p, error);
put_cred(lcred);
}
put_cred(cred);
return error;
}
/*
* AppArmor security module
*
* This file contains basic common functions used in AppArmor
*
* Copyright (C) 1998-2008 Novell/SUSE
* Copyright 2009-2010 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2 of the
* License.
*/
#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 (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
*
* Split a namespace name from a profile name (see policy.c for naming
* description). If a portion of the name is missing it returns NULL for
* that portion.
*
* NOTE: may modify the @fqname string. The pointers returned point
* into the @fqname string.
*/
char *aa_split_fqname(char *fqname, char **ns_name)
{
char *name = strim(fqname);
*ns_name = NULL;
if (name[0] == ':') {
char *split = strchr(&name[1], ':');
if (split) {
/* overwrite ':' with \0 */
*split = 0;
name = skip_spaces(split + 1);
} else
/* a ns name without a following profile is allowed */
name = NULL;
*ns_name = &name[1];
}
if (name && *name == 0)
name = NULL;
return name;
}
/**
* 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;
aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL);
}
printk(KERN_INFO "AppArmor: %s\n", str);
}
/**
* kvmalloc - do allocation preferring 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.
*/
void *kvmalloc(size_t size)
{
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) {
/* see kvfree for why size must be at least work_struct size
* when allocated via vmalloc
*/
if (size < sizeof(struct work_struct))
size = sizeof(struct work_struct);
buffer = vmalloc(size);
}
return buffer;
}
/**
* do_vfree - workqueue routine for freeing vmalloced memory
* @work: data to be freed
*
* The work_struct is overlaid 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);
}
/**
* 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);
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -27,7 +27,7 @@ static int cap_quota_on(struct dentry *dentry)
return 0;
}
static int cap_bprm_check_security (struct linux_binprm *bprm)
static int cap_bprm_check_security(struct linux_binprm *bprm)
{
return 0;
}
......@@ -268,8 +268,7 @@ static int cap_path_rename(struct path *old_path, struct dentry *old_dentry,
return 0;
}
static int cap_path_truncate(struct path *path, loff_t length,
unsigned int time_attrs)
static int cap_path_truncate(struct path *path)
{
return 0;
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
obj-y = common.o realpath.o tomoyo.o domain.o file.o gc.o path_group.o
obj-y = common.o domain.o file.o gc.o group.o load_policy.o memory.o mount.o realpath.o securityfs_if.o tomoyo.o util.o
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment