summaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
Diffstat (limited to 'security')
-rw-r--r--security/apparmor/Kconfig4
-rw-r--r--security/apparmor/Makefile3
-rw-r--r--security/apparmor/domain.c8
-rw-r--r--security/apparmor/file.c4
-rw-r--r--security/apparmor/include/policy_unpack.h50
-rw-r--r--security/apparmor/lsm.c25
-rw-r--r--security/apparmor/policy_unpack.c238
-rw-r--r--security/apparmor/policy_unpack_test.c69
-rw-r--r--security/commoncap.c57
-rw-r--r--security/integrity/evm/evm_main.c146
-rw-r--r--security/integrity/ima/ima_appraise.c9
-rw-r--r--security/integrity/ima/ima_policy.c34
-rw-r--r--security/keys/keyctl.c4
-rw-r--r--security/keys/trusted-keys/trusted_tee.c3
-rw-r--r--security/security.c42
-rw-r--r--security/selinux/hooks.c22
-rw-r--r--security/selinux/ss/services.c5
-rw-r--r--security/selinux/ss/sidtab.c4
-rw-r--r--security/selinux/ss/sidtab.h2
-rw-r--r--security/smack/smack_lsm.c71
20 files changed, 503 insertions, 297 deletions
diff --git a/security/apparmor/Kconfig b/security/apparmor/Kconfig
index cb3496e00d8a..f334e7cccf2d 100644
--- a/security/apparmor/Kconfig
+++ b/security/apparmor/Kconfig
@@ -106,8 +106,8 @@ config SECURITY_APPARMOR_PARANOID_LOAD
Disabling the check will speed up policy loads.
config SECURITY_APPARMOR_KUNIT_TEST
- bool "Build KUnit tests for policy_unpack.c" if !KUNIT_ALL_TESTS
- depends on KUNIT=y && SECURITY_APPARMOR
+ tristate "Build KUnit tests for policy_unpack.c" if !KUNIT_ALL_TESTS
+ depends on KUNIT && SECURITY_APPARMOR
default KUNIT_ALL_TESTS
help
This builds the AppArmor KUnit tests.
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
index ff23fcfefe19..065f4e346553 100644
--- a/security/apparmor/Makefile
+++ b/security/apparmor/Makefile
@@ -8,6 +8,9 @@ apparmor-y := apparmorfs.o audit.o capability.o task.o ipc.o lib.o match.o \
resource.o secid.o file.o policy_ns.o label.o mount.o net.o
apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
+obj-$(CONFIG_SECURITY_APPARMOR_KUNIT_TEST) += apparmor_policy_unpack_test.o
+apparmor_policy_unpack_test-objs += policy_unpack_test.o
+
clean-files := capability_names.h rlim_names.h net_names.h
# Build a lower case string table of address family names
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index 91689d34d281..7bafb4c4767c 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -859,10 +859,10 @@ int apparmor_bprm_creds_for_exec(struct linux_binprm *bprm)
const char *info = NULL;
int error = 0;
bool unsafe = false;
- kuid_t i_uid = i_uid_into_mnt(file_mnt_user_ns(bprm->file),
- file_inode(bprm->file));
+ vfsuid_t vfsuid = i_uid_into_vfsuid(file_mnt_user_ns(bprm->file),
+ file_inode(bprm->file));
struct path_cond cond = {
- i_uid,
+ vfsuid_into_kuid(vfsuid),
file_inode(bprm->file)->i_mode
};
@@ -970,7 +970,7 @@ audit:
error = fn_for_each(label, profile,
aa_audit_file(profile, &nullperms, OP_EXEC, MAY_EXEC,
bprm->filename, NULL, new,
- i_uid, info, error));
+ vfsuid_into_kuid(vfsuid), info, error));
aa_put_label(new);
goto done;
}
diff --git a/security/apparmor/file.c b/security/apparmor/file.c
index e1b7e93602e4..d43679894d23 100644
--- a/security/apparmor/file.c
+++ b/security/apparmor/file.c
@@ -510,8 +510,10 @@ static int __file_path_perm(const char *op, struct aa_label *label,
{
struct aa_profile *profile;
struct aa_perms perms = {};
+ vfsuid_t vfsuid = i_uid_into_vfsuid(file_mnt_user_ns(file),
+ file_inode(file));
struct path_cond cond = {
- .uid = i_uid_into_mnt(file_mnt_user_ns(file), file_inode(file)),
+ .uid = vfsuid_into_kuid(vfsuid),
.mode = file_inode(file)->i_mode
};
char *buffer;
diff --git a/security/apparmor/include/policy_unpack.h b/security/apparmor/include/policy_unpack.h
index eb5f7d7f132b..e89b701447bc 100644
--- a/security/apparmor/include/policy_unpack.h
+++ b/security/apparmor/include/policy_unpack.h
@@ -49,6 +49,43 @@ enum {
};
/*
+ * The AppArmor interface treats data as a type byte followed by the
+ * actual data. The interface has the notion of a named entry
+ * which has a name (AA_NAME typecode followed by name string) followed by
+ * the entries typecode and data. Named types allow for optional
+ * elements and extensions to be added and tested for without breaking
+ * backwards compatibility.
+ */
+
+enum aa_code {
+ AA_U8,
+ AA_U16,
+ AA_U32,
+ AA_U64,
+ AA_NAME, /* same as string except it is items name */
+ AA_STRING,
+ AA_BLOB,
+ AA_STRUCT,
+ AA_STRUCTEND,
+ AA_LIST,
+ AA_LISTEND,
+ AA_ARRAY,
+ AA_ARRAYEND,
+};
+
+/*
+ * aa_ext is the read of the buffer containing the serialized profile. The
+ * data is copied into a kernel buffer in apparmorfs and then handed off to
+ * the unpack routines.
+ */
+struct aa_ext {
+ void *start;
+ void *end;
+ void *pos; /* pointer to current position in the buffer */
+ u32 version;
+};
+
+/*
* struct aa_loaddata - buffer of policy raw_data set
*
* there is no loaddata ref for being on ns list, nor a ref from
@@ -126,4 +163,17 @@ static inline void aa_put_loaddata(struct aa_loaddata *data)
kref_put(&data->count, aa_loaddata_kref);
}
+#if IS_ENABLED(CONFIG_KUNIT)
+bool aa_inbounds(struct aa_ext *e, size_t size);
+size_t aa_unpack_u16_chunk(struct aa_ext *e, char **chunk);
+bool aa_unpack_X(struct aa_ext *e, enum aa_code code);
+bool aa_unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name);
+bool aa_unpack_u32(struct aa_ext *e, u32 *data, const char *name);
+bool aa_unpack_u64(struct aa_ext *e, u64 *data, const char *name);
+size_t aa_unpack_array(struct aa_ext *e, const char *name);
+size_t aa_unpack_blob(struct aa_ext *e, char **blob, const char *name);
+int aa_unpack_str(struct aa_ext *e, const char **string, const char *name);
+int aa_unpack_strdup(struct aa_ext *e, char **string, const char *name);
+#endif
+
#endif /* __POLICY_INTERFACE_H */
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index be31549cfb40..b751d6253977 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -225,8 +225,10 @@ static int common_perm(const char *op, const struct path *path, u32 mask,
static int common_perm_cond(const char *op, const struct path *path, u32 mask)
{
struct user_namespace *mnt_userns = mnt_user_ns(path->mnt);
+ vfsuid_t vfsuid = i_uid_into_vfsuid(mnt_userns,
+ d_backing_inode(path->dentry));
struct path_cond cond = {
- i_uid_into_mnt(mnt_userns, d_backing_inode(path->dentry)),
+ vfsuid_into_kuid(vfsuid),
d_backing_inode(path->dentry)->i_mode
};
@@ -270,11 +272,13 @@ static int common_perm_rm(const char *op, const struct path *dir,
struct inode *inode = d_backing_inode(dentry);
struct user_namespace *mnt_userns = mnt_user_ns(dir->mnt);
struct path_cond cond = { };
+ vfsuid_t vfsuid;
if (!inode || !path_mediated_fs(dentry))
return 0;
- cond.uid = i_uid_into_mnt(mnt_userns, inode);
+ vfsuid = i_uid_into_vfsuid(mnt_userns, inode);
+ cond.uid = vfsuid_into_kuid(vfsuid);
cond.mode = inode->i_mode;
return common_perm_dir_dentry(op, dir, dentry, mask, &cond);
@@ -373,20 +377,23 @@ static int apparmor_path_rename(const struct path *old_dir, struct dentry *old_d
label = begin_current_label_crit_section();
if (!unconfined(label)) {
struct user_namespace *mnt_userns = mnt_user_ns(old_dir->mnt);
+ vfsuid_t vfsuid;
struct path old_path = { .mnt = old_dir->mnt,
.dentry = old_dentry };
struct path new_path = { .mnt = new_dir->mnt,
.dentry = new_dentry };
struct path_cond cond = {
- i_uid_into_mnt(mnt_userns, d_backing_inode(old_dentry)),
- d_backing_inode(old_dentry)->i_mode
+ .mode = d_backing_inode(old_dentry)->i_mode
};
+ vfsuid = i_uid_into_vfsuid(mnt_userns, d_backing_inode(old_dentry));
+ cond.uid = vfsuid_into_kuid(vfsuid);
if (flags & RENAME_EXCHANGE) {
struct path_cond cond_exchange = {
- i_uid_into_mnt(mnt_userns, d_backing_inode(new_dentry)),
- d_backing_inode(new_dentry)->i_mode
+ .mode = d_backing_inode(new_dentry)->i_mode,
};
+ vfsuid = i_uid_into_vfsuid(mnt_userns, d_backing_inode(old_dentry));
+ cond_exchange.uid = vfsuid_into_kuid(vfsuid);
error = aa_path_perm(OP_RENAME_SRC, label, &new_path, 0,
MAY_READ | AA_MAY_GETATTR | MAY_WRITE |
@@ -452,10 +459,12 @@ static int apparmor_file_open(struct file *file)
if (!unconfined(label)) {
struct user_namespace *mnt_userns = file_mnt_user_ns(file);
struct inode *inode = file_inode(file);
+ vfsuid_t vfsuid;
struct path_cond cond = {
- i_uid_into_mnt(mnt_userns, inode),
- inode->i_mode
+ .mode = inode->i_mode,
};
+ vfsuid = i_uid_into_vfsuid(mnt_userns, inode);
+ cond.uid = vfsuid_into_kuid(vfsuid);
error = aa_path_perm(OP_OPEN, label, &file->f_path, 0,
aa_map_file_to_perms(file), &cond);
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index 55d31bac4f35..12e535fdfa8b 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -14,6 +14,7 @@
*/
#include <asm/unaligned.h>
+#include <kunit/visibility.h>
#include <linux/ctype.h>
#include <linux/errno.h>
#include <linux/zlib.h>
@@ -37,43 +38,6 @@
#define v7 7
#define v8 8 /* full network masking */
-/*
- * The AppArmor interface treats data as a type byte followed by the
- * actual data. The interface has the notion of a named entry
- * which has a name (AA_NAME typecode followed by name string) followed by
- * the entries typecode and data. Named types allow for optional
- * elements and extensions to be added and tested for without breaking
- * backwards compatibility.
- */
-
-enum aa_code {
- AA_U8,
- AA_U16,
- AA_U32,
- AA_U64,
- AA_NAME, /* same as string except it is items name */
- AA_STRING,
- AA_BLOB,
- AA_STRUCT,
- AA_STRUCTEND,
- AA_LIST,
- AA_LISTEND,
- AA_ARRAY,
- AA_ARRAYEND,
-};
-
-/*
- * aa_ext is the read of the buffer containing the serialized profile. The
- * data is copied into a kernel buffer in apparmorfs and then handed off to
- * the unpack routines.
- */
-struct aa_ext {
- void *start;
- void *end;
- void *pos; /* pointer to current position in the buffer */
- u32 version;
-};
-
/* audit callback for unpack fields */
static void audit_cb(struct audit_buffer *ab, void *va)
{
@@ -199,10 +163,11 @@ struct aa_loaddata *aa_loaddata_alloc(size_t size)
}
/* test if read will be in packed data bounds */
-static bool inbounds(struct aa_ext *e, size_t size)
+VISIBLE_IF_KUNIT bool aa_inbounds(struct aa_ext *e, size_t size)
{
return (size <= e->end - e->pos);
}
+EXPORT_SYMBOL_IF_KUNIT(aa_inbounds);
static void *kvmemdup(const void *src, size_t len)
{
@@ -214,22 +179,22 @@ static void *kvmemdup(const void *src, size_t len)
}
/**
- * unpack_u16_chunk - test and do bounds checking for a u16 size based chunk
+ * aa_unpack_u16_chunk - test and do bounds checking for a u16 size based chunk
* @e: serialized data read head (NOT NULL)
* @chunk: start address for chunk of data (NOT NULL)
*
* Returns: the size of chunk found with the read head at the end of the chunk.
*/
-static size_t unpack_u16_chunk(struct aa_ext *e, char **chunk)
+VISIBLE_IF_KUNIT size_t aa_unpack_u16_chunk(struct aa_ext *e, char **chunk)
{
size_t size = 0;
void *pos = e->pos;
- if (!inbounds(e, sizeof(u16)))
+ if (!aa_inbounds(e, sizeof(u16)))
goto fail;
size = le16_to_cpu(get_unaligned((__le16 *) e->pos));
e->pos += sizeof(__le16);
- if (!inbounds(e, size))
+ if (!aa_inbounds(e, size))
goto fail;
*chunk = e->pos;
e->pos += size;
@@ -239,20 +204,22 @@ fail:
e->pos = pos;
return 0;
}
+EXPORT_SYMBOL_IF_KUNIT(aa_unpack_u16_chunk);
/* unpack control byte */
-static bool unpack_X(struct aa_ext *e, enum aa_code code)
+VISIBLE_IF_KUNIT bool aa_unpack_X(struct aa_ext *e, enum aa_code code)
{
- if (!inbounds(e, 1))
+ if (!aa_inbounds(e, 1))
return false;
if (*(u8 *) e->pos != code)
return false;
e->pos++;
return true;
}
+EXPORT_SYMBOL_IF_KUNIT(aa_unpack_X);
/**
- * unpack_nameX - check is the next element is of type X with a name of @name
+ * aa_unpack_nameX - check is the next element is of type X with a name of @name
* @e: serialized data extent information (NOT NULL)
* @code: type code
* @name: name to match to the serialized element. (MAYBE NULL)
@@ -267,7 +234,7 @@ static bool unpack_X(struct aa_ext *e, enum aa_code code)
*
* Returns: false if either match fails, the read head does not move
*/
-static bool unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name)
+VISIBLE_IF_KUNIT bool aa_unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name)
{
/*
* May need to reset pos if name or type doesn't match
@@ -277,9 +244,9 @@ static bool unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name)
* Check for presence of a tagname, and if present name size
* AA_NAME tag value is a u16.
*/
- if (unpack_X(e, AA_NAME)) {
+ if (aa_unpack_X(e, AA_NAME)) {
char *tag = NULL;
- size_t size = unpack_u16_chunk(e, &tag);
+ size_t size = aa_unpack_u16_chunk(e, &tag);
/* if a name is specified it must match. otherwise skip tag */
if (name && (!size || tag[size-1] != '\0' || strcmp(name, tag)))
goto fail;
@@ -289,20 +256,21 @@ static bool unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name)
}
/* now check if type code matches */
- if (unpack_X(e, code))
+ if (aa_unpack_X(e, code))
return true;
fail:
e->pos = pos;
return false;
}
+EXPORT_SYMBOL_IF_KUNIT(aa_unpack_nameX);
static bool unpack_u8(struct aa_ext *e, u8 *data, const char *name)
{
void *pos = e->pos;
- if (unpack_nameX(e, AA_U8, name)) {
- if (!inbounds(e, sizeof(u8)))
+ if (aa_unpack_nameX(e, AA_U8, name)) {
+ if (!aa_inbounds(e, sizeof(u8)))
goto fail;
if (data)
*data = *((u8 *)e->pos);
@@ -315,12 +283,12 @@ fail:
return false;
}
-static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
+VISIBLE_IF_KUNIT bool aa_unpack_u32(struct aa_ext *e, u32 *data, const char *name)
{
void *pos = e->pos;
- if (unpack_nameX(e, AA_U32, name)) {
- if (!inbounds(e, sizeof(u32)))
+ if (aa_unpack_nameX(e, AA_U32, name)) {
+ if (!aa_inbounds(e, sizeof(u32)))
goto fail;
if (data)
*data = le32_to_cpu(get_unaligned((__le32 *) e->pos));
@@ -332,13 +300,14 @@ fail:
e->pos = pos;
return false;
}
+EXPORT_SYMBOL_IF_KUNIT(aa_unpack_u32);
-static bool unpack_u64(struct aa_ext *e, u64 *data, const char *name)
+VISIBLE_IF_KUNIT bool aa_unpack_u64(struct aa_ext *e, u64 *data, const char *name)
{
void *pos = e->pos;
- if (unpack_nameX(e, AA_U64, name)) {
- if (!inbounds(e, sizeof(u64)))
+ if (aa_unpack_nameX(e, AA_U64, name)) {
+ if (!aa_inbounds(e, sizeof(u64)))
goto fail;
if (data)
*data = le64_to_cpu(get_unaligned((__le64 *) e->pos));
@@ -350,14 +319,15 @@ fail:
e->pos = pos;
return false;
}
+EXPORT_SYMBOL_IF_KUNIT(aa_unpack_u64);
-static size_t unpack_array(struct aa_ext *e, const char *name)
+VISIBLE_IF_KUNIT size_t aa_unpack_array(struct aa_ext *e, const char *name)
{
void *pos = e->pos;
- if (unpack_nameX(e, AA_ARRAY, name)) {
+ if (aa_unpack_nameX(e, AA_ARRAY, name)) {
int size;
- if (!inbounds(e, sizeof(u16)))
+ if (!aa_inbounds(e, sizeof(u16)))
goto fail;
size = (int)le16_to_cpu(get_unaligned((__le16 *) e->pos));
e->pos += sizeof(u16);
@@ -368,18 +338,19 @@ fail:
e->pos = pos;
return 0;
}
+EXPORT_SYMBOL_IF_KUNIT(aa_unpack_array);
-static size_t unpack_blob(struct aa_ext *e, char **blob, const char *name)
+VISIBLE_IF_KUNIT size_t aa_unpack_blob(struct aa_ext *e, char **blob, const char *name)
{
void *pos = e->pos;
- if (unpack_nameX(e, AA_BLOB, name)) {
+ if (aa_unpack_nameX(e, AA_BLOB, name)) {
u32 size;
- if (!inbounds(e, sizeof(u32)))
+ if (!aa_inbounds(e, sizeof(u32)))
goto fail;
size = le32_to_cpu(get_unaligned((__le32 *) e->pos));
e->pos += sizeof(u32);
- if (inbounds(e, (size_t) size)) {
+ if (aa_inbounds(e, (size_t) size)) {
*blob = e->pos;
e->pos += size;
return size;
@@ -390,15 +361,16 @@ fail:
e->pos = pos;
return 0;
}
+EXPORT_SYMBOL_IF_KUNIT(aa_unpack_blob);
-static int unpack_str(struct aa_ext *e, const char **string, const char *name)
+VISIBLE_IF_KUNIT int aa_unpack_str(struct aa_ext *e, const char **string, const char *name)
{
char *src_str;
size_t size = 0;
void *pos = e->pos;
*string = NULL;
- if (unpack_nameX(e, AA_STRING, name)) {
- size = unpack_u16_chunk(e, &src_str);
+ if (aa_unpack_nameX(e, AA_STRING, name)) {
+ size = aa_unpack_u16_chunk(e, &src_str);
if (size) {
/* strings are null terminated, length is size - 1 */
if (src_str[size - 1] != 0)
@@ -413,12 +385,13 @@ fail:
e->pos = pos;
return 0;
}
+EXPORT_SYMBOL_IF_KUNIT(aa_unpack_str);
-static int unpack_strdup(struct aa_ext *e, char **string, const char *name)
+VISIBLE_IF_KUNIT int aa_unpack_strdup(struct aa_ext *e, char **string, const char *name)
{
const char *tmp;
void *pos = e->pos;
- int res = unpack_str(e, &tmp, name);
+ int res = aa_unpack_str(e, &tmp, name);
*string = NULL;
if (!res)
@@ -432,6 +405,7 @@ static int unpack_strdup(struct aa_ext *e, char **string, const char *name)
return res;
}
+EXPORT_SYMBOL_IF_KUNIT(aa_unpack_strdup);
/**
@@ -446,7 +420,7 @@ static struct aa_dfa *unpack_dfa(struct aa_ext *e)
size_t size;
struct aa_dfa *dfa = NULL;
- size = unpack_blob(e, &blob, "aadfa");
+ size = aa_unpack_blob(e, &blob, "aadfa");
if (size) {
/*
* The dfa is aligned with in the blob to 8 bytes
@@ -482,10 +456,10 @@ static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile)
void *saved_pos = e->pos;
/* exec table is optional */
- if (unpack_nameX(e, AA_STRUCT, "xtable")) {
+ if (aa_unpack_nameX(e, AA_STRUCT, "xtable")) {
int i, size;
- size = unpack_array(e, NULL);
+ size = aa_unpack_array(e, NULL);
/* currently 4 exec bits and entries 0-3 are reserved iupcx */
if (size > 16 - 4)
goto fail;
@@ -497,8 +471,8 @@ static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile)
profile->file.trans.size = size;
for (i = 0; i < size; i++) {
char *str;
- int c, j, pos, size2 = unpack_strdup(e, &str, NULL);
- /* unpack_strdup verifies that the last character is
+ int c, j, pos, size2 = aa_unpack_strdup(e, &str, NULL);
+ /* aa_unpack_strdup verifies that the last character is
* null termination byte.
*/
if (!size2)
@@ -521,7 +495,7 @@ static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile)
goto fail;
/* beginning with : requires an embedded \0,
* verify that exactly 1 internal \0 exists
- * trailing \0 already verified by unpack_strdup
+ * trailing \0 already verified by aa_unpack_strdup
*
* convert \0 back to : for label_parse
*/
@@ -533,9 +507,9 @@ static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile)
/* fail - all other cases with embedded \0 */
goto fail;
}
- if (!unpack_nameX(e, AA_ARRAYEND, NULL))
+ if (!aa_unpack_nameX(e, AA_ARRAYEND, NULL))
goto fail;
- if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+ if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
goto fail;
}
return true;
@@ -550,21 +524,21 @@ static bool unpack_xattrs(struct aa_ext *e, struct aa_profile *profile)
{
void *pos = e->pos;
- if (unpack_nameX(e, AA_STRUCT, "xattrs")) {
+ if (aa_unpack_nameX(e, AA_STRUCT, "xattrs")) {
int i, size;
- size = unpack_array(e, NULL);
+ size = aa_unpack_array(e, NULL);
profile->xattr_count = size;
profile->xattrs = kcalloc(size, sizeof(char *), GFP_KERNEL);
if (!profile->xattrs)
goto fail;
for (i = 0; i < size; i++) {
- if (!unpack_strdup(e, &profile->xattrs[i], NULL))
+ if (!aa_unpack_strdup(e, &profile->xattrs[i], NULL))
goto fail;
}
- if (!unpack_nameX(e, AA_ARRAYEND, NULL))
+ if (!aa_unpack_nameX(e, AA_ARRAYEND, NULL))
goto fail;
- if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+ if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
goto fail;
}
@@ -580,8 +554,8 @@ static bool unpack_secmark(struct aa_ext *e, struct aa_profile *profile)
void *pos = e->pos;
int i, size;
- if (unpack_nameX(e, AA_STRUCT, "secmark")) {
- size = unpack_array(e, NULL);
+ if (aa_unpack_nameX(e, AA_STRUCT, "secmark")) {
+ size = aa_unpack_array(e, NULL);
profile->secmark = kcalloc(size, sizeof(struct aa_secmark),
GFP_KERNEL);
@@ -595,12 +569,12 @@ static bool unpack_secmark(struct aa_ext *e, struct aa_profile *profile)
goto fail;
if (!unpack_u8(e, &profile->secmark[i].deny, NULL))
goto fail;
- if (!unpack_strdup(e, &profile->secmark[i].label, NULL))
+ if (!aa_unpack_strdup(e, &profile->secmark[i].label, NULL))
goto fail;
}
- if (!unpack_nameX(e, AA_ARRAYEND, NULL))
+ if (!aa_unpack_nameX(e, AA_ARRAYEND, NULL))
goto fail;
- if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+ if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
goto fail;
}
@@ -624,26 +598,26 @@ static bool unpack_rlimits(struct aa_ext *e, struct aa_profile *profile)
void *pos = e->pos;
/* rlimits are optional */
- if (unpack_nameX(e, AA_STRUCT, "rlimits")) {
+ if (aa_unpack_nameX(e, AA_STRUCT, "rlimits")) {
int i, size;
u32 tmp = 0;
- if (!unpack_u32(e, &tmp, NULL))
+ if (!aa_unpack_u32(e, &tmp, NULL))
goto fail;
profile->rlimits.mask = tmp;
- size = unpack_array(e, NULL);
+ size = aa_unpack_array(e, NULL);
if (size > RLIM_NLIMITS)
goto fail;
for (i = 0; i < size; i++) {
u64 tmp2 = 0;
int a = aa_map_resource(i);
- if (!unpack_u64(e, &tmp2, NULL))
+ if (!aa_unpack_u64(e, &tmp2, NULL))
goto fail;
profile->rlimits.limits[a].rlim_max = tmp2;
}
- if (!unpack_nameX(e, AA_ARRAYEND, NULL))
+ if (!aa_unpack_nameX(e, AA_ARRAYEND, NULL))
goto fail;
- if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+ if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
goto fail;
}
return true;
@@ -691,9 +665,9 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
*ns_name = NULL;
/* check that we have the right struct being passed */
- if (!unpack_nameX(e, AA_STRUCT, "profile"))
+ if (!aa_unpack_nameX(e, AA_STRUCT, "profile"))
goto fail;
- if (!unpack_str(e, &name, NULL))
+ if (!aa_unpack_str(e, &name, NULL))
goto fail;
if (*name == '\0')
goto fail;
@@ -713,10 +687,10 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
return ERR_PTR(-ENOMEM);
/* profile renaming is optional */
- (void) unpack_str(e, &profile->rename, "rename");
+ (void) aa_unpack_str(e, &profile->rename, "rename");
/* attachment string is optional */
- (void) unpack_str(e, &profile->attach, "attach");
+ (void) aa_unpack_str(e, &profile->attach, "attach");
/* xmatch is optional and may be NULL */
profile->xmatch = unpack_dfa(e);
@@ -728,7 +702,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
}
/* xmatch_len is not optional if xmatch is set */
if (profile->xmatch) {
- if (!unpack_u32(e, &tmp, NULL)) {
+ if (!aa_unpack_u32(e, &tmp, NULL)) {
info = "missing xmatch len";
goto fail;
}
@@ -736,15 +710,15 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
}
/* disconnected attachment string is optional */
- (void) unpack_str(e, &profile->disconnected, "disconnected");
+ (void) aa_unpack_str(e, &profile->disconnected, "disconnected");
/* per profile debug flags (complain, audit) */
- if (!unpack_nameX(e, AA_STRUCT, "flags")) {
+ if (!aa_unpack_nameX(e, AA_STRUCT, "flags")) {
info = "profile missing flags";
goto fail;
}
info = "failed to unpack profile flags";
- if (!unpack_u32(e, &tmp, NULL))
+ if (!aa_unpack_u32(e, &tmp, NULL))
goto fail;
if (tmp & PACKED_FLAG_HAT)
profile->label.flags |= FLAG_HAT;
@@ -752,7 +726,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
profile->label.flags |= FLAG_DEBUG1;
if (tmp & PACKED_FLAG_DEBUG2)
profile->label.flags |= FLAG_DEBUG2;
- if (!unpack_u32(e, &tmp, NULL))
+ if (!aa_unpack_u32(e, &tmp, NULL))
goto fail;
if (tmp == PACKED_MODE_COMPLAIN || (e->version & FORCE_COMPLAIN_FLAG)) {
profile->mode = APPARMOR_COMPLAIN;
@@ -766,16 +740,16 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
} else {
goto fail;
}
- if (!unpack_u32(e, &tmp, NULL))
+ if (!aa_unpack_u32(e, &tmp, NULL))
goto fail;
if (tmp)
profile->audit = AUDIT_ALL;
- if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+ if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
goto fail;
/* path_flags is optional */
- if (unpack_u32(e, &profile->path_flags, "path_flags"))
+ if (aa_unpack_u32(e, &profile->path_flags, "path_flags"))
profile->path_flags |= profile->label.flags &
PATH_MEDIATE_DELETED;
else
@@ -783,38 +757,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
profile->path_flags = PATH_MEDIATE_DELETED;
info = "failed to unpack profile capabilities";
- if (!unpack_u32(e, &(profile->caps.allow.cap[0]), NULL))
+ if (!aa_unpack_u32(e, &(profile->caps.allow.cap[0]), NULL))
goto fail;
- if (!unpack_u32(e, &(profile->caps.audit.cap[0]), NULL))
+ if (!aa_unpack_u32(e, &(profile->caps.audit.cap[0]), NULL))
goto fail;
- if (!unpack_u32(e, &(profile->caps.quiet.cap[0]), NULL))
+ if (!aa_unpack_u32(e, &(profile->caps.quiet.cap[0]), NULL))
goto fail;
- if (!unpack_u32(e, &tmpcap.cap[0], NULL))
+ if (!aa_unpack_u32(e, &tmpcap.cap[0], NULL))
goto fail;
info = "failed to unpack upper profile capabilities";
- if (unpack_nameX(e, AA_STRUCT, "caps64")) {
+ if (aa_unpack_nameX(e, AA_STRUCT, "caps64")) {
/* optional upper half of 64 bit caps */
- if (!unpack_u32(e, &(profile->caps.allow.cap[1]), NULL))
+ if (!aa_unpack_u32(e, &(profile->caps.allow.cap[1]), NULL))
goto fail;
- if (!unpack_u32(e, &(profile->caps.audit.cap[1]), NULL))
+ if (!aa_unpack_u32(e, &(profile->caps.audit.cap[1]), NULL))
goto fail;
- if (!unpack_u32(e, &(profile->caps.quiet.cap[1]), NULL))
+ if (!aa_unpack_u32(e, &(profile->caps.quiet.cap[1]), NULL))
goto fail;
- if (!unpack_u32(e, &(tmpcap.cap[1]), NULL))
+ if (!aa_unpack_u32(e, &(tmpcap.cap[1]), NULL))
goto fail;
- if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+ if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
goto fail;
}
info = "failed to unpack extended profile capabilities";
- if (unpack_nameX(e, AA_STRUCT, "capsx")) {
+ if (aa_unpack_nameX(e, AA_STRUCT, "capsx")) {
/* optional extended caps mediation mask */
- if (!unpack_u32(e, &(profile->caps.extended.cap[0]), NULL))
+ if (!aa_unpack_u32(e, &(profile->caps.extended.cap[0]), NULL))
goto fail;
- if (!unpack_u32(e, &(profile->caps.extended.cap[1]), NULL))
+ if (!aa_unpack_u32(e, &(profile->caps.extended.cap[1]), NULL))
goto fail;
- if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+ if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
goto fail;
}
@@ -833,7 +807,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
goto fail;
}
- if (unpack_nameX(e, AA_STRUCT, "policydb")) {
+ if (aa_unpack_nameX(e, AA_STRUCT, "policydb")) {
/* generic policy dfa - optional and may be NULL */
info = "failed to unpack policydb";
profile->policy.dfa = unpack_dfa(e);
@@ -845,7 +819,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
error = -EPROTO;
goto fail;
}
- if (!unpack_u32(e, &profile->policy.start[0], "start"))
+ if (!aa_unpack_u32(e, &profile->policy.start[0], "start"))
/* default start state */
profile->policy.start[0] = DFA_START;
/* setup class index */
@@ -855,7 +829,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
profile->policy.start[0],
i);
}
- if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+ if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
goto fail;
} else
profile->policy.dfa = aa_get_dfa(nulldfa);
@@ -868,7 +842,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
info = "failed to unpack profile file rules";
goto fail;
} else if (profile->file.dfa) {
- if (!unpack_u32(e, &profile->file.start, "dfa_start"))
+ if (!aa_unpack_u32(e, &profile->file.start, "dfa_start"))
/* default start state */
profile->file.start = DFA_START;
} else if (profile->policy.dfa &&
@@ -883,7 +857,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
goto fail;
}
- if (unpack_nameX(e, AA_STRUCT, "data")) {
+ if (aa_unpack_nameX(e, AA_STRUCT, "data")) {
info = "out of memory";
profile->data = kzalloc(sizeof(*profile->data), GFP_KERNEL);
if (!profile->data)
@@ -901,7 +875,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
goto fail;
}
- while (unpack_strdup(e, &key, NULL)) {
+ while (aa_unpack_strdup(e, &key, NULL)) {
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data) {
kfree_sensitive(key);
@@ -909,7 +883,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
}
data->key = key;
- data->size = unpack_blob(e, &data->data, NULL);
+ data->size = aa_unpack_blob(e, &data->data, NULL);
data->data = kvmemdup(data->data, data->size);
if (data->size && !data->data) {
kfree_sensitive(data->key);
@@ -921,13 +895,13 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
profile->data->p);
}
- if (!unpack_nameX(e, AA_STRUCTEND, NULL)) {
+ if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL)) {
info = "failed to unpack end of key, value data table";
goto fail;
}
}
- if (!unpack_nameX(e, AA_STRUCTEND, NULL)) {
+ if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL)) {
info = "failed to unpack end of profile";
goto fail;
}
@@ -960,7 +934,7 @@ static int verify_header(struct aa_ext *e, int required, const char **ns)
*ns = NULL;
/* get the interface version */
- if (!unpack_u32(e, &e->version, "version")) {
+ if (!aa_unpack_u32(e, &e->version, "version")) {
if (required) {
audit_iface(NULL, NULL, NULL, "invalid profile format",
e, error);
@@ -979,7 +953,7 @@ static int verify_header(struct aa_ext *e, int required, const char **ns)
}
/* read the namespace if present */
- if (unpack_str(e, &name, "namespace")) {
+ if (aa_unpack_str(e, &name, "namespace")) {
if (*name == '\0') {
audit_iface(NULL, NULL, NULL, "invalid namespace name",
e, error);
@@ -1251,7 +1225,3 @@ fail:
return error;
}
-
-#ifdef CONFIG_SECURITY_APPARMOR_KUNIT_TEST
-#include "policy_unpack_test.c"
-#endif /* CONFIG_SECURITY_APPARMOR_KUNIT_TEST */
diff --git a/security/apparmor/policy_unpack_test.c b/security/apparmor/policy_unpack_test.c
index 0a969b2e03db..f25cf2a023d5 100644
--- a/security/apparmor/policy_unpack_test.c
+++ b/security/apparmor/policy_unpack_test.c
@@ -4,6 +4,7 @@
*/
#include <kunit/test.h>
+#include <kunit/visibility.h>
#include "include/policy.h"
#include "include/policy_unpack.h"
@@ -43,6 +44,8 @@
#define TEST_ARRAY_BUF_OFFSET \
(TEST_NAMED_ARRAY_BUF_OFFSET + 3 + strlen(TEST_ARRAY_NAME) + 1)
+MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING);
+
struct policy_unpack_fixture {
struct aa_ext *e;
size_t e_size;
@@ -125,16 +128,16 @@ static void policy_unpack_test_inbounds_when_inbounds(struct kunit *test)
{
struct policy_unpack_fixture *puf = test->priv;
- KUNIT_EXPECT_TRUE(test, inbounds(puf->e, 0));
- KUNIT_EXPECT_TRUE(test, inbounds(puf->e, puf->e_size / 2));
- KUNIT_EXPECT_TRUE(test, inbounds(puf->e, puf->e_size));
+ KUNIT_EXPECT_TRUE(test, aa_inbounds(puf->e, 0));
+ KUNIT_EXPECT_TRUE(test, aa_inbounds(puf->e, puf->e_size / 2));
+ KUNIT_EXPECT_TRUE(test, aa_inbounds(puf->e, puf->e_size));
}
static void policy_unpack_test_inbounds_when_out_of_bounds(struct kunit *test)
{
struct policy_unpack_fixture *puf = test->priv;
- KUNIT_EXPECT_FALSE(test, inbounds(puf->e, puf->e_size + 1));
+ KUNIT_EXPECT_FALSE(test, aa_inbounds(puf->e, puf->e_size + 1));
}
static void policy_unpack_test_unpack_array_with_null_name(struct kunit *test)
@@ -144,7 +147,7 @@ static void policy_unpack_test_unpack_array_with_null_name(struct kunit *test)
puf->e->pos += TEST_ARRAY_BUF_OFFSET;
- array_size = unpack_array(puf->e, NULL);
+ array_size = aa_unpack_array(puf->e, NULL);
KUNIT_EXPECT_EQ(test, array_size, (u16)TEST_ARRAY_SIZE);
KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
@@ -159,7 +162,7 @@ static void policy_unpack_test_unpack_array_with_name(struct kunit *test)
puf->e->pos += TEST_NAMED_ARRAY_BUF_OFFSET;
- array_size = unpack_array(puf->e, name);
+ array_size = aa_unpack_array(puf->e, name);
KUNIT_EXPECT_EQ(test, array_size, (u16)TEST_ARRAY_SIZE);
KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
@@ -175,7 +178,7 @@ static void policy_unpack_test_unpack_array_out_of_bounds(struct kunit *test)
puf->e->pos += TEST_NAMED_ARRAY_BUF_OFFSET;
puf->e->end = puf->e->start + TEST_ARRAY_BUF_OFFSET + sizeof(u16);
- array_size = unpack_array(puf->e, name);
+ array_size = aa_unpack_array(puf->e, name);
KUNIT_EXPECT_EQ(test, array_size, 0);
KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
@@ -189,7 +192,7 @@ static void policy_unpack_test_unpack_blob_with_null_name(struct kunit *test)
size_t size;
puf->e->pos += TEST_BLOB_BUF_OFFSET;
- size = unpack_blob(puf->e, &blob, NULL);
+ size = aa_unpack_blob(puf->e, &blob, NULL);
KUNIT_ASSERT_EQ(test, size, TEST_BLOB_DATA_SIZE);
KUNIT_EXPECT_TRUE(test,
@@ -203,7 +206,7 @@ static void policy_unpack_test_unpack_blob_with_name(struct kunit *test)
size_t size;
puf->e->pos += TEST_NAMED_BLOB_BUF_OFFSET;
- size = unpack_blob(puf->e, &blob, TEST_BLOB_NAME);
+ size = aa_unpack_blob(puf->e, &blob, TEST_BLOB_NAME);
KUNIT_ASSERT_EQ(test, size, TEST_BLOB_DATA_SIZE);
KUNIT_EXPECT_TRUE(test,
@@ -222,7 +225,7 @@ static void policy_unpack_test_unpack_blob_out_of_bounds(struct kunit *test)
puf->e->end = puf->e->start + TEST_BLOB_BUF_OFFSET
+ TEST_BLOB_DATA_SIZE - 1;
- size = unpack_blob(puf->e, &blob, TEST_BLOB_NAME);
+ size = aa_unpack_blob(puf->e, &blob, TEST_BLOB_NAME);
KUNIT_EXPECT_EQ(test, size, 0);
KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, start);
@@ -235,7 +238,7 @@ static void policy_unpack_test_unpack_str_with_null_name(struct kunit *test)
size_t size;
puf->e->pos += TEST_STRING_BUF_OFFSET;
- size = unpack_str(puf->e, &string, NULL);
+ size = aa_unpack_str(puf->e, &string, NULL);
KUNIT_EXPECT_EQ(test, size, strlen(TEST_STRING_DATA) + 1);
KUNIT_EXPECT_STREQ(test, string, TEST_STRING_DATA);
@@ -247,7 +250,7 @@ static void policy_unpack_test_unpack_str_with_name(struct kunit *test)
const char *string = NULL;
size_t size;
- size = unpack_str(puf->e, &string, TEST_STRING_NAME);
+ size = aa_unpack_str(puf->e, &string, TEST_STRING_NAME);
KUNIT_EXPECT_EQ(test, size, strlen(TEST_STRING_DATA) + 1);
KUNIT_EXPECT_STREQ(test, string, TEST_STRING_DATA);
@@ -263,7 +266,7 @@ static void policy_unpack_test_unpack_str_out_of_bounds(struct kunit *test)
puf->e->end = puf->e->pos + TEST_STRING_BUF_OFFSET
+ strlen(TEST_STRING_DATA) - 1;
- size = unpack_str(puf->e, &string, TEST_STRING_NAME);
+ size = aa_unpack_str(puf->e, &string, TEST_STRING_NAME);
KUNIT_EXPECT_EQ(test, size, 0);
KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, start);
@@ -276,7 +279,7 @@ static void policy_unpack_test_unpack_strdup_with_null_name(struct kunit *test)
size_t size;
puf->e->pos += TEST_STRING_BUF_OFFSET;
- size = unpack_strdup(puf->e, &string, NULL);
+ size = aa_unpack_strdup(puf->e, &string, NULL);
KUNIT_EXPECT_EQ(test, size, strlen(TEST_STRING_DATA) + 1);
KUNIT_EXPECT_FALSE(test,
@@ -291,7 +294,7 @@ static void policy_unpack_test_unpack_strdup_with_name(struct kunit *test)
char *string = NULL;
size_t size;
- size = unpack_strdup(puf->e, &string, TEST_STRING_NAME);
+ size = aa_unpack_strdup(puf->e, &string, TEST_STRING_NAME);
KUNIT_EXPECT_EQ(test, size, strlen(TEST_STRING_DATA) + 1);
KUNIT_EXPECT_FALSE(test,
@@ -310,7 +313,7 @@ static void policy_unpack_test_unpack_strdup_out_of_bounds(struct kunit *test)
puf->e->end = puf->e->pos + TEST_STRING_BUF_OFFSET
+ strlen(TEST_STRING_DATA) - 1;
- size = unpack_strdup(puf->e, &string, TEST_STRING_NAME);
+ size = aa_unpack_strdup(puf->e, &string, TEST_STRING_NAME);
KUNIT_EXPECT_EQ(test, size, 0);
KUNIT_EXPECT_NULL(test, string);
@@ -324,7 +327,7 @@ static void policy_unpack_test_unpack_nameX_with_null_name(struct kunit *test)
puf->e->pos += TEST_U32_BUF_OFFSET;
- success = unpack_nameX(puf->e, AA_U32, NULL);
+ success = aa_unpack_nameX(puf->e, AA_U32, NULL);
KUNIT_EXPECT_TRUE(test, success);
KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
@@ -338,7 +341,7 @@ static void policy_unpack_test_unpack_nameX_with_wrong_code(struct kunit *test)
puf->e->pos += TEST_U32_BUF_OFFSET;
- success = unpack_nameX(puf->e, AA_BLOB, NULL);
+ success = aa_unpack_nameX(puf->e, AA_BLOB, NULL);
KUNIT_EXPECT_FALSE(test, success);
KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
@@ -353,7 +356,7 @@ static void policy_unpack_test_unpack_nameX_with_name(struct kunit *test)
puf->e->pos += TEST_NAMED_U32_BUF_OFFSET;
- success = unpack_nameX(puf->e, AA_U32, name);
+ success = aa_unpack_nameX(puf->e, AA_U32, name);
KUNIT_EXPECT_TRUE(test, success);
KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
@@ -368,7 +371,7 @@ static void policy_unpack_test_unpack_nameX_with_wrong_name(struct kunit *test)
puf->e->pos += TEST_NAMED_U32_BUF_OFFSET;
- success = unpack_nameX(puf->e, AA_U32, name);
+ success = aa_unpack_nameX(puf->e, AA_U32, name);
KUNIT_EXPECT_FALSE(test, success);
KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
@@ -389,7 +392,7 @@ static void policy_unpack_test_unpack_u16_chunk_basic(struct kunit *test)
*/
puf->e->end += TEST_U16_DATA;
- size = unpack_u16_chunk(puf->e, &chunk);
+ size = aa_unpack_u16_chunk(puf->e, &chunk);
KUNIT_EXPECT_PTR_EQ(test, chunk,
puf->e->start + TEST_U16_OFFSET + 2);
@@ -406,7 +409,7 @@ static void policy_unpack_test_unpack_u16_chunk_out_of_bounds_1(
puf->e->pos = puf->e->end - 1;
- size = unpack_u16_chunk(puf->e, &chunk);
+ size = aa_unpack_u16_chunk(puf->e, &chunk);
KUNIT_EXPECT_EQ(test, size, 0);
KUNIT_EXPECT_NULL(test, chunk);
@@ -428,7 +431,7 @@ static void policy_unpack_test_unpack_u16_chunk_out_of_bounds_2(
*/
puf->e->end = puf->e->pos + TEST_U16_DATA - 1;
- size = unpack_u16_chunk(puf->e, &chunk);
+ size = aa_unpack_u16_chunk(puf->e, &chunk);
KUNIT_EXPECT_EQ(test, size, 0);
KUNIT_EXPECT_NULL(test, chunk);
@@ -443,7 +446,7 @@ static void policy_unpack_test_unpack_u32_with_null_name(struct kunit *test)
puf->e->pos += TEST_U32_BUF_OFFSET;
- success = unpack_u32(puf->e, &data, NULL);
+ success = aa_unpack_u32(puf->e, &data, NULL);
KUNIT_EXPECT_TRUE(test, success);
KUNIT_EXPECT_EQ(test, data, TEST_U32_DATA);
@@ -460,7 +463,7 @@ static void policy_unpack_test_unpack_u32_with_name(struct kunit *test)
puf->e->pos += TEST_NAMED_U32_BUF_OFFSET;
- success = unpack_u32(puf->e, &data, name);
+ success = aa_unpack_u32(puf->e, &data, name);
KUNIT_EXPECT_TRUE(test, success);
KUNIT_EXPECT_EQ(test, data, TEST_U32_DATA);
@@ -478,7 +481,7 @@ static void policy_unpack_test_unpack_u32_out_of_bounds(struct kunit *test)
puf->e->pos += TEST_NAMED_U32_BUF_OFFSET;
puf->e->end = puf->e->start + TEST_U32_BUF_OFFSET + sizeof(u32);
- success = unpack_u32(puf->e, &data, name);
+ success = aa_unpack_u32(puf->e, &data, name);
KUNIT_EXPECT_FALSE(test, success);
KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
@@ -493,7 +496,7 @@ static void policy_unpack_test_unpack_u64_with_null_name(struct kunit *test)
puf->e->pos += TEST_U64_BUF_OFFSET;
- success = unpack_u64(puf->e, &data, NULL);
+ success = aa_unpack_u64(puf->e, &data, NULL);
KUNIT_EXPECT_TRUE(test, success);
KUNIT_EXPECT_EQ(test, data, TEST_U64_DATA);
@@ -510,7 +513,7 @@ static void policy_unpack_test_unpack_u64_with_name(struct kunit *test)
puf->e->pos += TEST_NAMED_U64_BUF_OFFSET;
- success = unpack_u64(puf->e, &data, name);
+ success = aa_unpack_u64(puf->e, &data, name);
KUNIT_EXPECT_TRUE(test, success);
KUNIT_EXPECT_EQ(test, data, TEST_U64_DATA);
@@ -528,7 +531,7 @@ static void policy_unpack_test_unpack_u64_out_of_bounds(struct kunit *test)
puf->e->pos += TEST_NAMED_U64_BUF_OFFSET;
puf->e->end = puf->e->start + TEST_U64_BUF_OFFSET + sizeof(u64);
- success = unpack_u64(puf->e, &data, name);
+ success = aa_unpack_u64(puf->e, &data, name);
KUNIT_EXPECT_FALSE(test, success);
KUNIT_EXPECT_PTR_EQ(test, puf->e->pos,
@@ -538,7 +541,7 @@ static void policy_unpack_test_unpack_u64_out_of_bounds(struct kunit *test)
static void policy_unpack_test_unpack_X_code_match(struct kunit *test)
{
struct policy_unpack_fixture *puf = test->priv;
- bool success = unpack_X(puf->e, AA_NAME);
+ bool success = aa_unpack_X(puf->e, AA_NAME);
KUNIT_EXPECT_TRUE(test, success);
KUNIT_EXPECT_TRUE(test, puf->e->pos == puf->e->start + 1);
@@ -547,7 +550,7 @@ static void policy_unpack_test_unpack_X_code_match(struct kunit *test)
static void policy_unpack_test_unpack_X_code_mismatch(struct kunit *test)
{
struct policy_unpack_fixture *puf = test->priv;
- bool success = unpack_X(puf->e, AA_STRING);
+ bool success = aa_unpack_X(puf->e, AA_STRING);
KUNIT_EXPECT_FALSE(test, success);
KUNIT_EXPECT_TRUE(test, puf->e->pos == puf->e->start);
@@ -559,7 +562,7 @@ static void policy_unpack_test_unpack_X_out_of_bounds(struct kunit *test)
bool success;
puf->e->pos = puf->e->end;
- success = unpack_X(puf->e, AA_NAME);
+ success = aa_unpack_X(puf->e, AA_NAME);
KUNIT_EXPECT_FALSE(test, success);
}
@@ -605,3 +608,5 @@ static struct kunit_suite apparmor_policy_unpack_test_module = {
};
kunit_test_suite(apparmor_policy_unpack_test_module);
+
+MODULE_LICENSE("GPL");
diff --git a/security/commoncap.c b/security/commoncap.c
index 5fc8986c3c77..5d9570f54a1c 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -328,14 +328,16 @@ int cap_inode_killpriv(struct user_namespace *mnt_userns, struct dentry *dentry)
return error;
}
-static bool rootid_owns_currentns(kuid_t kroot)
+static bool rootid_owns_currentns(vfsuid_t rootvfsuid)
{
struct user_namespace *ns;
+ kuid_t kroot;
- if (!uid_valid(kroot))
+ if (!vfsuid_valid(rootvfsuid))
return false;
- for (ns = current_user_ns(); ; ns = ns->parent) {
+ kroot = vfsuid_into_kuid(rootvfsuid);
+ for (ns = current_user_ns();; ns = ns->parent) {
if (from_kuid(ns, kroot) == 0)
return true;
if (ns == &init_user_ns)
@@ -381,6 +383,7 @@ int cap_inode_getsecurity(struct user_namespace *mnt_userns,
{
int size, ret;
kuid_t kroot;
+ vfsuid_t vfsroot;
u32 nsmagic, magic;
uid_t root, mappedroot;
char *tmpbuf = NULL;
@@ -401,8 +404,10 @@ int cap_inode_getsecurity(struct user_namespace *mnt_userns,
&tmpbuf, size, GFP_NOFS);
dput(dentry);
- if (ret < 0 || !tmpbuf)
- return ret;
+ if (ret < 0 || !tmpbuf) {
+ size = ret;
+ goto out_free;
+ }
fs_ns = inode->i_sb->s_user_ns;
cap = (struct vfs_cap_data *) tmpbuf;
@@ -419,11 +424,11 @@ int cap_inode_getsecurity(struct user_namespace *mnt_userns,
kroot = make_kuid(fs_ns, root);
/* If this is an idmapped mount shift the kuid. */
- kroot = mapped_kuid_fs(mnt_userns, fs_ns, kroot);
+ vfsroot = make_vfsuid(mnt_userns, fs_ns, kroot);
/* If the root kuid maps to a valid uid in current ns, then return
* this as a nscap. */
- mappedroot = from_kuid(current_user_ns(), kroot);
+ mappedroot = from_kuid(current_user_ns(), vfsuid_into_kuid(vfsroot));
if (mappedroot != (uid_t)-1 && mappedroot != (uid_t)0) {
size = sizeof(struct vfs_ns_cap_data);
if (alloc) {
@@ -450,7 +455,7 @@ int cap_inode_getsecurity(struct user_namespace *mnt_userns,
goto out_free;
}
- if (!rootid_owns_currentns(kroot)) {
+ if (!rootid_owns_currentns(vfsroot)) {
size = -EOVERFLOW;
goto out_free;
}
@@ -488,29 +493,17 @@ out_free:
* @value: vfs caps value which may be modified by this function
* @size: size of @ivalue
* @task_ns: user namespace of the caller
- * @mnt_userns: user namespace of the mount the inode was found from
- * @fs_userns: user namespace of the filesystem
- *
- * If the inode has been found through an idmapped mount the user namespace of
- * the vfsmount must be passed through @mnt_userns. This function will then
- * take care to map the inode according to @mnt_userns before checking
- * permissions. On non-idmapped mounts or if permission checking is to be
- * performed on the raw inode simply passs init_user_ns.
*/
-static kuid_t rootid_from_xattr(const void *value, size_t size,
- struct user_namespace *task_ns,
- struct user_namespace *mnt_userns,
- struct user_namespace *fs_userns)
+static vfsuid_t rootid_from_xattr(const void *value, size_t size,
+ struct user_namespace *task_ns)
{
const struct vfs_ns_cap_data *nscap = value;
- kuid_t rootkid;
uid_t rootid = 0;
if (size == XATTR_CAPS_SZ_3)
rootid = le32_to_cpu(nscap->rootid);
- rootkid = make_kuid(task_ns, rootid);
- return mapped_kuid_user(mnt_userns, fs_userns, rootkid);
+ return VFSUIDT_INIT(make_kuid(task_ns, rootid));
}
static bool validheader(size_t size, const struct vfs_cap_data *cap)
@@ -548,6 +541,7 @@ int cap_convert_nscap(struct user_namespace *mnt_userns, struct dentry *dentry,
struct user_namespace *task_ns = current_user_ns(),
*fs_ns = inode->i_sb->s_user_ns;
kuid_t rootid;
+ vfsuid_t vfsrootid;
size_t newsize;
if (!*ivalue)
@@ -561,7 +555,11 @@ int cap_convert_nscap(struct user_namespace *mnt_userns, struct dentry *dentry,
/* user is privileged, just write the v2 */
return size;
- rootid = rootid_from_xattr(*ivalue, size, task_ns, mnt_userns, fs_ns);
+ vfsrootid = rootid_from_xattr(*ivalue, size, task_ns);
+ if (!vfsuid_valid(vfsrootid))
+ return -EINVAL;
+
+ rootid = from_vfsuid(mnt_userns, fs_ns, vfsrootid);
if (!uid_valid(rootid))
return -EINVAL;
@@ -655,6 +653,7 @@ int get_vfs_caps_from_disk(struct user_namespace *mnt_userns,
struct vfs_ns_cap_data data, *nscaps = &data;
struct vfs_cap_data *caps = (struct vfs_cap_data *) &data;
kuid_t rootkuid;
+ vfsuid_t rootvfsuid;
struct user_namespace *fs_ns;
memset(cpu_caps, 0, sizeof(struct cpu_vfs_cap_data));
@@ -699,11 +698,15 @@ int get_vfs_caps_from_disk(struct user_namespace *mnt_userns,
default:
return -EINVAL;
}
+
+ rootvfsuid = make_vfsuid(mnt_userns, fs_ns, rootkuid);
+ if (!vfsuid_valid(rootvfsuid))
+ return -ENODATA;
+
/* Limit the caps to the mounter of the filesystem
* or the more limited uid specified in the xattr.
*/
- rootkuid = mapped_kuid_fs(mnt_userns, fs_ns, rootkuid);
- if (!rootid_owns_currentns(rootkuid))
+ if (!rootid_owns_currentns(rootvfsuid))
return -ENODATA;
CAP_FOR_EACH_U32(i) {
@@ -716,7 +719,7 @@ int get_vfs_caps_from_disk(struct user_namespace *mnt_userns,
cpu_caps->permitted.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
cpu_caps->inheritable.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
- cpu_caps->rootid = rootkuid;
+ cpu_caps->rootid = vfsuid_into_kuid(rootvfsuid);
return 0;
}
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 23d484e05e6f..e01cfd4ad896 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -8,7 +8,7 @@
*
* File: evm_main.c
* implements evm_inode_setxattr, evm_inode_post_setxattr,
- * evm_inode_removexattr, and evm_verifyxattr
+ * evm_inode_removexattr, evm_verifyxattr, and evm_inode_set_acl.
*/
#define pr_fmt(fmt) "EVM: "fmt
@@ -435,66 +435,6 @@ static enum integrity_status evm_verify_current_integrity(struct dentry *dentry)
}
/*
- * evm_xattr_acl_change - check if passed ACL changes the inode mode
- * @mnt_userns: user namespace of the idmapped mount
- * @dentry: pointer to the affected dentry
- * @xattr_name: requested xattr
- * @xattr_value: requested xattr value
- * @xattr_value_len: requested xattr value length
- *
- * Check if passed ACL changes the inode mode, which is protected by EVM.
- *
- * Returns 1 if passed ACL causes inode mode change, 0 otherwise.
- */
-static int evm_xattr_acl_change(struct user_namespace *mnt_userns,
- struct dentry *dentry, const char *xattr_name,
- const void *xattr_value, size_t xattr_value_len)
-{
-#ifdef CONFIG_FS_POSIX_ACL
- umode_t mode;
- struct posix_acl *acl = NULL, *acl_res;
- struct inode *inode = d_backing_inode(dentry);
- int rc;
-
- /*
- * An earlier comment here mentioned that the idmappings for
- * ACL_{GROUP,USER} don't matter since EVM is only interested in the
- * mode stored as part of POSIX ACLs. Nonetheless, if it must translate
- * from the uapi POSIX ACL representation to the VFS internal POSIX ACL
- * representation it should do so correctly. There's no guarantee that
- * we won't change POSIX ACLs in a way that ACL_{GROUP,USER} matters
- * for the mode at some point and it's difficult to keep track of all
- * the LSM and integrity modules and what they do to POSIX ACLs.
- *
- * Frankly, EVM shouldn't try to interpret the uapi struct for POSIX
- * ACLs it received. It requires knowledge that only the VFS is
- * guaranteed to have.
- */
- acl = vfs_set_acl_prepare(mnt_userns, i_user_ns(inode),
- xattr_value, xattr_value_len);
- if (IS_ERR_OR_NULL(acl))
- return 1;
-
- acl_res = acl;
- /*
- * Passing mnt_userns is necessary to correctly determine the GID in
- * an idmapped mount, as the GID is used to clear the setgid bit in
- * the inode mode.
- */
- rc = posix_acl_update_mode(mnt_userns, inode, &mode, &acl_res);
-
- posix_acl_release(acl);
-
- if (rc)
- return 1;
-
- if (inode->i_mode != mode)
- return 1;
-#endif
- return 0;
-}
-
-/*
* evm_xattr_change - check if passed xattr value differs from current value
* @mnt_userns: user namespace of the idmapped mount
* @dentry: pointer to the affected dentry
@@ -513,10 +453,6 @@ static int evm_xattr_change(struct user_namespace *mnt_userns,
char *xattr_data = NULL;
int rc = 0;
- if (posix_xattr_acl(xattr_name))
- return evm_xattr_acl_change(mnt_userns, dentry, xattr_name,
- xattr_value, xattr_value_len);
-
rc = vfs_getxattr_alloc(&init_user_ns, dentry, xattr_name, &xattr_data,
0, GFP_NOFS);
if (rc < 0)
@@ -670,6 +606,86 @@ int evm_inode_removexattr(struct user_namespace *mnt_userns,
return evm_protect_xattr(mnt_userns, dentry, xattr_name, NULL, 0);
}
+#ifdef CONFIG_FS_POSIX_ACL
+static int evm_inode_set_acl_change(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *name,
+ struct posix_acl *kacl)
+{
+ int rc;
+
+ umode_t mode;
+ struct inode *inode = d_backing_inode(dentry);
+
+ if (!kacl)
+ return 1;
+
+ rc = posix_acl_update_mode(mnt_userns, inode, &mode, &kacl);
+ if (rc || (inode->i_mode != mode))
+ return 1;
+
+ return 0;
+}
+#else
+static inline int evm_inode_set_acl_change(struct user_namespace *mnt_userns,
+ struct dentry *dentry,
+ const char *name,
+ struct posix_acl *kacl)
+{
+ return 0;
+}
+#endif
+
+/**
+ * evm_inode_set_acl - protect the EVM extended attribute from posix acls
+ * @mnt_userns: user namespace of the idmapped mount
+ * @dentry: pointer to the affected dentry
+ * @acl_name: name of the posix acl
+ * @kacl: pointer to the posix acls
+ *
+ * Prevent modifying posix acls causing the EVM HMAC to be re-calculated
+ * and 'security.evm' xattr updated, unless the existing 'security.evm' is
+ * valid.
+ */
+int evm_inode_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
+ const char *acl_name, struct posix_acl *kacl)
+{
+ enum integrity_status evm_status;
+
+ /* Policy permits modification of the protected xattrs even though
+ * there's no HMAC key loaded
+ */
+ if (evm_initialized & EVM_ALLOW_METADATA_WRITES)
+ return 0;
+
+ evm_status = evm_verify_current_integrity(dentry);
+ if ((evm_status == INTEGRITY_PASS) ||
+ (evm_status == INTEGRITY_NOXATTRS))
+ return 0;
+
+ /* Exception if the HMAC is not going to be calculated. */
+ if (evm_hmac_disabled() && (evm_status == INTEGRITY_NOLABEL ||
+ evm_status == INTEGRITY_UNKNOWN))
+ return 0;
+
+ /*
+ * Writing other xattrs is safe for portable signatures, as portable
+ * signatures are immutable and can never be updated.
+ */
+ if (evm_status == INTEGRITY_FAIL_IMMUTABLE)
+ return 0;
+
+ if (evm_status == INTEGRITY_PASS_IMMUTABLE &&
+ !evm_inode_set_acl_change(mnt_userns, dentry, acl_name, kacl))
+ return 0;
+
+ if (evm_status != INTEGRITY_PASS_IMMUTABLE)
+ integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry),
+ dentry->d_name.name, "appraise_metadata",
+ integrity_status_msg[evm_status],
+ -EPERM, 0);
+ return -EPERM;
+}
+
static void evm_reset_status(struct inode *inode)
{
struct integrity_iint_cache *iint;
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 3e0fbbd99534..3c9af3dc0713 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -774,6 +774,15 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
return result;
}
+int ima_inode_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
+ const char *acl_name, struct posix_acl *kacl)
+{
+ if (evm_revalidate_status(acl_name))
+ ima_reset_appraise_flags(d_backing_inode(dentry), 0);
+
+ return 0;
+}
+
int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
{
int result;
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index a8802b8da946..54c475f98ce1 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -85,8 +85,8 @@ struct ima_rule_entry {
kgid_t fgroup;
bool (*uid_op)(kuid_t cred_uid, kuid_t rule_uid); /* Handlers for operators */
bool (*gid_op)(kgid_t cred_gid, kgid_t rule_gid);
- bool (*fowner_op)(kuid_t cred_uid, kuid_t rule_uid); /* uid_eq(), uid_gt(), uid_lt() */
- bool (*fgroup_op)(kgid_t cred_gid, kgid_t rule_gid); /* gid_eq(), gid_gt(), gid_lt() */
+ bool (*fowner_op)(vfsuid_t vfsuid, kuid_t rule_uid); /* vfsuid_eq_kuid(), vfsuid_gt_kuid(), vfsuid_lt_kuid() */
+ bool (*fgroup_op)(vfsgid_t vfsgid, kgid_t rule_gid); /* vfsgid_eq_kgid(), vfsgid_gt_kgid(), vfsgid_lt_kgid() */
int pcr;
unsigned int allowed_algos; /* bitfield of allowed hash algorithms */
struct {
@@ -186,11 +186,11 @@ static struct ima_rule_entry default_appraise_rules[] __ro_after_init = {
.flags = IMA_FUNC | IMA_DIGSIG_REQUIRED},
#endif
#ifndef CONFIG_IMA_APPRAISE_SIGNED_INIT
- {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .fowner_op = &uid_eq,
+ {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .fowner_op = &vfsuid_eq_kuid,
.flags = IMA_FOWNER},
#else
/* force signature */
- {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .fowner_op = &uid_eq,
+ {.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .fowner_op = &vfsuid_eq_kuid,
.flags = IMA_FOWNER | IMA_DIGSIG_REQUIRED},
#endif
};
@@ -601,10 +601,12 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
return false;
}
if ((rule->flags & IMA_FOWNER) &&
- !rule->fowner_op(i_uid_into_mnt(mnt_userns, inode), rule->fowner))
+ !rule->fowner_op(i_uid_into_vfsuid(mnt_userns, inode),
+ rule->fowner))
return false;
if ((rule->flags & IMA_FGROUP) &&
- !rule->fgroup_op(i_gid_into_mnt(mnt_userns, inode), rule->fgroup))
+ !rule->fgroup_op(i_gid_into_vfsgid(mnt_userns, inode),
+ rule->fgroup))
return false;
for (i = 0; i < MAX_LSM_RULES; i++) {
int rc = 0;
@@ -1371,8 +1373,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
entry->fgroup = INVALID_GID;
entry->uid_op = &uid_eq;
entry->gid_op = &gid_eq;
- entry->fowner_op = &uid_eq;
- entry->fgroup_op = &gid_eq;
+ entry->fowner_op = &vfsuid_eq_kuid;
+ entry->fgroup_op = &vfsgid_eq_kgid;
entry->action = UNKNOWN;
while ((p = strsep(&rule, " \t")) != NULL) {
substring_t args[MAX_OPT_ARGS];
@@ -1650,11 +1652,11 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
}
break;
case Opt_fowner_gt:
- entry->fowner_op = &uid_gt;
+ entry->fowner_op = &vfsuid_gt_kuid;
fallthrough;
case Opt_fowner_lt:
if (token == Opt_fowner_lt)
- entry->fowner_op = &uid_lt;
+ entry->fowner_op = &vfsuid_lt_kuid;
fallthrough;
case Opt_fowner_eq:
ima_log_string_op(ab, "fowner", args[0].from, token);
@@ -1676,11 +1678,11 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
}
break;
case Opt_fgroup_gt:
- entry->fgroup_op = &gid_gt;
+ entry->fgroup_op = &vfsgid_gt_kgid;
fallthrough;
case Opt_fgroup_lt:
if (token == Opt_fgroup_lt)
- entry->fgroup_op = &gid_lt;
+ entry->fgroup_op = &vfsgid_lt_kgid;
fallthrough;
case Opt_fgroup_eq:
ima_log_string_op(ab, "fgroup", args[0].from, token);
@@ -2151,9 +2153,9 @@ int ima_policy_show(struct seq_file *m, void *v)
if (entry->flags & IMA_FOWNER) {
snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->fowner));
- if (entry->fowner_op == &uid_gt)
+ if (entry->fowner_op == &vfsuid_gt_kuid)
seq_printf(m, pt(Opt_fowner_gt), tbuf);
- else if (entry->fowner_op == &uid_lt)
+ else if (entry->fowner_op == &vfsuid_lt_kuid)
seq_printf(m, pt(Opt_fowner_lt), tbuf);
else
seq_printf(m, pt(Opt_fowner_eq), tbuf);
@@ -2162,9 +2164,9 @@ int ima_policy_show(struct seq_file *m, void *v)
if (entry->flags & IMA_FGROUP) {
snprintf(tbuf, sizeof(tbuf), "%d", __kgid_val(entry->fgroup));
- if (entry->fgroup_op == &gid_gt)
+ if (entry->fgroup_op == &vfsgid_gt_kgid)
seq_printf(m, pt(Opt_fgroup_gt), tbuf);
- else if (entry->fgroup_op == &gid_lt)
+ else if (entry->fgroup_op == &vfsgid_lt_kgid)
seq_printf(m, pt(Opt_fgroup_lt), tbuf);
else
seq_printf(m, pt(Opt_fgroup_eq), tbuf);
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 96a92a645216..d54f73c558f7 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -1251,7 +1251,7 @@ long keyctl_instantiate_key(key_serial_t id,
struct iov_iter from;
int ret;
- ret = import_single_range(WRITE, (void __user *)_payload, plen,
+ ret = import_single_range(ITER_SOURCE, (void __user *)_payload, plen,
&iov, &from);
if (unlikely(ret))
return ret;
@@ -1283,7 +1283,7 @@ long keyctl_instantiate_key_iov(key_serial_t id,
if (!_payload_iov)
ioc = 0;
- ret = import_iovec(WRITE, _payload_iov, ioc,
+ ret = import_iovec(ITER_SOURCE, _payload_iov, ioc,
ARRAY_SIZE(iovstack), &iov, &from);
if (ret < 0)
return ret;
diff --git a/security/keys/trusted-keys/trusted_tee.c b/security/keys/trusted-keys/trusted_tee.c
index c8626686ee1b..ac3e270ade69 100644
--- a/security/keys/trusted-keys/trusted_tee.c
+++ b/security/keys/trusted-keys/trusted_tee.c
@@ -219,7 +219,8 @@ static int trusted_tee_get_random(unsigned char *key, size_t key_len)
static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
{
- if (ver->impl_id == TEE_IMPL_ID_OPTEE)
+ if (ver->impl_id == TEE_IMPL_ID_OPTEE &&
+ ver->gen_caps & TEE_GEN_CAP_REG_MEM)
return 1;
else
return 0;
diff --git a/security/security.c b/security/security.c
index e0fe4ba39eb9..b967e035b456 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1373,6 +1373,48 @@ int security_inode_setxattr(struct user_namespace *mnt_userns,
return evm_inode_setxattr(mnt_userns, dentry, name, value, size);
}
+int security_inode_set_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name,
+ struct posix_acl *kacl)
+{
+ int ret;
+
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+ ret = call_int_hook(inode_set_acl, 0, mnt_userns, dentry, acl_name,
+ kacl);
+ if (ret)
+ return ret;
+ ret = ima_inode_set_acl(mnt_userns, dentry, acl_name, kacl);
+ if (ret)
+ return ret;
+ return evm_inode_set_acl(mnt_userns, dentry, acl_name, kacl);
+}
+
+int security_inode_get_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name)
+{
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+ return call_int_hook(inode_get_acl, 0, mnt_userns, dentry, acl_name);
+}
+
+int security_inode_remove_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name)
+{
+ int ret;
+
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+ ret = call_int_hook(inode_remove_acl, 0, mnt_userns, dentry, acl_name);
+ if (ret)
+ return ret;
+ ret = ima_inode_remove_acl(mnt_userns, dentry, acl_name);
+ if (ret)
+ return ret;
+ return evm_inode_remove_acl(mnt_userns, dentry, acl_name);
+}
+
void security_inode_post_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
{
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f553c370397e..7c5c8d17695c 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3240,6 +3240,25 @@ static int selinux_inode_setxattr(struct user_namespace *mnt_userns,
&ad);
}
+static int selinux_inode_set_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name,
+ struct posix_acl *kacl)
+{
+ return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
+}
+
+static int selinux_inode_get_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name)
+{
+ return dentry_has_perm(current_cred(), dentry, FILE__GETATTR);
+}
+
+static int selinux_inode_remove_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name)
+{
+ return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
+}
+
static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size,
int flags)
@@ -7088,6 +7107,9 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(inode_getxattr, selinux_inode_getxattr),
LSM_HOOK_INIT(inode_listxattr, selinux_inode_listxattr),
LSM_HOOK_INIT(inode_removexattr, selinux_inode_removexattr),
+ LSM_HOOK_INIT(inode_set_acl, selinux_inode_set_acl),
+ LSM_HOOK_INIT(inode_get_acl, selinux_inode_get_acl),
+ LSM_HOOK_INIT(inode_remove_acl, selinux_inode_remove_acl),
LSM_HOOK_INIT(inode_getsecurity, selinux_inode_getsecurity),
LSM_HOOK_INIT(inode_setsecurity, selinux_inode_setsecurity),
LSM_HOOK_INIT(inode_listsecurity, selinux_inode_listsecurity),
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index fe5fcf571c56..64a6a37dc36d 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -2022,7 +2022,8 @@ static inline int convert_context_handle_invalid_context(
* in `newc'. Verify that the context is valid
* under the new policy.
*/
-static int convert_context(struct context *oldc, struct context *newc, void *p)
+static int convert_context(struct context *oldc, struct context *newc, void *p,
+ gfp_t gfp_flags)
{
struct convert_context_args *args;
struct ocontext *oc;
@@ -2036,7 +2037,7 @@ static int convert_context(struct context *oldc, struct context *newc, void *p)
args = p;
if (oldc->str) {
- s = kstrdup(oldc->str, GFP_KERNEL);
+ s = kstrdup(oldc->str, gfp_flags);
if (!s)
return -ENOMEM;
diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c
index a54b8652bfb5..db5cce385bf8 100644
--- a/security/selinux/ss/sidtab.c
+++ b/security/selinux/ss/sidtab.c
@@ -325,7 +325,7 @@ int sidtab_context_to_sid(struct sidtab *s, struct context *context,
}
rc = convert->func(context, &dst_convert->context,
- convert->args);
+ convert->args, GFP_ATOMIC);
if (rc) {
context_destroy(&dst->context);
goto out_unlock;
@@ -404,7 +404,7 @@ static int sidtab_convert_tree(union sidtab_entry_inner *edst,
while (i < SIDTAB_LEAF_ENTRIES && *pos < count) {
rc = convert->func(&esrc->ptr_leaf->entries[i].context,
&edst->ptr_leaf->entries[i].context,
- convert->args);
+ convert->args, GFP_KERNEL);
if (rc)
return rc;
(*pos)++;
diff --git a/security/selinux/ss/sidtab.h b/security/selinux/ss/sidtab.h
index 4eff0e49dcb2..9fce0d553fe2 100644
--- a/security/selinux/ss/sidtab.h
+++ b/security/selinux/ss/sidtab.h
@@ -65,7 +65,7 @@ struct sidtab_isid_entry {
};
struct sidtab_convert_params {
- int (*func)(struct context *oldc, struct context *newc, void *args);
+ int (*func)(struct context *oldc, struct context *newc, void *args, gfp_t gfp_flags);
void *args;
struct sidtab *target;
};
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index b6306d71c908..cadef2f6a75e 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -1393,6 +1393,74 @@ static int smack_inode_removexattr(struct user_namespace *mnt_userns,
}
/**
+ * smack_inode_set_acl - Smack check for setting posix acls
+ * @mnt_userns: the userns attached to the mnt this request came from
+ * @dentry: the object
+ * @acl_name: name of the posix acl
+ * @kacl: the posix acls
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_set_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name,
+ struct posix_acl *kacl)
+{
+ struct smk_audit_info ad;
+ int rc;
+
+ smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
+ smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
+
+ rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_WRITE, &ad);
+ rc = smk_bu_inode(d_backing_inode(dentry), MAY_WRITE, rc);
+ return rc;
+}
+
+/**
+ * smack_inode_get_acl - Smack check for getting posix acls
+ * @mnt_userns: the userns attached to the mnt this request came from
+ * @dentry: the object
+ * @acl_name: name of the posix acl
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_get_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name)
+{
+ struct smk_audit_info ad;
+ int rc;
+
+ smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
+ smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
+
+ rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_READ, &ad);
+ rc = smk_bu_inode(d_backing_inode(dentry), MAY_READ, rc);
+ return rc;
+}
+
+/**
+ * smack_inode_remove_acl - Smack check for getting posix acls
+ * @mnt_userns: the userns attached to the mnt this request came from
+ * @dentry: the object
+ * @acl_name: name of the posix acl
+ *
+ * Returns 0 if access is permitted, an error code otherwise
+ */
+static int smack_inode_remove_acl(struct user_namespace *mnt_userns,
+ struct dentry *dentry, const char *acl_name)
+{
+ struct smk_audit_info ad;
+ int rc;
+
+ smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
+ smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
+
+ rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_WRITE, &ad);
+ rc = smk_bu_inode(d_backing_inode(dentry), MAY_WRITE, rc);
+ return rc;
+}
+
+/**
* smack_inode_getsecurity - get smack xattrs
* @mnt_userns: active user namespace
* @inode: the object
@@ -4816,6 +4884,9 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(inode_post_setxattr, smack_inode_post_setxattr),
LSM_HOOK_INIT(inode_getxattr, smack_inode_getxattr),
LSM_HOOK_INIT(inode_removexattr, smack_inode_removexattr),
+ LSM_HOOK_INIT(inode_set_acl, smack_inode_set_acl),
+ LSM_HOOK_INIT(inode_get_acl, smack_inode_get_acl),
+ LSM_HOOK_INIT(inode_remove_acl, smack_inode_remove_acl),
LSM_HOOK_INIT(inode_getsecurity, smack_inode_getsecurity),
LSM_HOOK_INIT(inode_setsecurity, smack_inode_setsecurity),
LSM_HOOK_INIT(inode_listsecurity, smack_inode_listsecurity),