Commit 00aa9d0b authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'apparmor-pr-2022-08-08' of...

Merge tag 'apparmor-pr-2022-08-08' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor

Pull AppArmor updates from John Johansen:
 "This is mostly cleanups and bug fixes with the one bigger change being
  Mathew Wilcox's patch to use XArrays instead of the IDR from the
  thread around the locking weirdness.

  Features:
   - Convert secid mapping to XArrays instead of IDR
   - Add a kernel label to use on kernel objects
   - Extend policydb permission set by making use of the xbits
   - Make export of raw binary profile to userspace optional
   - Enable tuning of policy paranoid load for embedded systems
   - Don't create raw_sha1 symlink if sha1 hashing is disabled
   - Allow labels to carry debug flags

  Cleanups:
   - Update MAINTAINERS file
   - Use struct_size() helper in kmalloc()
   - Move ptrace mediation to more logical task.{h,c}
   - Resolve uninitialized symbol warnings
   - Remove redundant ret variable
   - Mark alloc_unconfined() as static
   - Update help description of policy hash for introspection
   - Remove some casts which are no-longer required

  Bug Fixes:
   - Fix aa_label_asxprint return check
   - Fix reference count leak in aa_pivotroot()
   - Fix memleak in aa_simple_write_to_buffer()
   - Fix kernel doc comments
   - Fix absroot causing audited secids to begin with =
   - Fix quiet_denied for file rules
   - Fix failed mount permission check error message
   - Disable showing the mode as part of a secid to secctx
   - Fix setting unconfined mode on a loaded profile
   - Fix overlapping attachment computation
   - Fix undefined reference to `zlib_deflate_workspacesize'"

* tag 'apparmor-pr-2022-08-08' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor: (34 commits)
  apparmor: Update MAINTAINERS file with new email address
  apparmor: correct config reference to intended one
  apparmor: move ptrace mediation to more logical task.{h,c}
  apparmor: extend policydb permission set by making use of the xbits
  apparmor: allow label to carry debug flags
  apparmor: fix overlapping attachment computation
  apparmor: fix setting unconfined mode on a loaded profile
  apparmor: Fix some kernel-doc comments
  apparmor: Mark alloc_unconfined() as static
  apparmor: disable showing the mode as part of a secid to secctx
  apparmor: Convert secid mapping to XArrays instead of IDR
  apparmor: add a kernel label to use on kernel objects
  apparmor: test: Remove some casts which are no-longer required
  apparmor: Fix memleak in aa_simple_write_to_buffer()
  apparmor: fix reference count leak in aa_pivotroot()
  apparmor: Fix some kernel-doc comments
  apparmor: Fix undefined reference to `zlib_deflate_workspacesize'
  apparmor: fix aa_label_asxprint return check
  apparmor: Fix some kernel-doc comments
  apparmor: Fix some kernel-doc comments
  ...
parents 0af5cb34 c269fca7
...@@ -1390,10 +1390,14 @@ F: include/uapi/linux/apm_bios.h ...@@ -1390,10 +1390,14 @@ F: include/uapi/linux/apm_bios.h
APPARMOR SECURITY MODULE APPARMOR SECURITY MODULE
M: John Johansen <john.johansen@canonical.com> M: John Johansen <john.johansen@canonical.com>
L: apparmor@lists.ubuntu.com (subscribers-only, general discussion) M: John Johansen <john@apparmor.net>
L: apparmor@lists.ubuntu.com (moderated for non-subscribers)
S: Supported S: Supported
W: wiki.apparmor.net W: apparmor.net
B: https://gitlab.com/apparmor/apparmor-kernel
C: irc://irc.oftc.net/apparmor
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor T: git git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor
T: https://gitlab.com/apparmor/apparmor-kernel.git
F: Documentation/admin-guide/LSM/apparmor.rst F: Documentation/admin-guide/LSM/apparmor.rst
F: security/apparmor/ F: security/apparmor/
......
...@@ -6,8 +6,6 @@ config SECURITY_APPARMOR ...@@ -6,8 +6,6 @@ config SECURITY_APPARMOR
select SECURITY_PATH select SECURITY_PATH
select SECURITYFS select SECURITYFS
select SECURITY_NETWORK select SECURITY_NETWORK
select ZLIB_INFLATE
select ZLIB_DEFLATE
default n default n
help help
This enables the AppArmor security module. This enables the AppArmor security module.
...@@ -17,29 +15,6 @@ config SECURITY_APPARMOR ...@@ -17,29 +15,6 @@ config SECURITY_APPARMOR
If you are unsure how to answer this question, answer N. If you are unsure how to answer this question, answer N.
config SECURITY_APPARMOR_HASH
bool "Enable introspection of sha1 hashes for loaded profiles"
depends on SECURITY_APPARMOR
select CRYPTO
select CRYPTO_SHA1
default y
help
This option selects whether introspection of loaded policy
is available to userspace via the apparmor filesystem.
config SECURITY_APPARMOR_HASH_DEFAULT
bool "Enable policy hash introspection by default"
depends on SECURITY_APPARMOR_HASH
default y
help
This option selects whether sha1 hashing of loaded policy
is enabled by default. The generation of sha1 hashes for
loaded policy provide system administrators a quick way
to verify that policy in the kernel matches what is expected,
however it can slow down policy load on some devices. In
these cases policy hashing can be disabled by default and
enabled only if needed.
config SECURITY_APPARMOR_DEBUG config SECURITY_APPARMOR_DEBUG
bool "Build AppArmor with debug code" bool "Build AppArmor with debug code"
depends on SECURITY_APPARMOR depends on SECURITY_APPARMOR
...@@ -69,6 +44,67 @@ config SECURITY_APPARMOR_DEBUG_MESSAGES ...@@ -69,6 +44,67 @@ config SECURITY_APPARMOR_DEBUG_MESSAGES
When enabled, various debug messages will be logged to When enabled, various debug messages will be logged to
the kernel message buffer. the kernel message buffer.
config SECURITY_APPARMOR_INTROSPECT_POLICY
bool "Allow loaded policy to be introspected"
depends on SECURITY_APPARMOR
default y
help
This option selects whether introspection of loaded policy
is available to userspace via the apparmor filesystem. This
adds to kernel memory usage. It is required for introspection
of loaded policy, and check point and restore support. It
can be disabled for embedded systems where reducing memory and
cpu is paramount.
config SECURITY_APPARMOR_HASH
bool "Enable introspection of sha1 hashes for loaded profiles"
depends on SECURITY_APPARMOR_INTROSPECT_POLICY
select CRYPTO
select CRYPTO_SHA1
default y
help
This option selects whether introspection of loaded policy
hashes is available to userspace via the apparmor
filesystem. This option provides a light weight means of
checking loaded policy. This option adds to policy load
time and can be disabled for small embedded systems.
config SECURITY_APPARMOR_HASH_DEFAULT
bool "Enable policy hash introspection by default"
depends on SECURITY_APPARMOR_HASH
default y
help
This option selects whether sha1 hashing of loaded policy
is enabled by default. The generation of sha1 hashes for
loaded policy provide system administrators a quick way
to verify that policy in the kernel matches what is expected,
however it can slow down policy load on some devices. In
these cases policy hashing can be disabled by default and
enabled only if needed.
config SECURITY_APPARMOR_EXPORT_BINARY
bool "Allow exporting the raw binary policy"
depends on SECURITY_APPARMOR_INTROSPECT_POLICY
select ZLIB_INFLATE
select ZLIB_DEFLATE
default y
help
This option allows reading back binary policy as it was loaded.
It increases the amount of kernel memory needed by policy and
also increases policy load time. This option is required for
checkpoint and restore support, and debugging of loaded policy.
config SECURITY_APPARMOR_PARANOID_LOAD
bool "Perform full verification of loaded policy"
depends on SECURITY_APPARMOR
default y
help
This options allows controlling whether apparmor does a full
verification of loaded policy. This should not be disabled
except for embedded systems where the image is read only,
includes policy, and has some form of integrity check.
Disabling the check will speed up policy loads.
config SECURITY_APPARMOR_KUNIT_TEST config SECURITY_APPARMOR_KUNIT_TEST
bool "Build KUnit tests for policy_unpack.c" if !KUNIT_ALL_TESTS bool "Build KUnit tests for policy_unpack.c" if !KUNIT_ALL_TESTS
depends on KUNIT=y && SECURITY_APPARMOR depends on KUNIT=y && SECURITY_APPARMOR
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "include/policy_ns.h" #include "include/policy_ns.h"
#include "include/resource.h" #include "include/resource.h"
#include "include/policy_unpack.h" #include "include/policy_unpack.h"
#include "include/task.h"
/* /*
* The apparmor filesystem interface used for policy load and introspection * The apparmor filesystem interface used for policy load and introspection
...@@ -70,6 +71,7 @@ struct rawdata_f_data { ...@@ -70,6 +71,7 @@ struct rawdata_f_data {
struct aa_loaddata *loaddata; struct aa_loaddata *loaddata;
}; };
#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
#define RAWDATA_F_DATA_BUF(p) (char *)(p + 1) #define RAWDATA_F_DATA_BUF(p) (char *)(p + 1)
static void rawdata_f_data_free(struct rawdata_f_data *private) static void rawdata_f_data_free(struct rawdata_f_data *private)
...@@ -94,9 +96,10 @@ static struct rawdata_f_data *rawdata_f_data_alloc(size_t size) ...@@ -94,9 +96,10 @@ static struct rawdata_f_data *rawdata_f_data_alloc(size_t size)
return ret; return ret;
} }
#endif
/** /**
* aa_mangle_name - mangle a profile name to std profile layout form * mangle_name - mangle a profile name to std profile layout form
* @name: profile name to mangle (NOT NULL) * @name: profile name to mangle (NOT NULL)
* @target: buffer to store mangled name, same length as @name (MAYBE NULL) * @target: buffer to store mangled name, same length as @name (MAYBE NULL)
* *
...@@ -401,7 +404,7 @@ static struct aa_loaddata *aa_simple_write_to_buffer(const char __user *userbuf, ...@@ -401,7 +404,7 @@ static struct aa_loaddata *aa_simple_write_to_buffer(const char __user *userbuf,
data->size = copy_size; data->size = copy_size;
if (copy_from_user(data->data, userbuf, copy_size)) { if (copy_from_user(data->data, userbuf, copy_size)) {
kvfree(data); aa_put_loaddata(data);
return ERR_PTR(-EFAULT); return ERR_PTR(-EFAULT);
} }
...@@ -1201,7 +1204,7 @@ SEQ_NS_FOPS(name); ...@@ -1201,7 +1204,7 @@ SEQ_NS_FOPS(name);
/* policy/raw_data/ * file ops */ /* policy/raw_data/ * file ops */
#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
#define SEQ_RAWDATA_FOPS(NAME) \ #define SEQ_RAWDATA_FOPS(NAME) \
static int seq_rawdata_ ##NAME ##_open(struct inode *inode, struct file *file)\ static int seq_rawdata_ ##NAME ##_open(struct inode *inode, struct file *file)\
{ \ { \
...@@ -1294,44 +1297,47 @@ SEQ_RAWDATA_FOPS(compressed_size); ...@@ -1294,44 +1297,47 @@ SEQ_RAWDATA_FOPS(compressed_size);
static int deflate_decompress(char *src, size_t slen, char *dst, size_t dlen) static int deflate_decompress(char *src, size_t slen, char *dst, size_t dlen)
{ {
int error; #ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
struct z_stream_s strm; if (aa_g_rawdata_compression_level != 0) {
int error = 0;
struct z_stream_s strm;
if (aa_g_rawdata_compression_level == 0) { memset(&strm, 0, sizeof(strm));
if (dlen < slen)
return -EINVAL;
memcpy(dst, src, slen);
return 0;
}
memset(&strm, 0, sizeof(strm)); strm.workspace = kvzalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
if (!strm.workspace)
return -ENOMEM;
strm.workspace = kvzalloc(zlib_inflate_workspacesize(), GFP_KERNEL); strm.next_in = src;
if (!strm.workspace) strm.avail_in = slen;
return -ENOMEM;
strm.next_in = src;
strm.avail_in = slen;
error = zlib_inflateInit(&strm); error = zlib_inflateInit(&strm);
if (error != Z_OK) { if (error != Z_OK) {
error = -ENOMEM; error = -ENOMEM;
goto fail_inflate_init; goto fail_inflate_init;
} }
strm.next_out = dst; strm.next_out = dst;
strm.avail_out = dlen; strm.avail_out = dlen;
error = zlib_inflate(&strm, Z_FINISH); error = zlib_inflate(&strm, Z_FINISH);
if (error != Z_STREAM_END) if (error != Z_STREAM_END)
error = -EINVAL; error = -EINVAL;
else else
error = 0; error = 0;
zlib_inflateEnd(&strm); zlib_inflateEnd(&strm);
fail_inflate_init: fail_inflate_init:
kvfree(strm.workspace); kvfree(strm.workspace);
return error;
return error;
}
#endif
if (dlen < slen)
return -EINVAL;
memcpy(dst, src, slen);
return 0;
} }
static ssize_t rawdata_read(struct file *file, char __user *buf, size_t size, static ssize_t rawdata_read(struct file *file, char __user *buf, size_t size,
...@@ -1492,10 +1498,12 @@ int __aa_fs_create_rawdata(struct aa_ns *ns, struct aa_loaddata *rawdata) ...@@ -1492,10 +1498,12 @@ int __aa_fs_create_rawdata(struct aa_ns *ns, struct aa_loaddata *rawdata)
return PTR_ERR(dent); return PTR_ERR(dent);
} }
#endif /* CONFIG_SECURITY_APPARMOR_EXPORT_BINARY */
/** fns to setup dynamic per profile/namespace files **/ /** fns to setup dynamic per profile/namespace files **/
/** /*
* *
* Requires: @profile->ns->lock held * Requires: @profile->ns->lock held
*/ */
...@@ -1522,7 +1530,7 @@ void __aafs_profile_rmdir(struct aa_profile *profile) ...@@ -1522,7 +1530,7 @@ void __aafs_profile_rmdir(struct aa_profile *profile)
} }
} }
/** /*
* *
* Requires: @old->ns->lock held * Requires: @old->ns->lock held
*/ */
...@@ -1557,6 +1565,7 @@ static struct dentry *create_profile_file(struct dentry *dir, const char *name, ...@@ -1557,6 +1565,7 @@ static struct dentry *create_profile_file(struct dentry *dir, const char *name,
return dent; return dent;
} }
#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
static int profile_depth(struct aa_profile *profile) static int profile_depth(struct aa_profile *profile)
{ {
int depth = 0; int depth = 0;
...@@ -1658,7 +1667,7 @@ static const struct inode_operations rawdata_link_abi_iops = { ...@@ -1658,7 +1667,7 @@ static const struct inode_operations rawdata_link_abi_iops = {
static const struct inode_operations rawdata_link_data_iops = { static const struct inode_operations rawdata_link_data_iops = {
.get_link = rawdata_get_link_data, .get_link = rawdata_get_link_data,
}; };
#endif /* CONFIG_SECURITY_APPARMOR_EXPORT_BINARY */
/* /*
* Requires: @profile->ns->lock held * Requires: @profile->ns->lock held
...@@ -1729,15 +1738,17 @@ int __aafs_profile_mkdir(struct aa_profile *profile, struct dentry *parent) ...@@ -1729,15 +1738,17 @@ int __aafs_profile_mkdir(struct aa_profile *profile, struct dentry *parent)
profile->dents[AAFS_PROF_HASH] = dent; profile->dents[AAFS_PROF_HASH] = dent;
} }
#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
if (profile->rawdata) { if (profile->rawdata) {
dent = aafs_create("raw_sha1", S_IFLNK | 0444, dir, if (aa_g_hash_policy) {
profile->label.proxy, NULL, NULL, dent = aafs_create("raw_sha1", S_IFLNK | 0444, dir,
&rawdata_link_sha1_iops); profile->label.proxy, NULL, NULL,
if (IS_ERR(dent)) &rawdata_link_sha1_iops);
goto fail; if (IS_ERR(dent))
aa_get_proxy(profile->label.proxy); goto fail;
profile->dents[AAFS_PROF_RAW_HASH] = dent; aa_get_proxy(profile->label.proxy);
profile->dents[AAFS_PROF_RAW_HASH] = dent;
}
dent = aafs_create("raw_abi", S_IFLNK | 0444, dir, dent = aafs_create("raw_abi", S_IFLNK | 0444, dir,
profile->label.proxy, NULL, NULL, profile->label.proxy, NULL, NULL,
&rawdata_link_abi_iops); &rawdata_link_abi_iops);
...@@ -1754,6 +1765,7 @@ int __aafs_profile_mkdir(struct aa_profile *profile, struct dentry *parent) ...@@ -1754,6 +1765,7 @@ int __aafs_profile_mkdir(struct aa_profile *profile, struct dentry *parent)
aa_get_proxy(profile->label.proxy); aa_get_proxy(profile->label.proxy);
profile->dents[AAFS_PROF_RAW_DATA] = dent; profile->dents[AAFS_PROF_RAW_DATA] = dent;
} }
#endif /*CONFIG_SECURITY_APPARMOR_EXPORT_BINARY */
list_for_each_entry(child, &profile->base.profiles, base.list) { list_for_each_entry(child, &profile->base.profiles, base.list) {
error = __aafs_profile_mkdir(child, prof_child_dir(profile)); error = __aafs_profile_mkdir(child, prof_child_dir(profile));
...@@ -1880,7 +1892,7 @@ static void __aa_fs_list_remove_rawdata(struct aa_ns *ns) ...@@ -1880,7 +1892,7 @@ static void __aa_fs_list_remove_rawdata(struct aa_ns *ns)
__aa_fs_remove_rawdata(ent); __aa_fs_remove_rawdata(ent);
} }
/** /*
* *
* Requires: @ns->lock held * Requires: @ns->lock held
*/ */
...@@ -2323,6 +2335,7 @@ static struct aa_sfs_entry aa_sfs_entry_versions[] = { ...@@ -2323,6 +2335,7 @@ static struct aa_sfs_entry aa_sfs_entry_versions[] = {
AA_SFS_FILE_BOOLEAN("v6", 1), AA_SFS_FILE_BOOLEAN("v6", 1),
AA_SFS_FILE_BOOLEAN("v7", 1), AA_SFS_FILE_BOOLEAN("v7", 1),
AA_SFS_FILE_BOOLEAN("v8", 1), AA_SFS_FILE_BOOLEAN("v8", 1),
AA_SFS_FILE_BOOLEAN("v9", 1),
{ } { }
}; };
......
...@@ -137,7 +137,7 @@ int aa_audit(int type, struct aa_profile *profile, struct common_audit_data *sa, ...@@ -137,7 +137,7 @@ int aa_audit(int type, struct aa_profile *profile, struct common_audit_data *sa,
} }
if (AUDIT_MODE(profile) == AUDIT_QUIET || if (AUDIT_MODE(profile) == AUDIT_QUIET ||
(type == AUDIT_APPARMOR_DENIED && (type == AUDIT_APPARMOR_DENIED &&
AUDIT_MODE(profile) == AUDIT_QUIET)) AUDIT_MODE(profile) == AUDIT_QUIET_DENIED))
return aad(sa)->error; return aad(sa)->error;
if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED) if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED)
......
...@@ -119,7 +119,7 @@ static inline unsigned int match_component(struct aa_profile *profile, ...@@ -119,7 +119,7 @@ static inline unsigned int match_component(struct aa_profile *profile,
* @profile: profile to find perms for * @profile: profile to find perms for
* @label: label to check access permissions for * @label: label to check access permissions for
* @stack: whether this is a stacking request * @stack: whether this is a stacking request
* @start: state to start match in * @state: state to start match in
* @subns: whether to do permission checks on components in a subns * @subns: whether to do permission checks on components in a subns
* @request: permissions to request * @request: permissions to request
* @perms: perms struct to set * @perms: perms struct to set
...@@ -466,7 +466,7 @@ static struct aa_label *find_attach(const struct linux_binprm *bprm, ...@@ -466,7 +466,7 @@ static struct aa_label *find_attach(const struct linux_binprm *bprm,
* xattrs, or a longer match * xattrs, or a longer match
*/ */
candidate = profile; candidate = profile;
candidate_len = profile->xmatch_len; candidate_len = max(count, profile->xmatch_len);
candidate_xattrs = ret; candidate_xattrs = ret;
conflict = false; conflict = false;
} }
...@@ -1279,7 +1279,6 @@ static int change_profile_perms_wrapper(const char *op, const char *name, ...@@ -1279,7 +1279,6 @@ static int change_profile_perms_wrapper(const char *op, const char *name,
/** /**
* aa_change_profile - perform a one-way profile transition * aa_change_profile - perform a one-way profile transition
* @fqname: name of profile may include namespace (NOT NULL) * @fqname: name of profile may include namespace (NOT NULL)
* @onexec: whether this transition is to take place immediately or at exec
* @flags: flags affecting change behavior * @flags: flags affecting change behavior
* *
* Change to new profile @name. Unlike with hats, there is no way * Change to new profile @name. Unlike with hats, there is no way
......
...@@ -36,6 +36,7 @@ extern enum audit_mode aa_g_audit; ...@@ -36,6 +36,7 @@ extern enum audit_mode aa_g_audit;
extern bool aa_g_audit_header; extern bool aa_g_audit_header;
extern bool aa_g_debug; extern bool aa_g_debug;
extern bool aa_g_hash_policy; extern bool aa_g_hash_policy;
extern bool aa_g_export_binary;
extern int aa_g_rawdata_compression_level; extern int aa_g_rawdata_compression_level;
extern bool aa_g_lock_policy; extern bool aa_g_lock_policy;
extern bool aa_g_logsyscall; extern bool aa_g_logsyscall;
......
...@@ -114,7 +114,21 @@ int __aafs_ns_mkdir(struct aa_ns *ns, struct dentry *parent, const char *name, ...@@ -114,7 +114,21 @@ int __aafs_ns_mkdir(struct aa_ns *ns, struct dentry *parent, const char *name,
struct dentry *dent); struct dentry *dent);
struct aa_loaddata; struct aa_loaddata;
#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
void __aa_fs_remove_rawdata(struct aa_loaddata *rawdata); void __aa_fs_remove_rawdata(struct aa_loaddata *rawdata);
int __aa_fs_create_rawdata(struct aa_ns *ns, struct aa_loaddata *rawdata); int __aa_fs_create_rawdata(struct aa_ns *ns, struct aa_loaddata *rawdata);
#else
static inline void __aa_fs_remove_rawdata(struct aa_loaddata *rawdata)
{
/* empty stub */
}
static inline int __aa_fs_create_rawdata(struct aa_ns *ns,
struct aa_loaddata *rawdata)
{
return 0;
}
#endif /* CONFIG_SECURITY_APPARMOR_EXPORT_BINARY */
#endif /* __AA_APPARMORFS_H */ #endif /* __AA_APPARMORFS_H */
...@@ -142,6 +142,7 @@ static inline u16 dfa_map_xindex(u16 mask) ...@@ -142,6 +142,7 @@ static inline u16 dfa_map_xindex(u16 mask)
*/ */
#define dfa_user_allow(dfa, state) (((ACCEPT_TABLE(dfa)[state]) & 0x7f) | \ #define dfa_user_allow(dfa, state) (((ACCEPT_TABLE(dfa)[state]) & 0x7f) | \
((ACCEPT_TABLE(dfa)[state]) & 0x80000000)) ((ACCEPT_TABLE(dfa)[state]) & 0x80000000))
#define dfa_user_xbits(dfa, state) (((ACCEPT_TABLE(dfa)[state]) >> 7) & 0x7f)
#define dfa_user_audit(dfa, state) ((ACCEPT_TABLE2(dfa)[state]) & 0x7f) #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_quiet(dfa, state) (((ACCEPT_TABLE2(dfa)[state]) >> 7) & 0x7f)
#define dfa_user_xindex(dfa, state) \ #define dfa_user_xindex(dfa, state) \
...@@ -150,6 +151,8 @@ static inline u16 dfa_map_xindex(u16 mask) ...@@ -150,6 +151,8 @@ static inline u16 dfa_map_xindex(u16 mask)
#define dfa_other_allow(dfa, state) ((((ACCEPT_TABLE(dfa)[state]) >> 14) & \ #define dfa_other_allow(dfa, state) ((((ACCEPT_TABLE(dfa)[state]) >> 14) & \
0x7f) | \ 0x7f) | \
((ACCEPT_TABLE(dfa)[state]) & 0x80000000)) ((ACCEPT_TABLE(dfa)[state]) & 0x80000000))
#define dfa_other_xbits(dfa, state) \
((((ACCEPT_TABLE(dfa)[state]) >> 7) >> 14) & 0x7f)
#define dfa_other_audit(dfa, state) (((ACCEPT_TABLE2(dfa)[state]) >> 14) & 0x7f) #define dfa_other_audit(dfa, state) (((ACCEPT_TABLE2(dfa)[state]) >> 14) & 0x7f)
#define dfa_other_quiet(dfa, state) \ #define dfa_other_quiet(dfa, state) \
((((ACCEPT_TABLE2(dfa)[state]) >> 7) >> 14) & 0x7f) ((((ACCEPT_TABLE2(dfa)[state]) >> 7) >> 14) & 0x7f)
......
...@@ -13,24 +13,6 @@ ...@@ -13,24 +13,6 @@
#include <linux/sched.h> #include <linux/sched.h>
struct aa_profile;
#define AA_PTRACE_TRACE MAY_WRITE
#define AA_PTRACE_READ MAY_READ
#define AA_MAY_BE_TRACED AA_MAY_APPEND
#define AA_MAY_BE_READ AA_MAY_CREATE
#define PTRACE_PERM_SHIFT 2
#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); int aa_may_signal(struct aa_label *sender, struct aa_label *target, int sig);
#endif /* __AA_IPC_H */ #endif /* __AA_IPC_H */
...@@ -92,6 +92,8 @@ enum label_flags { ...@@ -92,6 +92,8 @@ enum label_flags {
FLAG_STALE = 0x800, /* replaced/removed */ FLAG_STALE = 0x800, /* replaced/removed */
FLAG_RENAMED = 0x1000, /* label has renaming in it */ FLAG_RENAMED = 0x1000, /* label has renaming in it */
FLAG_REVOKED = 0x2000, /* label has revocation in it */ FLAG_REVOKED = 0x2000, /* label has revocation in it */
FLAG_DEBUG1 = 0x4000,
FLAG_DEBUG2 = 0x8000,
/* These flags must correspond with PATH_flags */ /* These flags must correspond with PATH_flags */
/* TODO: add new path flags */ /* TODO: add new path flags */
......
...@@ -22,6 +22,11 @@ ...@@ -22,6 +22,11 @@
*/ */
#define DEBUG_ON (aa_g_debug) #define DEBUG_ON (aa_g_debug)
/*
* split individual debug cases out in preparation for finer grained
* debug controls in the future.
*/
#define AA_DEBUG_LABEL DEBUG_ON
#define dbg_printk(__fmt, __args...) pr_debug(__fmt, ##__args) #define dbg_printk(__fmt, __args...) pr_debug(__fmt, ##__args)
#define AA_DEBUG(fmt, args...) \ #define AA_DEBUG(fmt, args...) \
do { \ do { \
......
...@@ -17,8 +17,8 @@ enum path_flags { ...@@ -17,8 +17,8 @@ enum path_flags {
PATH_CHROOT_REL = 0x8, /* do path lookup relative to chroot */ PATH_CHROOT_REL = 0x8, /* do path lookup relative to chroot */
PATH_CHROOT_NSCONNECT = 0x10, /* connect paths that are at ns root */ PATH_CHROOT_NSCONNECT = 0x10, /* connect paths that are at ns root */
PATH_DELEGATE_DELETED = 0x08000, /* delegate deleted files */ PATH_DELEGATE_DELETED = 0x10000, /* delegate deleted files */
PATH_MEDIATE_DELETED = 0x10000, /* mediate deleted paths */ PATH_MEDIATE_DELETED = 0x20000, /* mediate deleted paths */
}; };
int aa_path_name(const struct path *path, int flags, char *buffer, int aa_path_name(const struct path *path, int flags, char *buffer,
......
...@@ -48,6 +48,10 @@ extern const char *const aa_profile_mode_names[]; ...@@ -48,6 +48,10 @@ extern const char *const aa_profile_mode_names[];
#define PROFILE_IS_HAT(_profile) ((_profile)->label.flags & FLAG_HAT) #define PROFILE_IS_HAT(_profile) ((_profile)->label.flags & FLAG_HAT)
#define CHECK_DEBUG1(_profile) ((_profile)->label.flags & FLAG_DEBUG1)
#define CHECK_DEBUG2(_profile) ((_profile)->label.flags & FLAG_DEBUG2)
#define profile_is_stale(_profile) (label_is_stale(&(_profile)->label)) #define profile_is_stale(_profile) (label_is_stale(&(_profile)->label))
#define on_list_rcu(X) (!list_empty(X) && (X)->prev != LIST_POISON2) #define on_list_rcu(X) (!list_empty(X) && (X)->prev != LIST_POISON2)
...@@ -135,7 +139,7 @@ struct aa_profile { ...@@ -135,7 +139,7 @@ struct aa_profile {
const char *attach; const char *attach;
struct aa_dfa *xmatch; struct aa_dfa *xmatch;
int xmatch_len; unsigned int xmatch_len;
enum audit_mode audit; enum audit_mode audit;
long mode; long mode;
u32 path_flags; u32 path_flags;
......
...@@ -74,6 +74,7 @@ struct aa_ns { ...@@ -74,6 +74,7 @@ struct aa_ns {
struct dentry *dents[AAFS_NS_SIZEOF]; struct dentry *dents[AAFS_NS_SIZEOF];
}; };
extern struct aa_label *kernel_t;
extern struct aa_ns *root_ns; extern struct aa_ns *root_ns;
extern const char *aa_hidden_ns_name; extern const char *aa_hidden_ns_name;
......
...@@ -28,6 +28,8 @@ void aa_load_ent_free(struct aa_load_ent *ent); ...@@ -28,6 +28,8 @@ void aa_load_ent_free(struct aa_load_ent *ent);
struct aa_load_ent *aa_load_ent_alloc(void); struct aa_load_ent *aa_load_ent_alloc(void);
#define PACKED_FLAG_HAT 1 #define PACKED_FLAG_HAT 1
#define PACKED_FLAG_DEBUG1 2
#define PACKED_FLAG_DEBUG2 4
#define PACKED_MODE_ENFORCE 0 #define PACKED_MODE_ENFORCE 0
#define PACKED_MODE_COMPLAIN 1 #define PACKED_MODE_COMPLAIN 1
......
...@@ -21,6 +21,9 @@ struct aa_label; ...@@ -21,6 +21,9 @@ struct aa_label;
/* secid value that matches any other secid */ /* secid value that matches any other secid */
#define AA_SECID_WILDCARD 1 #define AA_SECID_WILDCARD 1
/* sysctl to enable displaying mode when converting secid to secctx */
extern int apparmor_display_secid_mode;
struct aa_label *aa_secid_to_label(u32 secid); struct aa_label *aa_secid_to_label(u32 secid);
int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen); int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid); int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
...@@ -31,6 +34,4 @@ int aa_alloc_secid(struct aa_label *label, gfp_t gfp); ...@@ -31,6 +34,4 @@ int aa_alloc_secid(struct aa_label *label, gfp_t gfp);
void aa_free_secid(u32 secid); void aa_free_secid(u32 secid);
void aa_secid_update(u32 secid, struct aa_label *label); void aa_secid_update(u32 secid, struct aa_label *label);
void aa_secids_init(void);
#endif /* __AA_SECID_H */ #endif /* __AA_SECID_H */
...@@ -77,4 +77,22 @@ static inline void aa_clear_task_ctx_trans(struct aa_task_ctx *ctx) ...@@ -77,4 +77,22 @@ static inline void aa_clear_task_ctx_trans(struct aa_task_ctx *ctx)
ctx->token = 0; ctx->token = 0;
} }
#define AA_PTRACE_TRACE MAY_WRITE
#define AA_PTRACE_READ MAY_READ
#define AA_MAY_BE_TRACED AA_MAY_APPEND
#define AA_MAY_BE_READ AA_MAY_CREATE
#define PTRACE_PERM_SHIFT 2
#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);
#endif /* __AA_TASK_H */ #endif /* __AA_TASK_H */
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
*/ */
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/ptrace.h>
#include "include/audit.h" #include "include/audit.h"
#include "include/capability.h" #include "include/capability.h"
...@@ -18,115 +17,6 @@ ...@@ -18,115 +17,6 @@
#include "include/ipc.h" #include "include/ipc.h"
#include "include/sig_names.h" #include "include/sig_names.h"
/**
* audit_ptrace_mask - convert mask to permission string
* @mask: permission mask to convert
*
* Returns: pointer to static string
*/
static const char *audit_ptrace_mask(u32 mask)
{
switch (mask) {
case MAY_READ:
return "read";
case MAY_WRITE:
return "trace";
case AA_MAY_BE_READ:
return "readby";
case AA_MAY_BE_TRACED:
return "tracedby";
}
return "";
}
/* call back to audit ptrace fields */
static void audit_ptrace_cb(struct audit_buffer *ab, void *va)
{
struct common_audit_data *sa = va;
if (aad(sa)->request & AA_PTRACE_PERM_MASK) {
audit_log_format(ab, " requested_mask=\"%s\"",
audit_ptrace_mask(aad(sa)->request));
if (aad(sa)->denied & AA_PTRACE_PERM_MASK) {
audit_log_format(ab, " denied_mask=\"%s\"",
audit_ptrace_mask(aad(sa)->denied));
}
}
audit_log_format(ab, " peer=");
aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
FLAGS_NONE, GFP_ATOMIC);
}
/* assumes check for PROFILE_MEDIATES is already done */
/* TODO: conditionals */
static int profile_ptrace_perm(struct aa_profile *profile,
struct aa_label *peer, u32 request,
struct common_audit_data *sa)
{
struct aa_perms perms = { };
aad(sa)->peer = peer;
aa_profile_match_label(profile, peer, AA_CLASS_PTRACE, request,
&perms);
aa_apply_modes_to_perms(profile, &perms);
return aa_check_perms(profile, &perms, request, sa, audit_ptrace_cb);
}
static int profile_tracee_perm(struct aa_profile *tracee,
struct aa_label *tracer, u32 request,
struct common_audit_data *sa)
{
if (profile_unconfined(tracee) || unconfined(tracer) ||
!PROFILE_MEDIATES(tracee, AA_CLASS_PTRACE))
return 0;
return profile_ptrace_perm(tracee, tracer, request, sa);
}
static int profile_tracer_perm(struct aa_profile *tracer,
struct aa_label *tracee, u32 request,
struct common_audit_data *sa)
{
if (profile_unconfined(tracer))
return 0;
if (PROFILE_MEDIATES(tracer, AA_CLASS_PTRACE))
return profile_ptrace_perm(tracer, tracee, request, sa);
/* profile uses the old style capability check for ptrace */
if (&tracer->label == tracee)
return 0;
aad(sa)->label = &tracer->label;
aad(sa)->peer = tracee;
aad(sa)->request = 0;
aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE,
CAP_OPT_NONE);
return aa_audit(AUDIT_APPARMOR_AUTO, tracer, sa, audit_ptrace_cb);
}
/**
* aa_may_ptrace - test if tracer task can trace the tracee
* @tracer: label of the task doing the tracing (NOT NULL)
* @tracee: task label to be traced
* @request: permission request
*
* Returns: %0 else error code if permission denied or error
*/
int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee,
u32 request)
{
struct aa_profile *profile;
u32 xrequest = request << PTRACE_PERM_SHIFT;
DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_PTRACE);
return xcheck_labels(tracer, tracee, profile,
profile_tracer_perm(profile, tracee, request, &sa),
profile_tracee_perm(profile, tracer, xrequest, &sa));
}
static inline int map_signal_num(int sig) static inline int map_signal_num(int sig)
{ {
......
...@@ -197,18 +197,18 @@ static bool vec_is_stale(struct aa_profile **vec, int n) ...@@ -197,18 +197,18 @@ static bool vec_is_stale(struct aa_profile **vec, int n)
return false; return false;
} }
static bool vec_unconfined(struct aa_profile **vec, int n) static long union_vec_flags(struct aa_profile **vec, int n, long mask)
{ {
long u = 0;
int i; int i;
AA_BUG(!vec); AA_BUG(!vec);
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
if (!profile_unconfined(vec[i])) u |= vec[i]->label.flags & mask;
return false;
} }
return true; return u;
} }
static int sort_cmp(const void *a, const void *b) static int sort_cmp(const void *a, const void *b)
...@@ -485,7 +485,7 @@ int aa_label_next_confined(struct aa_label *label, int i) ...@@ -485,7 +485,7 @@ int aa_label_next_confined(struct aa_label *label, int i)
} }
/** /**
* aa_label_next_not_in_set - return the next profile of @sub not in @set * __aa_label_next_not_in_set - return the next profile of @sub not in @set
* @I: label iterator * @I: label iterator
* @set: label to test against * @set: label to test against
* @sub: label to if is subset of @set * @sub: label to if is subset of @set
...@@ -1097,8 +1097,8 @@ static struct aa_label *label_merge_insert(struct aa_label *new, ...@@ -1097,8 +1097,8 @@ static struct aa_label *label_merge_insert(struct aa_label *new,
else if (k == b->size) else if (k == b->size)
return aa_get_label(b); return aa_get_label(b);
} }
if (vec_unconfined(new->vec, new->size)) new->flags |= union_vec_flags(new->vec, new->size, FLAG_UNCONFINED |
new->flags |= FLAG_UNCONFINED; FLAG_DEBUG1 | FLAG_DEBUG2);
ls = labels_set(new); ls = labels_set(new);
write_lock_irqsave(&ls->lock, flags); write_lock_irqsave(&ls->lock, flags);
label = __label_insert(labels_set(new), new, false); label = __label_insert(labels_set(new), new, false);
...@@ -1631,9 +1631,9 @@ int aa_label_snxprint(char *str, size_t size, struct aa_ns *ns, ...@@ -1631,9 +1631,9 @@ int aa_label_snxprint(char *str, size_t size, struct aa_ns *ns,
AA_BUG(!str && size != 0); AA_BUG(!str && size != 0);
AA_BUG(!label); AA_BUG(!label);
if (flags & FLAG_ABS_ROOT) { if (AA_DEBUG_LABEL && (flags & FLAG_ABS_ROOT)) {
ns = root_ns; ns = root_ns;
len = snprintf(str, size, "="); len = snprintf(str, size, "_");
update_for_len(total, len, size, str); update_for_len(total, len, size, str);
} else if (!ns) { } else if (!ns) {
ns = labels_ns(label); ns = labels_ns(label);
...@@ -1744,7 +1744,7 @@ void aa_label_xaudit(struct audit_buffer *ab, struct aa_ns *ns, ...@@ -1744,7 +1744,7 @@ void aa_label_xaudit(struct audit_buffer *ab, struct aa_ns *ns,
if (!use_label_hname(ns, label, flags) || if (!use_label_hname(ns, label, flags) ||
display_mode(ns, label, flags)) { display_mode(ns, label, flags)) {
len = aa_label_asxprint(&name, ns, label, flags, gfp); len = aa_label_asxprint(&name, ns, label, flags, gfp);
if (len == -1) { if (len < 0) {
AA_DEBUG("label print error"); AA_DEBUG("label print error");
return; return;
} }
...@@ -1772,7 +1772,7 @@ void aa_label_seq_xprint(struct seq_file *f, struct aa_ns *ns, ...@@ -1772,7 +1772,7 @@ void aa_label_seq_xprint(struct seq_file *f, struct aa_ns *ns,
int len; int len;
len = aa_label_asxprint(&str, ns, label, flags, gfp); len = aa_label_asxprint(&str, ns, label, flags, gfp);
if (len == -1) { if (len < 0) {
AA_DEBUG("label print error"); AA_DEBUG("label print error");
return; return;
} }
...@@ -1795,7 +1795,7 @@ void aa_label_xprintk(struct aa_ns *ns, struct aa_label *label, int flags, ...@@ -1795,7 +1795,7 @@ void aa_label_xprintk(struct aa_ns *ns, struct aa_label *label, int flags,
int len; int len;
len = aa_label_asxprint(&str, ns, label, flags, gfp); len = aa_label_asxprint(&str, ns, label, flags, gfp);
if (len == -1) { if (len < 0) {
AA_DEBUG("label print error"); AA_DEBUG("label print error");
return; return;
} }
...@@ -1895,7 +1895,8 @@ struct aa_label *aa_label_strn_parse(struct aa_label *base, const char *str, ...@@ -1895,7 +1895,8 @@ struct aa_label *aa_label_strn_parse(struct aa_label *base, const char *str,
AA_BUG(!str); AA_BUG(!str);
str = skipn_spaces(str, n); str = skipn_spaces(str, n);
if (str == NULL || (*str == '=' && base != &root_ns->unconfined->label)) if (str == NULL || (AA_DEBUG_LABEL && *str == '_' &&
base != &root_ns->unconfined->label))
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
len = label_count_strn_entries(str, end - str); len = label_count_strn_entries(str, end - str);
...@@ -2136,7 +2137,7 @@ static void __labelset_update(struct aa_ns *ns) ...@@ -2136,7 +2137,7 @@ static void __labelset_update(struct aa_ns *ns)
} }
/** /**
* __aa_labelset_udate_subtree - update all labels with a stale component * __aa_labelset_update_subtree - update all labels with a stale component
* @ns: ns to start update at (NOT NULL) * @ns: ns to start update at (NOT NULL)
* *
* Requires: @ns lock be held * Requires: @ns lock be held
......
...@@ -136,7 +136,7 @@ __counted char *aa_str_alloc(int size, gfp_t gfp) ...@@ -136,7 +136,7 @@ __counted char *aa_str_alloc(int size, gfp_t gfp)
{ {
struct counted_str *str; struct counted_str *str;
str = kmalloc(sizeof(struct counted_str) + size, gfp); str = kmalloc(struct_size(str, name, size), gfp);
if (!str) if (!str)
return NULL; return NULL;
...@@ -322,22 +322,39 @@ static u32 map_other(u32 x) ...@@ -322,22 +322,39 @@ static u32 map_other(u32 x)
((x & 0x60) << 19); /* SETOPT/GETOPT */ ((x & 0x60) << 19); /* SETOPT/GETOPT */
} }
static u32 map_xbits(u32 x)
{
return ((x & 0x1) << 7) |
((x & 0x7e) << 9);
}
void aa_compute_perms(struct aa_dfa *dfa, unsigned int state, void aa_compute_perms(struct aa_dfa *dfa, unsigned int state,
struct aa_perms *perms) struct aa_perms *perms)
{ {
/* This mapping is convulated due to history.
* v1-v4: only file perms
* v5: added policydb which dropped in perm user conditional to
* gain new perm bits, but had to map around the xbits because
* the userspace compiler was still munging them.
* v9: adds using the xbits in policydb because the compiler now
* supports treating policydb permission bits different.
* Unfortunately there is not way to force auditing on the
* perms represented by the xbits
*/
*perms = (struct aa_perms) { *perms = (struct aa_perms) {
.allow = dfa_user_allow(dfa, state), .allow = dfa_user_allow(dfa, state) |
map_xbits(dfa_user_xbits(dfa, state)),
.audit = dfa_user_audit(dfa, state), .audit = dfa_user_audit(dfa, state),
.quiet = dfa_user_quiet(dfa, state), .quiet = dfa_user_quiet(dfa, state) |
map_xbits(dfa_other_xbits(dfa, state)),
}; };
/* for v5 perm mapping in the policydb, the other set is used /* for v5-v9 perm mapping in the policydb, the other set is used
* to extend the general perm set * to extend the general perm set
*/ */
perms->allow |= map_other(dfa_other_allow(dfa, state)); perms->allow |= map_other(dfa_other_allow(dfa, state));
perms->audit |= map_other(dfa_other_audit(dfa, state)); perms->audit |= map_other(dfa_other_audit(dfa, state));
perms->quiet |= map_other(dfa_other_quiet(dfa, state)); perms->quiet |= map_other(dfa_other_quiet(dfa, state));
// perms->xindex = dfa_user_xindex(dfa, state);
} }
/** /**
......
...@@ -832,7 +832,7 @@ static void apparmor_sk_free_security(struct sock *sk) ...@@ -832,7 +832,7 @@ static void apparmor_sk_free_security(struct sock *sk)
} }
/** /**
* apparmor_clone_security - clone the sk_security field * apparmor_sk_clone_security - clone the sk_security field
*/ */
static void apparmor_sk_clone_security(const struct sock *sk, static void apparmor_sk_clone_security(const struct sock *sk,
struct sock *newsk) struct sock *newsk)
...@@ -886,10 +886,7 @@ static int apparmor_socket_post_create(struct socket *sock, int family, ...@@ -886,10 +886,7 @@ static int apparmor_socket_post_create(struct socket *sock, int family,
struct aa_label *label; struct aa_label *label;
if (kern) { if (kern) {
struct aa_ns *ns = aa_get_current_ns(); label = aa_get_label(kernel_t);
label = aa_get_label(ns_unconfined(ns));
aa_put_ns(ns);
} else } else
label = aa_get_current_label(); label = aa_get_current_label();
...@@ -937,7 +934,7 @@ static int apparmor_socket_connect(struct socket *sock, ...@@ -937,7 +934,7 @@ static int apparmor_socket_connect(struct socket *sock,
} }
/** /**
* apparmor_socket_list - check perms before allowing listen * apparmor_socket_listen - check perms before allowing listen
*/ */
static int apparmor_socket_listen(struct socket *sock, int backlog) static int apparmor_socket_listen(struct socket *sock, int backlog)
{ {
...@@ -1041,7 +1038,7 @@ static int aa_sock_opt_perm(const char *op, u32 request, struct socket *sock, ...@@ -1041,7 +1038,7 @@ static int aa_sock_opt_perm(const char *op, u32 request, struct socket *sock,
} }
/** /**
* apparmor_getsockopt - check perms before getting socket options * apparmor_socket_getsockopt - check perms before getting socket options
*/ */
static int apparmor_socket_getsockopt(struct socket *sock, int level, static int apparmor_socket_getsockopt(struct socket *sock, int level,
int optname) int optname)
...@@ -1051,7 +1048,7 @@ static int apparmor_socket_getsockopt(struct socket *sock, int level, ...@@ -1051,7 +1048,7 @@ static int apparmor_socket_getsockopt(struct socket *sock, int level,
} }
/** /**
* apparmor_setsockopt - check perms before setting socket options * apparmor_socket_setsockopt - check perms before setting socket options
*/ */
static int apparmor_socket_setsockopt(struct socket *sock, int level, static int apparmor_socket_setsockopt(struct socket *sock, int level,
int optname) int optname)
...@@ -1070,7 +1067,7 @@ static int apparmor_socket_shutdown(struct socket *sock, int how) ...@@ -1070,7 +1067,7 @@ static int apparmor_socket_shutdown(struct socket *sock, int how)
#ifdef CONFIG_NETWORK_SECMARK #ifdef CONFIG_NETWORK_SECMARK
/** /**
* apparmor_socket_sock_recv_skb - check perms before associating skb to sk * apparmor_socket_sock_rcv_skb - check perms before associating skb to sk
* *
* Note: can not sleep may be called with locks held * Note: can not sleep may be called with locks held
* *
...@@ -1357,6 +1354,12 @@ bool aa_g_hash_policy = IS_ENABLED(CONFIG_SECURITY_APPARMOR_HASH_DEFAULT); ...@@ -1357,6 +1354,12 @@ bool aa_g_hash_policy = IS_ENABLED(CONFIG_SECURITY_APPARMOR_HASH_DEFAULT);
module_param_named(hash_policy, aa_g_hash_policy, aabool, S_IRUSR | S_IWUSR); module_param_named(hash_policy, aa_g_hash_policy, aabool, S_IRUSR | S_IWUSR);
#endif #endif
/* whether policy exactly as loaded is retained for debug and checkpointing */
bool aa_g_export_binary = IS_ENABLED(CONFIG_SECURITY_APPARMOR_EXPORT_BINARY);
#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
module_param_named(export_binary, aa_g_export_binary, aabool, 0600);
#endif
/* policy loaddata compression level */ /* policy loaddata compression level */
int aa_g_rawdata_compression_level = Z_DEFAULT_COMPRESSION; int aa_g_rawdata_compression_level = Z_DEFAULT_COMPRESSION;
module_param_named(rawdata_compression_level, aa_g_rawdata_compression_level, module_param_named(rawdata_compression_level, aa_g_rawdata_compression_level,
...@@ -1399,7 +1402,7 @@ module_param_named(path_max, aa_g_path_max, aauint, S_IRUSR); ...@@ -1399,7 +1402,7 @@ module_param_named(path_max, aa_g_path_max, aauint, S_IRUSR);
* DEPRECATED: read only as strict checking of load is always done now * DEPRECATED: read only as strict checking of load is always done now
* that none root users (user namespaces) can load policy. * that none root users (user namespaces) can load policy.
*/ */
bool aa_g_paranoid_load = true; bool aa_g_paranoid_load = IS_ENABLED(CONFIG_SECURITY_APPARMOR_PARANOID_LOAD);
module_param_named(paranoid_load, aa_g_paranoid_load, aabool, S_IRUGO); module_param_named(paranoid_load, aa_g_paranoid_load, aabool, S_IRUGO);
static int param_get_aaintbool(char *buffer, const struct kernel_param *kp); static int param_get_aaintbool(char *buffer, const struct kernel_param *kp);
...@@ -1761,6 +1764,14 @@ static struct ctl_table apparmor_sysctl_table[] = { ...@@ -1761,6 +1764,14 @@ static struct ctl_table apparmor_sysctl_table[] = {
.mode = 0600, .mode = 0600,
.proc_handler = apparmor_dointvec, .proc_handler = apparmor_dointvec,
}, },
{
.procname = "apparmor_display_secid_mode",
.data = &apparmor_display_secid_mode,
.maxlen = sizeof(int),
.mode = 0600,
.proc_handler = apparmor_dointvec,
},
{ } { }
}; };
...@@ -1819,11 +1830,8 @@ static const struct nf_hook_ops apparmor_nf_ops[] = { ...@@ -1819,11 +1830,8 @@ static const struct nf_hook_ops apparmor_nf_ops[] = {
static int __net_init apparmor_nf_register(struct net *net) static int __net_init apparmor_nf_register(struct net *net)
{ {
int ret; return nf_register_net_hooks(net, apparmor_nf_ops,
ret = nf_register_net_hooks(net, apparmor_nf_ops,
ARRAY_SIZE(apparmor_nf_ops)); ARRAY_SIZE(apparmor_nf_ops));
return ret;
} }
static void __net_exit apparmor_nf_unregister(struct net *net) static void __net_exit apparmor_nf_unregister(struct net *net)
...@@ -1857,8 +1865,6 @@ static int __init apparmor_init(void) ...@@ -1857,8 +1865,6 @@ static int __init apparmor_init(void)
{ {
int error; int error;
aa_secids_init();
error = aa_setup_dfa_engine(); error = aa_setup_dfa_engine();
if (error) { if (error) {
AA_ERROR("Unable to setup dfa engine\n"); AA_ERROR("Unable to setup dfa engine\n");
......
...@@ -217,7 +217,6 @@ static struct aa_perms compute_mnt_perms(struct aa_dfa *dfa, ...@@ -217,7 +217,6 @@ static struct aa_perms compute_mnt_perms(struct aa_dfa *dfa,
.allow = dfa_user_allow(dfa, state), .allow = dfa_user_allow(dfa, state),
.audit = dfa_user_audit(dfa, state), .audit = dfa_user_audit(dfa, state),
.quiet = dfa_user_quiet(dfa, state), .quiet = dfa_user_quiet(dfa, state),
.xindex = dfa_user_xindex(dfa, state),
}; };
return perms; return perms;
...@@ -229,7 +228,8 @@ static const char * const mnt_info_table[] = { ...@@ -229,7 +228,8 @@ static const char * const mnt_info_table[] = {
"failed srcname match", "failed srcname match",
"failed type match", "failed type match",
"failed flags match", "failed flags match",
"failed data match" "failed data match",
"failed perms check"
}; };
/* /*
...@@ -284,8 +284,8 @@ static int do_match_mnt(struct aa_dfa *dfa, unsigned int start, ...@@ -284,8 +284,8 @@ static int do_match_mnt(struct aa_dfa *dfa, unsigned int start,
return 0; return 0;
} }
/* failed at end of flags match */ /* failed at perms check, don't confuse with flags match */
return 4; return 6;
} }
...@@ -303,7 +303,7 @@ static int path_flags(struct aa_profile *profile, const struct path *path) ...@@ -303,7 +303,7 @@ static int path_flags(struct aa_profile *profile, const struct path *path)
* @profile: the confining profile * @profile: the confining profile
* @mntpath: for the mntpnt (NOT NULL) * @mntpath: for the mntpnt (NOT NULL)
* @buffer: buffer to be used to lookup mntpath * @buffer: buffer to be used to lookup mntpath
* @devnme: string for the devname/src_name (MAY BE NULL OR ERRPTR) * @devname: string for the devname/src_name (MAY BE NULL OR ERRPTR)
* @type: string for the dev type (MAYBE NULL) * @type: string for the dev type (MAYBE NULL)
* @flags: mount flags to match * @flags: mount flags to match
* @data: fs mount data (MAYBE NULL) * @data: fs mount data (MAYBE NULL)
...@@ -358,7 +358,7 @@ static int match_mnt_path_str(struct aa_profile *profile, ...@@ -358,7 +358,7 @@ static int match_mnt_path_str(struct aa_profile *profile,
/** /**
* match_mnt - handle path matching for mount * match_mnt - handle path matching for mount
* @profile: the confining profile * @profile: the confining profile
* @mntpath: for the mntpnt (NOT NULL) * @path: for the mntpnt (NOT NULL)
* @buffer: buffer to be used to lookup mntpath * @buffer: buffer to be used to lookup mntpath
* @devpath: path devname/src_name (MAYBE NULL) * @devpath: path devname/src_name (MAYBE NULL)
* @devbuffer: buffer to be used to lookup devname/src_name * @devbuffer: buffer to be used to lookup devname/src_name
...@@ -718,6 +718,7 @@ int aa_pivotroot(struct aa_label *label, const struct path *old_path, ...@@ -718,6 +718,7 @@ int aa_pivotroot(struct aa_label *label, const struct path *old_path,
aa_put_label(target); aa_put_label(target);
goto out; goto out;
} }
aa_put_label(target);
} else } else
/* already audited error */ /* already audited error */
error = PTR_ERR(target); error = PTR_ERR(target);
......
...@@ -145,12 +145,13 @@ int aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family, ...@@ -145,12 +145,13 @@ int aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family,
static int aa_label_sk_perm(struct aa_label *label, const char *op, u32 request, static int aa_label_sk_perm(struct aa_label *label, const char *op, u32 request,
struct sock *sk) struct sock *sk)
{ {
struct aa_sk_ctx *ctx = SK_CTX(sk);
int error = 0; int error = 0;
AA_BUG(!label); AA_BUG(!label);
AA_BUG(!sk); AA_BUG(!sk);
if (!unconfined(label)) { if (ctx->label != kernel_t && !unconfined(label)) {
struct aa_profile *profile; struct aa_profile *profile;
DEFINE_AUDIT_SK(sa, op, sk); DEFINE_AUDIT_SK(sa, op, sk);
......
...@@ -422,7 +422,7 @@ static struct aa_profile *__lookup_profile(struct aa_policy *base, ...@@ -422,7 +422,7 @@ static struct aa_profile *__lookup_profile(struct aa_policy *base,
} }
/** /**
* aa_lookup_profile - find a profile by its full or partial name * aa_lookupn_profile - find a profile by its full or partial name
* @ns: the namespace to start from (NOT NULL) * @ns: the namespace to start from (NOT NULL)
* @hname: name to do lookup on. Does not contain namespace prefix (NOT NULL) * @hname: name to do lookup on. Does not contain namespace prefix (NOT NULL)
* @n: size of @hname * @n: size of @hname
...@@ -952,16 +952,18 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label, ...@@ -952,16 +952,18 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label,
mutex_lock_nested(&ns->lock, ns->level); mutex_lock_nested(&ns->lock, ns->level);
/* check for duplicate rawdata blobs: space and file dedup */ /* check for duplicate rawdata blobs: space and file dedup */
list_for_each_entry(rawdata_ent, &ns->rawdata_list, list) { if (!list_empty(&ns->rawdata_list)) {
if (aa_rawdata_eq(rawdata_ent, udata)) { list_for_each_entry(rawdata_ent, &ns->rawdata_list, list) {
struct aa_loaddata *tmp; if (aa_rawdata_eq(rawdata_ent, udata)) {
struct aa_loaddata *tmp;
tmp = __aa_get_loaddata(rawdata_ent);
/* check we didn't fail the race */ tmp = __aa_get_loaddata(rawdata_ent);
if (tmp) { /* check we didn't fail the race */
aa_put_loaddata(udata); if (tmp) {
udata = tmp; aa_put_loaddata(udata);
break; udata = tmp;
break;
}
} }
} }
} }
...@@ -969,7 +971,8 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label, ...@@ -969,7 +971,8 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label,
list_for_each_entry(ent, &lh, list) { list_for_each_entry(ent, &lh, list) {
struct aa_policy *policy; struct aa_policy *policy;
ent->new->rawdata = aa_get_loaddata(udata); if (aa_g_export_binary)
ent->new->rawdata = aa_get_loaddata(udata);
error = __lookup_replace(ns, ent->new->base.hname, error = __lookup_replace(ns, ent->new->base.hname,
!(mask & AA_MAY_REPLACE_POLICY), !(mask & AA_MAY_REPLACE_POLICY),
&ent->old, &info); &ent->old, &info);
...@@ -1009,7 +1012,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label, ...@@ -1009,7 +1012,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label,
} }
/* create new fs entries for introspection if needed */ /* create new fs entries for introspection if needed */
if (!udata->dents[AAFS_LOADDATA_DIR]) { if (!udata->dents[AAFS_LOADDATA_DIR] && aa_g_export_binary) {
error = __aa_fs_create_rawdata(ns, udata); error = __aa_fs_create_rawdata(ns, udata);
if (error) { if (error) {
info = "failed to create raw_data dir and files"; info = "failed to create raw_data dir and files";
...@@ -1037,12 +1040,14 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label, ...@@ -1037,12 +1040,14 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label,
/* Done with checks that may fail - do actual replacement */ /* Done with checks that may fail - do actual replacement */
__aa_bump_ns_revision(ns); __aa_bump_ns_revision(ns);
__aa_loaddata_update(udata, ns->revision); if (aa_g_export_binary)
__aa_loaddata_update(udata, ns->revision);
list_for_each_entry_safe(ent, tmp, &lh, list) { list_for_each_entry_safe(ent, tmp, &lh, list) {
list_del_init(&ent->list); list_del_init(&ent->list);
op = (!ent->old && !ent->rename) ? OP_PROF_LOAD : OP_PROF_REPL; op = (!ent->old && !ent->rename) ? OP_PROF_LOAD : OP_PROF_REPL;
if (ent->old && ent->old->rawdata == ent->new->rawdata) { if (ent->old && ent->old->rawdata == ent->new->rawdata &&
ent->new->rawdata) {
/* dedup actual profile replacement */ /* dedup actual profile replacement */
audit_policy(label, op, ns_name, ent->new->base.hname, audit_policy(label, op, ns_name, ent->new->base.hname,
"same as current profile, skipping", "same as current profile, skipping",
......
...@@ -22,6 +22,9 @@ ...@@ -22,6 +22,9 @@
#include "include/label.h" #include "include/label.h"
#include "include/policy.h" #include "include/policy.h"
/* kernel label */
struct aa_label *kernel_t;
/* root profile namespace */ /* root profile namespace */
struct aa_ns *root_ns; struct aa_ns *root_ns;
const char *aa_hidden_ns_name = "---"; const char *aa_hidden_ns_name = "---";
...@@ -51,10 +54,10 @@ bool aa_ns_visible(struct aa_ns *curr, struct aa_ns *view, bool subns) ...@@ -51,10 +54,10 @@ bool aa_ns_visible(struct aa_ns *curr, struct aa_ns *view, bool subns)
} }
/** /**
* aa_na_name - Find the ns name to display for @view from @curr * aa_ns_name - Find the ns name to display for @view from @curr
* @curr - current namespace (NOT NULL) * @curr: current namespace (NOT NULL)
* @view - namespace attempting to view (NOT NULL) * @view: namespace attempting to view (NOT NULL)
* @subns - are subns visible * @subns: are subns visible
* *
* Returns: name of @view visible from @curr * Returns: name of @view visible from @curr
*/ */
...@@ -77,6 +80,23 @@ const char *aa_ns_name(struct aa_ns *curr, struct aa_ns *view, bool subns) ...@@ -77,6 +80,23 @@ const char *aa_ns_name(struct aa_ns *curr, struct aa_ns *view, bool subns)
return aa_hidden_ns_name; return aa_hidden_ns_name;
} }
static struct aa_profile *alloc_unconfined(const char *name)
{
struct aa_profile *profile;
profile = aa_alloc_profile(name, NULL, GFP_KERNEL);
if (!profile)
return NULL;
profile->label.flags |= FLAG_IX_ON_NAME_ERROR |
FLAG_IMMUTIBLE | FLAG_NS_COUNT | FLAG_UNCONFINED;
profile->mode = APPARMOR_UNCONFINED;
profile->file.dfa = aa_get_dfa(nulldfa);
profile->policy.dfa = aa_get_dfa(nulldfa);
return profile;
}
/** /**
* alloc_ns - allocate, initialize and return a new namespace * alloc_ns - allocate, initialize and return a new namespace
* @prefix: parent namespace name (MAYBE NULL) * @prefix: parent namespace name (MAYBE NULL)
...@@ -101,16 +121,9 @@ static struct aa_ns *alloc_ns(const char *prefix, const char *name) ...@@ -101,16 +121,9 @@ static struct aa_ns *alloc_ns(const char *prefix, const char *name)
init_waitqueue_head(&ns->wait); init_waitqueue_head(&ns->wait);
/* released by aa_free_ns() */ /* released by aa_free_ns() */
ns->unconfined = aa_alloc_profile("unconfined", NULL, GFP_KERNEL); ns->unconfined = alloc_unconfined("unconfined");
if (!ns->unconfined) if (!ns->unconfined)
goto fail_unconfined; goto fail_unconfined;
ns->unconfined->label.flags |= FLAG_IX_ON_NAME_ERROR |
FLAG_IMMUTIBLE | FLAG_NS_COUNT | FLAG_UNCONFINED;
ns->unconfined->mode = APPARMOR_UNCONFINED;
ns->unconfined->file.dfa = aa_get_dfa(nulldfa);
ns->unconfined->policy.dfa = aa_get_dfa(nulldfa);
/* ns and ns->unconfined share ns->unconfined refcount */ /* ns and ns->unconfined share ns->unconfined refcount */
ns->unconfined->ns = ns; ns->unconfined->ns = ns;
...@@ -187,7 +200,7 @@ struct aa_ns *aa_find_ns(struct aa_ns *root, const char *name) ...@@ -187,7 +200,7 @@ struct aa_ns *aa_find_ns(struct aa_ns *root, const char *name)
/** /**
* __aa_lookupn_ns - lookup the namespace matching @hname * __aa_lookupn_ns - lookup the namespace matching @hname
* @base: base list to start looking up profile name from (NOT NULL) * @view: namespace to search in (NOT NULL)
* @hname: hierarchical ns name (NOT NULL) * @hname: hierarchical ns name (NOT NULL)
* @n: length of @hname * @n: length of @hname
* *
...@@ -272,7 +285,7 @@ static struct aa_ns *__aa_create_ns(struct aa_ns *parent, const char *name, ...@@ -272,7 +285,7 @@ static struct aa_ns *__aa_create_ns(struct aa_ns *parent, const char *name,
} }
/** /**
* aa_create_ns - create an ns, fail if it already exists * __aa_find_or_create_ns - create an ns, fail if it already exists
* @parent: the parent of the namespace being created * @parent: the parent of the namespace being created
* @name: the name of the namespace * @name: the name of the namespace
* @dir: if not null the dir to put the ns entries in * @dir: if not null the dir to put the ns entries in
...@@ -388,11 +401,22 @@ static void __ns_list_release(struct list_head *head) ...@@ -388,11 +401,22 @@ static void __ns_list_release(struct list_head *head)
*/ */
int __init aa_alloc_root_ns(void) int __init aa_alloc_root_ns(void)
{ {
struct aa_profile *kernel_p;
/* released by aa_free_root_ns - used as list ref*/ /* released by aa_free_root_ns - used as list ref*/
root_ns = alloc_ns(NULL, "root"); root_ns = alloc_ns(NULL, "root");
if (!root_ns) if (!root_ns)
return -ENOMEM; return -ENOMEM;
kernel_p = alloc_unconfined("kernel_t");
if (!kernel_p) {
destroy_ns(root_ns);
aa_free_ns(root_ns);
return -ENOMEM;
}
kernel_t = &kernel_p->label;
root_ns->unconfined->ns = aa_get_ns(root_ns);
return 0; return 0;
} }
...@@ -405,6 +429,7 @@ void __init aa_free_root_ns(void) ...@@ -405,6 +429,7 @@ void __init aa_free_root_ns(void)
root_ns = NULL; root_ns = NULL;
aa_label_free(kernel_t);
destroy_ns(ns); destroy_ns(ns);
aa_put_ns(ns); aa_put_ns(ns);
} }
...@@ -125,15 +125,16 @@ void __aa_loaddata_update(struct aa_loaddata *data, long revision) ...@@ -125,15 +125,16 @@ void __aa_loaddata_update(struct aa_loaddata *data, long revision)
{ {
AA_BUG(!data); AA_BUG(!data);
AA_BUG(!data->ns); AA_BUG(!data->ns);
AA_BUG(!data->dents[AAFS_LOADDATA_REVISION]);
AA_BUG(!mutex_is_locked(&data->ns->lock)); AA_BUG(!mutex_is_locked(&data->ns->lock));
AA_BUG(data->revision > revision); AA_BUG(data->revision > revision);
data->revision = revision; data->revision = revision;
d_inode(data->dents[AAFS_LOADDATA_DIR])->i_mtime = if ((data->dents[AAFS_LOADDATA_REVISION])) {
current_time(d_inode(data->dents[AAFS_LOADDATA_DIR])); d_inode(data->dents[AAFS_LOADDATA_DIR])->i_mtime =
d_inode(data->dents[AAFS_LOADDATA_REVISION])->i_mtime = current_time(d_inode(data->dents[AAFS_LOADDATA_DIR]));
current_time(d_inode(data->dents[AAFS_LOADDATA_REVISION])); d_inode(data->dents[AAFS_LOADDATA_REVISION])->i_mtime =
current_time(d_inode(data->dents[AAFS_LOADDATA_REVISION]));
}
} }
bool aa_rawdata_eq(struct aa_loaddata *l, struct aa_loaddata *r) bool aa_rawdata_eq(struct aa_loaddata *l, struct aa_loaddata *r)
...@@ -213,7 +214,7 @@ static void *kvmemdup(const void *src, size_t len) ...@@ -213,7 +214,7 @@ static void *kvmemdup(const void *src, size_t len)
} }
/** /**
* aa_u16_chunck - test and do bounds checking for a u16 size based chunk * unpack_u16_chunk - test and do bounds checking for a u16 size based chunk
* @e: serialized data read head (NOT NULL) * @e: serialized data read head (NOT NULL)
* @chunk: start address for chunk of data (NOT NULL) * @chunk: start address for chunk of data (NOT NULL)
* *
...@@ -456,7 +457,9 @@ static struct aa_dfa *unpack_dfa(struct aa_ext *e) ...@@ -456,7 +457,9 @@ static struct aa_dfa *unpack_dfa(struct aa_ext *e)
((e->pos - e->start) & 7); ((e->pos - e->start) & 7);
size_t pad = ALIGN(sz, 8) - sz; size_t pad = ALIGN(sz, 8) - sz;
int flags = TO_ACCEPT1_FLAG(YYTD_DATA32) | int flags = TO_ACCEPT1_FLAG(YYTD_DATA32) |
TO_ACCEPT2_FLAG(YYTD_DATA32) | DFA_FLAG_VERIFY_STATES; TO_ACCEPT2_FLAG(YYTD_DATA32);
if (aa_g_paranoid_load)
flags |= DFA_FLAG_VERIFY_STATES;
dfa = aa_dfa_unpack(blob + pad, size - pad, flags); dfa = aa_dfa_unpack(blob + pad, size - pad, flags);
if (IS_ERR(dfa)) if (IS_ERR(dfa))
...@@ -668,6 +671,7 @@ static int datacmp(struct rhashtable_compare_arg *arg, const void *obj) ...@@ -668,6 +671,7 @@ static int datacmp(struct rhashtable_compare_arg *arg, const void *obj)
/** /**
* unpack_profile - unpack a serialized profile * unpack_profile - unpack a serialized profile
* @e: serialized data extent information (NOT NULL) * @e: serialized data extent information (NOT NULL)
* @ns_name: pointer of newly allocated copy of %NULL in case of error
* *
* NOTE: unpack profile sets audit struct if there is a failure * NOTE: unpack profile sets audit struct if there is a failure
*/ */
...@@ -744,18 +748,24 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) ...@@ -744,18 +748,24 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
goto fail; goto fail;
if (tmp & PACKED_FLAG_HAT) if (tmp & PACKED_FLAG_HAT)
profile->label.flags |= FLAG_HAT; profile->label.flags |= FLAG_HAT;
if (tmp & PACKED_FLAG_DEBUG1)
profile->label.flags |= FLAG_DEBUG1;
if (tmp & PACKED_FLAG_DEBUG2)
profile->label.flags |= FLAG_DEBUG2;
if (!unpack_u32(e, &tmp, NULL)) if (!unpack_u32(e, &tmp, NULL))
goto fail; goto fail;
if (tmp == PACKED_MODE_COMPLAIN || (e->version & FORCE_COMPLAIN_FLAG)) if (tmp == PACKED_MODE_COMPLAIN || (e->version & FORCE_COMPLAIN_FLAG)) {
profile->mode = APPARMOR_COMPLAIN; profile->mode = APPARMOR_COMPLAIN;
else if (tmp == PACKED_MODE_ENFORCE) } else if (tmp == PACKED_MODE_ENFORCE) {
profile->mode = APPARMOR_ENFORCE; profile->mode = APPARMOR_ENFORCE;
else if (tmp == PACKED_MODE_KILL) } else if (tmp == PACKED_MODE_KILL) {
profile->mode = APPARMOR_KILL; profile->mode = APPARMOR_KILL;
else if (tmp == PACKED_MODE_UNCONFINED) } else if (tmp == PACKED_MODE_UNCONFINED) {
profile->mode = APPARMOR_UNCONFINED; profile->mode = APPARMOR_UNCONFINED;
else profile->label.flags |= FLAG_UNCONFINED;
} else {
goto fail; goto fail;
}
if (!unpack_u32(e, &tmp, NULL)) if (!unpack_u32(e, &tmp, NULL))
goto fail; goto fail;
if (tmp) if (tmp)
...@@ -936,7 +946,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) ...@@ -936,7 +946,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
} }
/** /**
* verify_head - unpack serialized stream header * verify_header - unpack serialized stream header
* @e: serialized data read head (NOT NULL) * @e: serialized data read head (NOT NULL)
* @required: whether the header is required or optional * @required: whether the header is required or optional
* @ns: Returns - namespace if one is specified else NULL (NOT NULL) * @ns: Returns - namespace if one is specified else NULL (NOT NULL)
...@@ -1052,6 +1062,7 @@ struct aa_load_ent *aa_load_ent_alloc(void) ...@@ -1052,6 +1062,7 @@ struct aa_load_ent *aa_load_ent_alloc(void)
static int deflate_compress(const char *src, size_t slen, char **dst, static int deflate_compress(const char *src, size_t slen, char **dst,
size_t *dlen) size_t *dlen)
{ {
#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
int error; int error;
struct z_stream_s strm; struct z_stream_s strm;
void *stgbuf, *dstbuf; void *stgbuf, *dstbuf;
...@@ -1123,6 +1134,10 @@ static int deflate_compress(const char *src, size_t slen, char **dst, ...@@ -1123,6 +1134,10 @@ static int deflate_compress(const char *src, size_t slen, char **dst,
fail_deflate: fail_deflate:
kvfree(stgbuf); kvfree(stgbuf);
goto fail_stg_alloc; goto fail_stg_alloc;
#else
*dlen = slen;
return 0;
#endif
} }
static int compress_loaddata(struct aa_loaddata *data) static int compress_loaddata(struct aa_loaddata *data)
...@@ -1141,7 +1156,8 @@ static int compress_loaddata(struct aa_loaddata *data) ...@@ -1141,7 +1156,8 @@ static int compress_loaddata(struct aa_loaddata *data)
if (error) if (error)
return error; return error;
kvfree(udata); if (udata != data->data)
kvfree(udata);
} else } else
data->compressed_size = data->size; data->compressed_size = data->size;
...@@ -1216,9 +1232,12 @@ int aa_unpack(struct aa_loaddata *udata, struct list_head *lh, ...@@ -1216,9 +1232,12 @@ int aa_unpack(struct aa_loaddata *udata, struct list_head *lh,
goto fail; goto fail;
} }
} }
error = compress_loaddata(udata);
if (error) if (aa_g_export_binary) {
goto fail; error = compress_loaddata(udata);
if (error)
goto fail;
}
return 0; return 0;
fail_profile: fail_profile:
......
...@@ -48,8 +48,8 @@ struct policy_unpack_fixture { ...@@ -48,8 +48,8 @@ struct policy_unpack_fixture {
size_t e_size; size_t e_size;
}; };
struct aa_ext *build_aa_ext_struct(struct policy_unpack_fixture *puf, static struct aa_ext *build_aa_ext_struct(struct policy_unpack_fixture *puf,
struct kunit *test, size_t buf_size) struct kunit *test, size_t buf_size)
{ {
char *buf; char *buf;
struct aa_ext *e; struct aa_ext *e;
...@@ -439,7 +439,7 @@ static void policy_unpack_test_unpack_u32_with_null_name(struct kunit *test) ...@@ -439,7 +439,7 @@ static void policy_unpack_test_unpack_u32_with_null_name(struct kunit *test)
{ {
struct policy_unpack_fixture *puf = test->priv; struct policy_unpack_fixture *puf = test->priv;
bool success; bool success;
u32 data; u32 data = 0;
puf->e->pos += TEST_U32_BUF_OFFSET; puf->e->pos += TEST_U32_BUF_OFFSET;
...@@ -456,7 +456,7 @@ static void policy_unpack_test_unpack_u32_with_name(struct kunit *test) ...@@ -456,7 +456,7 @@ static void policy_unpack_test_unpack_u32_with_name(struct kunit *test)
struct policy_unpack_fixture *puf = test->priv; struct policy_unpack_fixture *puf = test->priv;
const char name[] = TEST_U32_NAME; const char name[] = TEST_U32_NAME;
bool success; bool success;
u32 data; u32 data = 0;
puf->e->pos += TEST_NAMED_U32_BUF_OFFSET; puf->e->pos += TEST_NAMED_U32_BUF_OFFSET;
...@@ -473,7 +473,7 @@ static void policy_unpack_test_unpack_u32_out_of_bounds(struct kunit *test) ...@@ -473,7 +473,7 @@ static void policy_unpack_test_unpack_u32_out_of_bounds(struct kunit *test)
struct policy_unpack_fixture *puf = test->priv; struct policy_unpack_fixture *puf = test->priv;
const char name[] = TEST_U32_NAME; const char name[] = TEST_U32_NAME;
bool success; bool success;
u32 data; u32 data = 0;
puf->e->pos += TEST_NAMED_U32_BUF_OFFSET; puf->e->pos += TEST_NAMED_U32_BUF_OFFSET;
puf->e->end = puf->e->start + TEST_U32_BUF_OFFSET + sizeof(u32); puf->e->end = puf->e->start + TEST_U32_BUF_OFFSET + sizeof(u32);
...@@ -489,7 +489,7 @@ static void policy_unpack_test_unpack_u64_with_null_name(struct kunit *test) ...@@ -489,7 +489,7 @@ static void policy_unpack_test_unpack_u64_with_null_name(struct kunit *test)
{ {
struct policy_unpack_fixture *puf = test->priv; struct policy_unpack_fixture *puf = test->priv;
bool success; bool success;
u64 data; u64 data = 0;
puf->e->pos += TEST_U64_BUF_OFFSET; puf->e->pos += TEST_U64_BUF_OFFSET;
...@@ -506,7 +506,7 @@ static void policy_unpack_test_unpack_u64_with_name(struct kunit *test) ...@@ -506,7 +506,7 @@ static void policy_unpack_test_unpack_u64_with_name(struct kunit *test)
struct policy_unpack_fixture *puf = test->priv; struct policy_unpack_fixture *puf = test->priv;
const char name[] = TEST_U64_NAME; const char name[] = TEST_U64_NAME;
bool success; bool success;
u64 data; u64 data = 0;
puf->e->pos += TEST_NAMED_U64_BUF_OFFSET; puf->e->pos += TEST_NAMED_U64_BUF_OFFSET;
...@@ -523,7 +523,7 @@ static void policy_unpack_test_unpack_u64_out_of_bounds(struct kunit *test) ...@@ -523,7 +523,7 @@ static void policy_unpack_test_unpack_u64_out_of_bounds(struct kunit *test)
struct policy_unpack_fixture *puf = test->priv; struct policy_unpack_fixture *puf = test->priv;
const char name[] = TEST_U64_NAME; const char name[] = TEST_U64_NAME;
bool success; bool success;
u64 data; u64 data = 0;
puf->e->pos += TEST_NAMED_U64_BUF_OFFSET; puf->e->pos += TEST_NAMED_U64_BUF_OFFSET;
puf->e->end = puf->e->start + TEST_U64_BUF_OFFSET + sizeof(u64); puf->e->end = puf->e->start + TEST_U64_BUF_OFFSET + sizeof(u64);
......
...@@ -90,7 +90,7 @@ static char *split_token_from_name(const char *op, char *args, u64 *token) ...@@ -90,7 +90,7 @@ static char *split_token_from_name(const char *op, char *args, u64 *token)
} }
/** /**
* aa_setprocattr_chagnehat - handle procattr interface to change_hat * aa_setprocattr_changehat - handle procattr interface to change_hat
* @args: args received from writing to /proc/<pid>/attr/current (NOT NULL) * @args: args received from writing to /proc/<pid>/attr/current (NOT NULL)
* @size: size of the args * @size: size of the args
* @flags: set of flags governing behavior * @flags: set of flags governing behavior
......
...@@ -13,9 +13,9 @@ ...@@ -13,9 +13,9 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/idr.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/xarray.h>
#include "include/cred.h" #include "include/cred.h"
#include "include/lib.h" #include "include/lib.h"
...@@ -29,8 +29,9 @@ ...@@ -29,8 +29,9 @@
*/ */
#define AA_FIRST_SECID 2 #define AA_FIRST_SECID 2
static DEFINE_IDR(aa_secids); static DEFINE_XARRAY_FLAGS(aa_secids, XA_FLAGS_LOCK_IRQ | XA_FLAGS_TRACK_FREE);
static DEFINE_SPINLOCK(secid_lock);
int apparmor_display_secid_mode;
/* /*
* TODO: allow policy to reserve a secid range? * TODO: allow policy to reserve a secid range?
...@@ -47,9 +48,9 @@ void aa_secid_update(u32 secid, struct aa_label *label) ...@@ -47,9 +48,9 @@ void aa_secid_update(u32 secid, struct aa_label *label)
{ {
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&secid_lock, flags); xa_lock_irqsave(&aa_secids, flags);
idr_replace(&aa_secids, label, secid); __xa_store(&aa_secids, secid, label, 0);
spin_unlock_irqrestore(&secid_lock, flags); xa_unlock_irqrestore(&aa_secids, flags);
} }
/** /**
...@@ -58,19 +59,14 @@ void aa_secid_update(u32 secid, struct aa_label *label) ...@@ -58,19 +59,14 @@ void aa_secid_update(u32 secid, struct aa_label *label)
*/ */
struct aa_label *aa_secid_to_label(u32 secid) struct aa_label *aa_secid_to_label(u32 secid)
{ {
struct aa_label *label; return xa_load(&aa_secids, secid);
rcu_read_lock();
label = idr_find(&aa_secids, secid);
rcu_read_unlock();
return label;
} }
int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
{ {
/* TODO: cache secctx and ref count so we don't have to recreate */ /* TODO: cache secctx and ref count so we don't have to recreate */
struct aa_label *label = aa_secid_to_label(secid); struct aa_label *label = aa_secid_to_label(secid);
int flags = FLAG_VIEW_SUBNS | FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT;
int len; int len;
AA_BUG(!seclen); AA_BUG(!seclen);
...@@ -78,15 +74,15 @@ int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) ...@@ -78,15 +74,15 @@ int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
if (!label) if (!label)
return -EINVAL; return -EINVAL;
if (apparmor_display_secid_mode)
flags |= FLAG_SHOW_MODE;
if (secdata) if (secdata)
len = aa_label_asxprint(secdata, root_ns, label, len = aa_label_asxprint(secdata, root_ns, label,
FLAG_SHOW_MODE | FLAG_VIEW_SUBNS | flags, GFP_ATOMIC);
FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT,
GFP_ATOMIC);
else else
len = aa_label_snxprint(NULL, 0, root_ns, label, len = aa_label_snxprint(NULL, 0, root_ns, label, flags);
FLAG_SHOW_MODE | FLAG_VIEW_SUBNS |
FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT);
if (len < 0) if (len < 0)
return -ENOMEM; return -ENOMEM;
...@@ -126,19 +122,16 @@ int aa_alloc_secid(struct aa_label *label, gfp_t gfp) ...@@ -126,19 +122,16 @@ int aa_alloc_secid(struct aa_label *label, gfp_t gfp)
unsigned long flags; unsigned long flags;
int ret; int ret;
idr_preload(gfp); xa_lock_irqsave(&aa_secids, flags);
spin_lock_irqsave(&secid_lock, flags); ret = __xa_alloc(&aa_secids, &label->secid, label,
ret = idr_alloc(&aa_secids, label, AA_FIRST_SECID, 0, GFP_ATOMIC); XA_LIMIT(AA_FIRST_SECID, INT_MAX), gfp);
spin_unlock_irqrestore(&secid_lock, flags); xa_unlock_irqrestore(&aa_secids, flags);
idr_preload_end();
if (ret < 0) { if (ret < 0) {
label->secid = AA_SECID_INVALID; label->secid = AA_SECID_INVALID;
return ret; return ret;
} }
AA_BUG(ret == AA_SECID_INVALID);
label->secid = ret;
return 0; return 0;
} }
...@@ -150,12 +143,7 @@ void aa_free_secid(u32 secid) ...@@ -150,12 +143,7 @@ void aa_free_secid(u32 secid)
{ {
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&secid_lock, flags); xa_lock_irqsave(&aa_secids, flags);
idr_remove(&aa_secids, secid); __xa_erase(&aa_secids, secid);
spin_unlock_irqrestore(&secid_lock, flags); xa_unlock_irqrestore(&aa_secids, flags);
}
void aa_secids_init(void)
{
idr_init_base(&aa_secids, AA_FIRST_SECID);
} }
...@@ -12,7 +12,12 @@ ...@@ -12,7 +12,12 @@
* should return to the previous cred if it has not been modified. * should return to the previous cred if it has not been modified.
*/ */
#include <linux/gfp.h>
#include <linux/ptrace.h>
#include "include/audit.h"
#include "include/cred.h" #include "include/cred.h"
#include "include/policy.h"
#include "include/task.h" #include "include/task.h"
/** /**
...@@ -177,3 +182,112 @@ int aa_restore_previous_label(u64 token) ...@@ -177,3 +182,112 @@ int aa_restore_previous_label(u64 token)
return 0; return 0;
} }
/**
* audit_ptrace_mask - convert mask to permission string
* @mask: permission mask to convert
*
* Returns: pointer to static string
*/
static const char *audit_ptrace_mask(u32 mask)
{
switch (mask) {
case MAY_READ:
return "read";
case MAY_WRITE:
return "trace";
case AA_MAY_BE_READ:
return "readby";
case AA_MAY_BE_TRACED:
return "tracedby";
}
return "";
}
/* call back to audit ptrace fields */
static void audit_ptrace_cb(struct audit_buffer *ab, void *va)
{
struct common_audit_data *sa = va;
if (aad(sa)->request & AA_PTRACE_PERM_MASK) {
audit_log_format(ab, " requested_mask=\"%s\"",
audit_ptrace_mask(aad(sa)->request));
if (aad(sa)->denied & AA_PTRACE_PERM_MASK) {
audit_log_format(ab, " denied_mask=\"%s\"",
audit_ptrace_mask(aad(sa)->denied));
}
}
audit_log_format(ab, " peer=");
aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
FLAGS_NONE, GFP_ATOMIC);
}
/* assumes check for PROFILE_MEDIATES is already done */
/* TODO: conditionals */
static int profile_ptrace_perm(struct aa_profile *profile,
struct aa_label *peer, u32 request,
struct common_audit_data *sa)
{
struct aa_perms perms = { };
aad(sa)->peer = peer;
aa_profile_match_label(profile, peer, AA_CLASS_PTRACE, request,
&perms);
aa_apply_modes_to_perms(profile, &perms);
return aa_check_perms(profile, &perms, request, sa, audit_ptrace_cb);
}
static int profile_tracee_perm(struct aa_profile *tracee,
struct aa_label *tracer, u32 request,
struct common_audit_data *sa)
{
if (profile_unconfined(tracee) || unconfined(tracer) ||
!PROFILE_MEDIATES(tracee, AA_CLASS_PTRACE))
return 0;
return profile_ptrace_perm(tracee, tracer, request, sa);
}
static int profile_tracer_perm(struct aa_profile *tracer,
struct aa_label *tracee, u32 request,
struct common_audit_data *sa)
{
if (profile_unconfined(tracer))
return 0;
if (PROFILE_MEDIATES(tracer, AA_CLASS_PTRACE))
return profile_ptrace_perm(tracer, tracee, request, sa);
/* profile uses the old style capability check for ptrace */
if (&tracer->label == tracee)
return 0;
aad(sa)->label = &tracer->label;
aad(sa)->peer = tracee;
aad(sa)->request = 0;
aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE,
CAP_OPT_NONE);
return aa_audit(AUDIT_APPARMOR_AUTO, tracer, sa, audit_ptrace_cb);
}
/**
* aa_may_ptrace - test if tracer task can trace the tracee
* @tracer: label of the task doing the tracing (NOT NULL)
* @tracee: task label to be traced
* @request: permission request
*
* Returns: %0 else error code if permission denied or error
*/
int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee,
u32 request)
{
struct aa_profile *profile;
u32 xrequest = request << PTRACE_PERM_SHIFT;
DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_PTRACE);
return xcheck_labels(tracer, tracee, profile,
profile_tracer_perm(profile, tracee, request, &sa),
profile_tracee_perm(profile, tracer, xrequest, &sa));
}
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