summaryrefslogtreecommitdiff
path: root/security
diff options
context:
space:
mode:
Diffstat (limited to 'security')
-rw-r--r--security/apparmor/.kunitconfig5
-rw-r--r--security/apparmor/af_unix.c2
-rw-r--r--security/apparmor/apparmorfs.c25
-rw-r--r--security/apparmor/audit.c2
-rw-r--r--security/apparmor/domain.c60
-rw-r--r--security/apparmor/file.c49
-rw-r--r--security/apparmor/include/audit.h2
-rw-r--r--security/apparmor/include/cred.h100
-rw-r--r--security/apparmor/include/lib.h37
-rw-r--r--security/apparmor/include/match.h12
-rw-r--r--security/apparmor/include/policy.h32
-rw-r--r--security/apparmor/label.c59
-rw-r--r--security/apparmor/lib.c33
-rw-r--r--security/apparmor/lsm.c68
-rw-r--r--security/apparmor/match.c24
-rw-r--r--security/apparmor/net.c6
-rw-r--r--security/apparmor/path.c13
-rw-r--r--security/apparmor/policy.c37
-rw-r--r--security/apparmor/policy_compat.c16
-rw-r--r--security/apparmor/policy_ns.c2
-rw-r--r--security/apparmor/policy_unpack.c348
-rw-r--r--security/apparmor/resource.c5
-rw-r--r--security/apparmor/task.c32
-rw-r--r--security/device_cgroup.c2
-rw-r--r--security/integrity/digsig.c2
-rw-r--r--security/integrity/evm/evm_main.c2
-rw-r--r--security/integrity/evm/evm_secfs.c2
-rw-r--r--security/integrity/ima/ima_api.c9
-rw-r--r--security/integrity/ima/ima_crypto.c4
-rw-r--r--security/integrity/ima/ima_modsig.c2
-rw-r--r--security/integrity/ima/ima_mok.c2
-rw-r--r--security/integrity/ima/ima_policy.c7
-rw-r--r--security/integrity/ima/ima_queue.c6
-rw-r--r--security/integrity/ima/ima_queue_keys.c2
-rw-r--r--security/integrity/ima/ima_template.c13
-rw-r--r--security/ipe/digest.c2
-rw-r--r--security/ipe/hooks.c2
-rw-r--r--security/ipe/policy.c2
-rw-r--r--security/ipe/policy_parser.c6
-rw-r--r--security/keys/key.c2
-rw-r--r--security/keys/keyctl.c4
-rw-r--r--security/keys/keyring.c2
-rw-r--r--security/keys/request_key_auth.c2
-rw-r--r--security/keys/trusted-keys/trusted_core.c2
-rw-r--r--security/keys/trusted-keys/trusted_pkwm.c4
-rw-r--r--security/keys/trusted-keys/trusted_tpm1.c7
-rw-r--r--security/landlock/domain.c2
-rw-r--r--security/landlock/object.c2
-rw-r--r--security/landlock/ruleset.c12
-rw-r--r--security/landlock/tsync.c2
-rw-r--r--security/loadpin/loadpin.c2
-rw-r--r--security/safesetid/securityfs.c6
-rw-r--r--security/selinux/avc.c2
-rw-r--r--security/selinux/hooks.c4
-rw-r--r--security/selinux/ibpkey.c2
-rw-r--r--security/selinux/netif.c2
-rw-r--r--security/selinux/netnode.c2
-rw-r--r--security/selinux/netport.c2
-rw-r--r--security/selinux/selinuxfs.c4
-rw-r--r--security/selinux/ss/conditional.c22
-rw-r--r--security/selinux/ss/hashtab.c6
-rw-r--r--security/selinux/ss/policydb.c69
-rw-r--r--security/selinux/ss/services.c14
-rw-r--r--security/selinux/ss/sidtab.c2
-rw-r--r--security/selinux/xfrm.c4
-rw-r--r--security/smack/smack_access.c2
-rw-r--r--security/smack/smack_lsm.c10
-rw-r--r--security/smack/smackfs.c8
-rw-r--r--security/tomoyo/audit.c2
-rw-r--r--security/tomoyo/common.c4
-rw-r--r--security/tomoyo/domain.c2
-rw-r--r--security/yama/yama_lsm.c4
72 files changed, 845 insertions, 405 deletions
diff --git a/security/apparmor/.kunitconfig b/security/apparmor/.kunitconfig
new file mode 100644
index 000000000000..aa842a0266e9
--- /dev/null
+++ b/security/apparmor/.kunitconfig
@@ -0,0 +1,5 @@
+CONFIG_KUNIT=y
+CONFIG_NET=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_APPARMOR=y
+CONFIG_SECURITY_APPARMOR_KUNIT_TEST=y
diff --git a/security/apparmor/af_unix.c b/security/apparmor/af_unix.c
index ac0f4be791ec..fdb4a9f212c3 100644
--- a/security/apparmor/af_unix.c
+++ b/security/apparmor/af_unix.c
@@ -416,7 +416,7 @@ static int profile_peer_perm(struct aa_profile *profile, u32 request,
unix_sk(sk),
peer_addr, peer_addrlen, &p, &ad->info);
- return fn_for_each_in_ns(peer_label, peerp,
+ return fn_for_each_in_scope(peer_label, peerp,
match_label(profile, rules, state, request,
peerp, p, ad));
}
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 907bd2667e28..2f84bd23edb6 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -570,7 +570,7 @@ static ssize_t ns_revision_read(struct file *file, char __user *buf,
static int ns_revision_open(struct inode *inode, struct file *file)
{
- struct aa_revision *rev = kzalloc(sizeof(*rev), GFP_KERNEL);
+ struct aa_revision *rev = kzalloc_obj(*rev);
if (!rev)
return -ENOMEM;
@@ -801,7 +801,7 @@ static ssize_t query_label(char *buf, size_t buf_len,
perms = allperms;
if (view_only) {
- label_for_each_in_ns(i, labels_ns(label), label, profile) {
+ label_for_each_in_scope(i, labels_ns(label), label, profile) {
profile_query_cb(profile, &perms, match_str, match_len);
}
} else {
@@ -1607,16 +1607,20 @@ static char *gen_symlink_name(int depth, const char *dirname, const char *fname)
{
char *buffer, *s;
int error;
- int size = depth * 6 + strlen(dirname) + strlen(fname) + 11;
+ const char *path = "../../";
+ size_t path_len = strlen(path);
+ int size;
+ /* Extra 11 bytes: "raw_data" (9) + two slashes "//" (2) */
+ size = depth * path_len + strlen(dirname) + strlen(fname) + 11;
s = buffer = kmalloc(size, GFP_KERNEL);
if (!buffer)
return ERR_PTR(-ENOMEM);
for (; depth > 0; depth--) {
- strcpy(s, "../../");
- s += 6;
- size -= 6;
+ memcpy(s, path, path_len);
+ s += path_len;
+ size -= path_len;
}
error = snprintf(s, size, "raw_data/%s/%s", dirname, fname);
@@ -1644,6 +1648,15 @@ static const char *rawdata_get_link_base(struct dentry *dentry,
label = aa_get_label_rcu(&proxy->label);
profile = labels_profile(label);
+
+ /* rawdata can be null when aa_g_export_binary is unset during
+ * runtime and a profile is replaced
+ */
+ if (!profile->rawdata) {
+ aa_put_label(label);
+ return ERR_PTR(-ENOENT);
+ }
+
depth = profile_depth(profile);
target = gen_symlink_name(depth, profile->rawdata->name, name);
aa_put_label(label);
diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
index ac89602aa2d9..4a60b6fda75f 100644
--- a/security/apparmor/audit.c
+++ b/security/apparmor/audit.c
@@ -230,7 +230,7 @@ int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule, gfp_t gfp
return -EINVAL;
}
- rule = kzalloc(sizeof(struct aa_audit_rule), gfp);
+ rule = kzalloc_obj(struct aa_audit_rule, gfp);
if (!rule)
return -ENOMEM;
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index 267da82afb14..f02bf770f638 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -115,7 +115,7 @@ static inline aa_state_t match_component(struct aa_profile *profile,
* @label: label to check access permissions for
* @stack: whether this is a stacking request
* @state: state to start match in
- * @subns: whether to do permission checks on components in a subns
+ * @inview: whether to match labels in view or only in scope
* @request: permissions to request
* @perms: perms struct to set
*
@@ -127,7 +127,7 @@ static inline aa_state_t match_component(struct aa_profile *profile,
*/
static int label_compound_match(struct aa_profile *profile,
struct aa_label *label, bool stack,
- aa_state_t state, bool subns, u32 request,
+ aa_state_t state, bool inview, u32 request,
struct aa_perms *perms)
{
struct aa_ruleset *rules = profile->label.rules[0];
@@ -135,9 +135,9 @@ static int label_compound_match(struct aa_profile *profile,
struct label_it i;
struct path_cond cond = { };
- /* find first subcomponent that is visible */
+ /* find first subcomponent that is in view and going to be interated with */
label_for_each(i, label, tp) {
- if (!aa_ns_visible(profile->ns, tp->ns, subns))
+ if (!aa_ns_visible(profile->ns, tp->ns, inview))
continue;
state = match_component(profile, tp, stack, state);
if (!state)
@@ -151,7 +151,7 @@ static int label_compound_match(struct aa_profile *profile,
next:
label_for_each_cont(i, label, tp) {
- if (!aa_ns_visible(profile->ns, tp->ns, subns))
+ if (!aa_ns_visible(profile->ns, tp->ns, inview))
continue;
state = aa_dfa_match(rules->file->dfa, state, "//&");
state = match_component(profile, tp, false, state);
@@ -177,7 +177,7 @@ fail:
* @label: label to check access permissions for
* @stack: whether this is a stacking request
* @start: state to start match in
- * @subns: whether to do permission checks on components in a subns
+ * @inview: whether to match labels in view or only in scope
* @request: permissions to request
* @perms: an initialized perms struct to add accumulation to
*
@@ -189,7 +189,7 @@ fail:
*/
static int label_components_match(struct aa_profile *profile,
struct aa_label *label, bool stack,
- aa_state_t start, bool subns, u32 request,
+ aa_state_t start, bool inview, u32 request,
struct aa_perms *perms)
{
struct aa_ruleset *rules = profile->label.rules[0];
@@ -201,7 +201,7 @@ static int label_components_match(struct aa_profile *profile,
/* find first subcomponent to test */
label_for_each(i, label, tp) {
- if (!aa_ns_visible(profile->ns, tp->ns, subns))
+ if (!aa_ns_visible(profile->ns, tp->ns, inview))
continue;
state = match_component(profile, tp, stack, start);
if (!state)
@@ -218,7 +218,7 @@ next:
aa_apply_modes_to_perms(profile, &tmp);
aa_perms_accum(perms, &tmp);
label_for_each_cont(i, label, tp) {
- if (!aa_ns_visible(profile->ns, tp->ns, subns))
+ if (!aa_ns_visible(profile->ns, tp->ns, inview))
continue;
state = match_component(profile, tp, stack, start);
if (!state)
@@ -245,26 +245,26 @@ fail:
* @label: label to match (NOT NULL)
* @stack: whether this is a stacking request
* @state: state to start in
- * @subns: whether to match subns components
+ * @inview: whether to match labels in view or only in scope
* @request: permission request
* @perms: Returns computed perms (NOT NULL)
*
* Returns: the state the match finished in, may be the none matching state
*/
static int label_match(struct aa_profile *profile, struct aa_label *label,
- bool stack, aa_state_t state, bool subns, u32 request,
+ bool stack, aa_state_t state, bool inview, u32 request,
struct aa_perms *perms)
{
int error;
*perms = nullperms;
- error = label_compound_match(profile, label, stack, state, subns,
+ error = label_compound_match(profile, label, stack, state, inview,
request, perms);
if (!error)
return error;
*perms = allperms;
- return label_components_match(profile, label, stack, state, subns,
+ return label_components_match(profile, label, stack, state, inview,
request, perms);
}
@@ -529,7 +529,7 @@ struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex,
/* TODO: move lookup parsing to unpack time so this is a straight
* index into the resultant label
*/
- for (next = rules->file->trans.table[index]; next;
+ for (next = rules->file->trans.table[index].strs; next;
next = next_name(xtype, next)) {
const char *lookup = (*next == '&') ? next + 1 : next;
*name = next;
@@ -880,14 +880,16 @@ static struct aa_label *handle_onexec(const struct cred *subj_cred,
AA_BUG(!bprm);
AA_BUG(!buffer);
- /* TODO: determine how much we want to loosen this */
- error = fn_for_each_in_ns(label, profile,
+ /* TODO: determine how much we want to loosen this
+ * only check profiles in scope for permission to change at exec
+ */
+ error = fn_for_each_in_scope(label, profile,
profile_onexec(subj_cred, profile, onexec, stack,
bprm, buffer, cond, unsafe));
if (error)
return ERR_PTR(error);
- new = fn_label_build_in_ns(label, profile, GFP_KERNEL,
+ new = fn_label_build_in_scope(label, profile, GFP_KERNEL,
stack ? aa_label_merge(&profile->label, onexec,
GFP_KERNEL)
: aa_get_newest_label(onexec),
@@ -897,7 +899,7 @@ static struct aa_label *handle_onexec(const struct cred *subj_cred,
return new;
/* TODO: get rid of GLOBAL_ROOT_UID */
- error = fn_for_each_in_ns(label, profile,
+ error = fn_for_each_in_scope(label, profile,
aa_audit_file(subj_cred, profile, &nullperms,
OP_CHANGE_ONEXEC,
AA_MAY_ONEXEC, bprm->filename, NULL,
@@ -1123,7 +1125,7 @@ static struct aa_label *change_hat(const struct cred *subj_cred,
/*find first matching hat */
for (i = 0; i < count && !hat; i++) {
name = hats[i];
- label_for_each_in_ns(it, labels_ns(label), label, profile) {
+ label_for_each_in_scope(it, labels_ns(label), label, profile) {
if (sibling && PROFILE_IS_HAT(profile)) {
root = aa_get_profile_rcu(&profile->parent);
} else if (!sibling && !PROFILE_IS_HAT(profile)) {
@@ -1159,7 +1161,7 @@ outer_continue:
* change_hat.
*/
name = NULL;
- label_for_each_in_ns(it, labels_ns(label), label, profile) {
+ label_for_each_in_scope(it, labels_ns(label), label, profile) {
if (!list_empty(&profile->base.profiles)) {
info = "hat not found";
error = -ENOENT;
@@ -1170,7 +1172,7 @@ outer_continue:
error = -ECHILD;
fail:
- label_for_each_in_ns(it, labels_ns(label), label, profile) {
+ label_for_each_in_scope(it, labels_ns(label), label, profile) {
/*
* no target as it has failed to be found or built
*
@@ -1188,7 +1190,7 @@ fail:
return ERR_PTR(error);
build:
- new = fn_label_build_in_ns(label, profile, GFP_KERNEL,
+ new = fn_label_build_in_scope(label, profile, GFP_KERNEL,
build_change_hat(subj_cred, profile, name,
sibling),
aa_get_label(&profile->label));
@@ -1251,7 +1253,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags)
bool empty = true;
rcu_read_lock();
- label_for_each_in_ns(i, labels_ns(label), label, profile) {
+ label_for_each_in_scope(i, labels_ns(label), label, profile) {
empty &= list_empty(&profile->base.profiles);
}
rcu_read_unlock();
@@ -1338,7 +1340,7 @@ kill:
perms.kill = AA_MAY_CHANGEHAT;
fail:
- fn_for_each_in_ns(label, profile,
+ fn_for_each_in_scope(label, profile,
aa_audit_file(subj_cred, profile, &perms, OP_CHANGE_HAT,
AA_MAY_CHANGEHAT, NULL, NULL, target,
GLOBAL_ROOT_UID, info, error));
@@ -1446,7 +1448,7 @@ int aa_change_profile(const char *fqname, int flags)
*/
stack = true;
perms.audit = request;
- (void) fn_for_each_in_ns(label, profile,
+ (void) fn_for_each_in_scope(label, profile,
aa_audit_file(subj_cred, profile, &perms, op,
request, auditname, NULL, target,
GLOBAL_ROOT_UID, stack_msg, 0));
@@ -1492,7 +1494,7 @@ int aa_change_profile(const char *fqname, int flags)
*
* if (!stack) {
*/
- error = fn_for_each_in_ns(label, profile,
+ error = fn_for_each_in_scope(label, profile,
change_profile_perms_wrapper(op, auditname,
subj_cred,
profile, target, stack,
@@ -1506,7 +1508,7 @@ int aa_change_profile(const char *fqname, int flags)
check:
/* check if tracing task is allowed to trace target domain */
error = may_change_ptraced_domain(subj_cred, target, &info);
- if (error && !fn_for_each_in_ns(label, profile,
+ if (error && !fn_for_each_in_scope(label, profile,
COMPLAIN_MODE(profile)))
goto audit;
@@ -1522,7 +1524,7 @@ check:
/* stacking is always a subset, so only check the nonstack case */
if (!stack) {
- new = fn_label_build_in_ns(label, profile, GFP_KERNEL,
+ new = fn_label_build_in_scope(label, profile, GFP_KERNEL,
aa_get_label(target),
aa_get_label(&profile->label));
/*
@@ -1565,7 +1567,7 @@ check:
}
audit:
- error = fn_for_each_in_ns(label, profile,
+ error = fn_for_each_in_scope(label, profile,
aa_audit_file(subj_cred,
profile, &perms, op, request, auditname,
NULL, new ? new : target,
diff --git a/security/apparmor/file.c b/security/apparmor/file.c
index c75820402878..694e157149e8 100644
--- a/security/apparmor/file.c
+++ b/security/apparmor/file.c
@@ -103,6 +103,7 @@ int aa_audit_file(const struct cred *subj_cred,
ad.subj_cred = subj_cred;
ad.request = request;
+ ad.tags = perms->tag;
ad.name = name;
ad.fs.target = target;
ad.peer = tlabel;
@@ -154,8 +155,12 @@ static int path_name(const char *op, const struct cred *subj_cred,
const char *info = NULL;
int error;
- error = aa_path_name(path, flags, buffer, name, &info,
- labels_profile(label)->disconnected);
+ /* don't reaudit files closed during inheritance */
+ if (unlikely(path->dentry == aa_null.dentry))
+ error = -EACCES;
+ else
+ error = aa_path_name(path, flags, buffer, name, &info,
+ labels_profile(label)->disconnected);
if (error) {
fn_for_each_confined(label, profile,
aa_audit_file(subj_cred,
@@ -567,8 +572,7 @@ static bool __file_is_delegated(struct aa_label *obj_label)
return unconfined(obj_label);
}
-static bool __unix_needs_revalidation(struct file *file, struct aa_label *label,
- u32 request)
+static bool __is_unix_file(struct file *file)
{
struct socket *sock = (struct socket *) file->private_data;
@@ -576,20 +580,31 @@ static bool __unix_needs_revalidation(struct file *file, struct aa_label *label,
if (!S_ISSOCK(file_inode(file)->i_mode))
return false;
- if (request & NET_PEER_MASK)
+ /* sock and sock->sk can be NULL for sockets being set up or torn down */
+ if (!sock || !sock->sk)
return false;
- if (sock->sk->sk_family == PF_UNIX) {
- struct aa_sk_ctx *ctx = aa_sock(sock->sk);
-
- if (rcu_access_pointer(ctx->peer) !=
- rcu_access_pointer(ctx->peer_lastupdate))
- return true;
- return !__aa_subj_label_is_cached(rcu_dereference(ctx->label),
- label);
- }
+ if (sock->sk->sk_family == PF_UNIX)
+ return true;
return false;
}
+static bool __unix_needs_revalidation(struct file *file, struct aa_label *label,
+ u32 request)
+{
+ struct socket *sock = (struct socket *) file->private_data;
+
+ AA_BUG(!__is_unix_file(file));
+ lockdep_assert_in_rcu_read_lock();
+
+ struct aa_sk_ctx *skctx = aa_sock(sock->sk);
+
+ if (rcu_access_pointer(skctx->peer) !=
+ rcu_access_pointer(skctx->peer_lastupdate))
+ return true;
+
+ return !__aa_subj_label_is_cached(rcu_dereference(skctx->label), label);
+}
+
/**
* aa_file_perm - do permission revalidation check & audit for @file
* @op: operation being checked
@@ -613,6 +628,10 @@ int aa_file_perm(const char *op, const struct cred *subj_cred,
AA_BUG(!label);
AA_BUG(!file);
+ /* don't reaudit files closed during inheritance */
+ if (unlikely(file->f_path.dentry == aa_null.dentry))
+ return -EACCES;
+
fctx = file_ctx(file);
rcu_read_lock();
@@ -628,7 +647,7 @@ int aa_file_perm(const char *op, const struct cred *subj_cred,
*/
denied = request & ~fctx->allow;
if (unconfined(label) || __file_is_delegated(flabel) ||
- __unix_needs_revalidation(file, label, request) ||
+ (!denied && __is_unix_file(file) && !__unix_needs_revalidation(file, label, request)) ||
(!denied && __aa_subj_label_is_cached(label, flabel))) {
rcu_read_unlock();
goto done;
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
index 1a71a94ea19c..aa00b34404f9 100644
--- a/security/apparmor/include/audit.h
+++ b/security/apparmor/include/audit.h
@@ -119,6 +119,8 @@ struct apparmor_audit_data {
const char *info;
u32 request;
u32 denied;
+ u32 tags;
+
union {
/* these entries require a custom callback fn */
struct {
diff --git a/security/apparmor/include/cred.h b/security/apparmor/include/cred.h
index b028e4c13b6f..2b6098149b15 100644
--- a/security/apparmor/include/cred.h
+++ b/security/apparmor/include/cred.h
@@ -37,22 +37,6 @@ static inline void set_cred_label(const struct cred *cred,
}
/**
- * aa_cred_raw_label - obtain cred's label
- * @cred: cred to obtain label from (NOT NULL)
- *
- * Returns: confining label
- *
- * does NOT increment reference count
- */
-static inline struct aa_label *aa_cred_raw_label(const struct cred *cred)
-{
- struct aa_label *label = cred_label(cred);
-
- AA_BUG(!label);
- return label;
-}
-
-/**
* aa_get_newest_cred_label - obtain the newest label on a cred
* @cred: cred to obtain label from (NOT NULL)
*
@@ -60,13 +44,13 @@ static inline struct aa_label *aa_cred_raw_label(const struct cred *cred)
*/
static inline struct aa_label *aa_get_newest_cred_label(const struct cred *cred)
{
- return aa_get_newest_label(aa_cred_raw_label(cred));
+ return aa_get_newest_label(cred_label(cred));
}
static inline struct aa_label *aa_get_newest_cred_label_condref(const struct cred *cred,
bool *needput)
{
- struct aa_label *l = aa_cred_raw_label(cred);
+ struct aa_label *l = cred_label(cred);
if (unlikely(label_is_stale(l))) {
*needput = true;
@@ -93,7 +77,7 @@ static inline void aa_put_label_condref(struct aa_label *l, bool needput)
*/
static inline struct aa_label *aa_current_raw_label(void)
{
- return aa_cred_raw_label(current_cred());
+ return cred_label(current_cred());
}
/**
@@ -115,17 +99,79 @@ static inline struct aa_label *aa_get_current_label(void)
}
/**
+ * __end_cred_crit_section - end crit section begun with __begin_...
+ * @label: label obtained from __begin_cred_crit_section
+ * @needput: output: bool set by __begin_cred_crit_section
+ *
+ * While the cred passed to __begin is guaranteed to not change
+ * and the cred and label could be passed here instead of needput
+ * using needput with a local var makes it easier for the compiler
+ * and processor to optimize and speculatively execute the comparison
+ * than chasing a pointer in the cred struct.
+ */
+static inline void __end_cred_crit_section(struct aa_label *label,
+ bool needput)
+{
+ if (unlikely(needput))
+ aa_put_label(label);
+}
+
+/**
+ * __begin_cred_crit_section - @cred's confining label
+ * @cred: current's cred to start a crit section on its label
+ * @needput: store whether the label needs to be put when ending crit section
+ *
+ * Returns: up to date confining label or the ns unconfined label (NOT NULL)
+ *
+ * safe to call inside locks
+ *
+ * The returned reference must be put with __end_cred_crit_section()
+ * This must NOT be used if the task cred could be updated within the
+ * critical section between
+ * __begin_cred_crit_section() .. __end_cred_crit_section()
+ *
+ * The crit section is an optimization to avoid having to get and put
+ * the newest version of the label. While the cred won't change and
+ * hence the label it contains won't change, the newest version of the
+ * label can. During the crit section the newest versions of the label
+ * will be used until the end of the crit section.
+ *
+ * If the label has not been updated at the start of the crit section
+ * no refcount is taken, the cred's refcount is enough to hold the
+ * label for the duration of the crit section.
+ *
+ * If the label has been updated then a refcount will be taken and the
+ * newest version of the label will be returned. While the cred label
+ * and the returned label could be compared at the end of the crit
+ * section, needput is used because it allows better optimization by
+ * the compiler and the processor's speculative execution.
+ */
+static inline struct aa_label *__begin_cred_crit_section(const struct cred *cred,
+ bool *needput)
+{
+ struct aa_label *label = cred_label(cred);
+
+ if (label_is_stale(label)) {
+ *needput = true;
+ return aa_get_newest_label(label);
+ }
+
+ *needput = false;
+ return label;
+}
+
+/**
* __end_current_label_crit_section - end crit section begun with __begin_...
* @label: label obtained from __begin_current_label_crit_section
* @needput: output: bool set by __begin_current_label_crit_section
*
- * Returns: label to use for this crit section
+ * wrapper around __end_cred_crit_section() to pair nicely with
+ * __begin_current_label_crit_section()
*/
static inline void __end_current_label_crit_section(struct aa_label *label,
bool needput)
{
- if (unlikely(needput))
- aa_put_label(label);
+ __end_cred_crit_section(label, needput);
}
/**
@@ -157,15 +203,7 @@ static inline void end_current_label_crit_section(struct aa_label *label)
*/
static inline struct aa_label *__begin_current_label_crit_section(bool *needput)
{
- struct aa_label *label = aa_current_raw_label();
-
- if (label_is_stale(label)) {
- *needput = true;
- return aa_get_newest_label(label);
- }
-
- *needput = false;
- return label;
+ return __begin_cred_crit_section(current_cred(), needput);
}
/**
diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h
index 444197075fd6..1c5d1f60f6a7 100644
--- a/security/apparmor/include/lib.h
+++ b/security/apparmor/include/lib.h
@@ -30,8 +30,10 @@ extern struct aa_dfa *stacksplitdfa;
#define DEBUG_DOMAIN 4
#define DEBUG_POLICY 8
#define DEBUG_INTERFACE 0x10
+#define DEBUG_UNPACK 0x20
+#define DEBUG_TAGS 0x40
-#define DEBUG_ALL 0x1f /* update if new DEBUG_X added */
+#define DEBUG_ALL 0x7f /* update if new DEBUG_X added */
#define DEBUG_PARSE_ERROR (-1)
#define DEBUG_ON (aa_g_debug != DEBUG_NONE)
@@ -45,9 +47,11 @@ extern struct aa_dfa *stacksplitdfa;
#define AA_DEBUG_LABEL(LAB, X, fmt, args...) \
do { \
if ((LAB)->flags & FLAG_DEBUG1) \
- AA_DEBUG(X, fmt, args); \
+ AA_DEBUG(X, fmt, ##args); \
} while (0)
+#define AA_DEBUG_PROFILE(PROF, X, fmt...) AA_DEBUG_LABEL(&(PROF)->label, X, ##fmt)
+
#define AA_WARN(X) WARN((X), "APPARMOR WARN %s: %s\n", __func__, #X)
#define AA_BUG(X, args...) \
@@ -76,6 +80,19 @@ int aa_print_debug_params(char *buffer);
/* Flag indicating whether initialization completed */
extern int apparmor_initialized;
+/* semantic split of scope and view */
+#define aa_in_scope(SUBJ, OBJ) \
+ aa_ns_visible(SUBJ, OBJ, false)
+
+#define aa_in_view(SUBJ, OBJ) \
+ aa_ns_visible(SUBJ, OBJ, true)
+
+#define label_for_each_in_scope(I, NS, L, P) \
+ label_for_each_in_ns(I, NS, L, P)
+
+#define fn_for_each_in_scope(L, P, FN) \
+ fn_for_each_in_ns(L, P, FN)
+
/* fn's in lib */
const char *skipn_spaces(const char *str, size_t n);
const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name,
@@ -119,13 +136,19 @@ static inline bool path_mediated_fs(struct dentry *dentry)
return !(dentry->d_sb->s_flags & SB_NOUSER);
}
+struct aa_str_table_ent {
+ int count;
+ int size;
+ char *strs;
+};
+
struct aa_str_table {
int size;
- char **table;
+ struct aa_str_table_ent *table;
};
-void aa_free_str_table(struct aa_str_table *table);
bool aa_resize_str_table(struct aa_str_table *t, int newsize, gfp_t gfp);
+void aa_destroy_str_table(struct aa_str_table *table);
struct counted_str {
struct kref count;
@@ -306,7 +329,7 @@ __done: \
})
-#define __fn_build_in_ns(NS, P, NS_FN, OTHER_FN) \
+#define __fn_build_in_scope(NS, P, NS_FN, OTHER_FN) \
({ \
struct aa_label *__new; \
if ((P)->ns != (NS)) \
@@ -316,10 +339,10 @@ __done: \
(__new); \
})
-#define fn_label_build_in_ns(L, P, GFP, NS_FN, OTHER_FN) \
+#define fn_label_build_in_scope(L, P, GFP, NS_FN, OTHER_FN) \
({ \
fn_label_build((L), (P), (GFP), \
- __fn_build_in_ns(labels_ns(L), (P), (NS_FN), (OTHER_FN))); \
+ __fn_build_in_scope(labels_ns(L), (P), (NS_FN), (OTHER_FN))); \
})
#endif /* __AA_LIB_H */
diff --git a/security/apparmor/include/match.h b/security/apparmor/include/match.h
index 1fbe82f5021b..0dde8eda3d1a 100644
--- a/security/apparmor/include/match.h
+++ b/security/apparmor/include/match.h
@@ -104,16 +104,18 @@ struct aa_dfa {
struct table_header *tables[YYTD_ID_TSIZE];
};
-#define byte_to_byte(X) (X)
-
#define UNPACK_ARRAY(TABLE, BLOB, LEN, TTYPE, BTYPE, NTOHX) \
do { \
typeof(LEN) __i; \
TTYPE *__t = (TTYPE *) TABLE; \
BTYPE *__b = (BTYPE *) BLOB; \
- for (__i = 0; __i < LEN; __i++) { \
- __t[__i] = NTOHX(__b[__i]); \
- } \
+ BUILD_BUG_ON(sizeof(TTYPE) != sizeof(BTYPE)); \
+ if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) \
+ memcpy(__t, __b, (LEN) * sizeof(BTYPE)); \
+ else /* copy & convert from big-endian */ \
+ for (__i = 0; __i < LEN; __i++) { \
+ __t[__i] = NTOHX(&__b[__i]); \
+ } \
} while (0)
static inline size_t table_size(size_t len, size_t el_size)
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
index 4c50875c9d13..5115ebae2661 100644
--- a/security/apparmor/include/policy.h
+++ b/security/apparmor/include/policy.h
@@ -79,11 +79,33 @@ enum profile_mode {
};
+struct aa_tags_header {
+ u32 mask; /* bit mask matching permissions */
+ u32 count; /* number of strings per entry */
+ u32 size; /* size of all strings covered by count */
+ u32 tags; /* index into string table */
+};
+
+struct aa_tags_struct {
+ struct {
+ u32 size; /* number of entries in tagsets */
+ u32 *table; /* indexes into headers & strs */
+ } sets;
+ struct {
+ u32 size; /* number of headers == num of strs */
+ struct aa_tags_header *table;
+ } hdrs;
+ struct aa_str_table strs;
+};
+
/* struct aa_policydb - match engine for a policy
- * count: refcount for the pdb
- * dfa: dfa pattern match
- * perms: table of permissions
- * strs: table of strings, index by x
+ * @count: refcount for the pdb
+ * @dfa: dfa pattern match
+ * @perms: table of permissions
+ * @size: number of entries in @perms
+ * @trans: table of strings, index by x
+ * @tags: table of tags that perms->tag indexes
+ * @start:_states to start in for each class
* start: set of start states for the different classes of data
*/
struct aa_policydb {
@@ -94,11 +116,13 @@ struct aa_policydb {
u32 size;
};
struct aa_str_table trans;
+ struct aa_tags_struct tags;
aa_state_t start[AA_CLASS_LAST + 1];
};
extern struct aa_policydb *nullpdb;
+void aa_destroy_tags(struct aa_tags_struct *tags);
struct aa_policydb *aa_alloc_pdb(gfp_t gfp);
void aa_pdb_free_kref(struct kref *kref);
diff --git a/security/apparmor/label.c b/security/apparmor/label.c
index 913678f199c3..e478283bc514 100644
--- a/security/apparmor/label.c
+++ b/security/apparmor/label.c
@@ -61,7 +61,7 @@ struct aa_proxy *aa_alloc_proxy(struct aa_label *label, gfp_t gfp)
{
struct aa_proxy *new;
- new = kzalloc(sizeof(struct aa_proxy), gfp);
+ new = kzalloc_obj(struct aa_proxy, gfp);
if (new) {
kref_init(&new->count);
rcu_assign_pointer(new->label, aa_get_label(label));
@@ -434,7 +434,7 @@ struct aa_label *aa_label_alloc(int size, struct aa_proxy *proxy, gfp_t gfp)
AA_BUG(size < 1);
/* + 1 for null terminator entry on vec */
- new = kzalloc(struct_size(new, vec, size + 1), gfp);
+ new = kzalloc_flex(*new, vec, size + 1, gfp);
AA_DEBUG(DEBUG_LABEL, "%s (%p)\n", __func__, new);
if (!new)
goto fail;
@@ -1274,11 +1274,11 @@ static inline aa_state_t match_component(struct aa_profile *profile,
* @rules: ruleset to search
* @label: label to check access permissions for
* @state: state to start match in
- * @subns: whether to do permission checks on components in a subns
+ * @inview: whether to match labels in view or only in scope
* @request: permissions to request
* @perms: perms struct to set
*
- * Returns: 0 on success else ERROR
+ * Returns: state match stopped at or DFA_NOMATCH if aborted early
*
* For the label A//&B//&C this does the perm match for A//&B//&C
* @perms should be preinitialized with allperms OR a previous permission
@@ -1287,7 +1287,7 @@ static inline aa_state_t match_component(struct aa_profile *profile,
static int label_compound_match(struct aa_profile *profile,
struct aa_ruleset *rules,
struct aa_label *label,
- aa_state_t state, bool subns, u32 request,
+ aa_state_t state, bool inview, u32 request,
struct aa_perms *perms)
{
struct aa_profile *tp;
@@ -1295,7 +1295,7 @@ static int label_compound_match(struct aa_profile *profile,
/* find first subcomponent that is visible */
label_for_each(i, label, tp) {
- if (!aa_ns_visible(profile->ns, tp->ns, subns))
+ if (!aa_ns_visible(profile->ns, tp->ns, inview))
continue;
state = match_component(profile, rules, tp, state);
if (!state)
@@ -1305,11 +1305,11 @@ static int label_compound_match(struct aa_profile *profile,
/* no component visible */
*perms = allperms;
- return 0;
+ return state;
next:
label_for_each_cont(i, label, tp) {
- if (!aa_ns_visible(profile->ns, tp->ns, subns))
+ if (!aa_ns_visible(profile->ns, tp->ns, inview))
continue;
state = aa_dfa_match(rules->policy->dfa, state, "//&");
state = match_component(profile, rules, tp, state);
@@ -1317,15 +1317,11 @@ next:
goto fail;
}
*perms = *aa_lookup_perms(rules->policy, state);
- aa_apply_modes_to_perms(profile, perms);
- if ((perms->allow & request) != request)
- return -EACCES;
-
- return 0;
+ return state;
fail:
*perms = nullperms;
- return state;
+ return DFA_NOMATCH;
}
/**
@@ -1334,11 +1330,11 @@ fail:
* @rules: ruleset to search
* @label: label to check access permissions for
* @start: state to start match in
- * @subns: whether to do permission checks on components in a subns
+ * @inview: whether to match labels in view or only in scope
* @request: permissions to request
* @perms: an initialized perms struct to add accumulation to
*
- * Returns: 0 on success else ERROR
+ * Returns: the state the match finished in, may be the none matching state
*
* For the label A//&B//&C this does the perm match for each of A and B and C
* @perms should be preinitialized with allperms OR a previous permission
@@ -1347,7 +1343,7 @@ fail:
static int label_components_match(struct aa_profile *profile,
struct aa_ruleset *rules,
struct aa_label *label, aa_state_t start,
- bool subns, u32 request,
+ bool inview, u32 request,
struct aa_perms *perms)
{
struct aa_profile *tp;
@@ -1357,7 +1353,7 @@ static int label_components_match(struct aa_profile *profile,
/* find first subcomponent to test */
label_for_each(i, label, tp) {
- if (!aa_ns_visible(profile->ns, tp->ns, subns))
+ if (!aa_ns_visible(profile->ns, tp->ns, inview))
continue;
state = match_component(profile, rules, tp, start);
if (!state)
@@ -1366,31 +1362,29 @@ static int label_components_match(struct aa_profile *profile,
}
/* no subcomponents visible - no change in perms */
- return 0;
+ return state;
next:
tmp = *aa_lookup_perms(rules->policy, state);
- aa_apply_modes_to_perms(profile, &tmp);
aa_perms_accum(perms, &tmp);
label_for_each_cont(i, label, tp) {
- if (!aa_ns_visible(profile->ns, tp->ns, subns))
+ if (!aa_ns_visible(profile->ns, tp->ns, inview))
continue;
state = match_component(profile, rules, tp, start);
if (!state)
goto fail;
tmp = *aa_lookup_perms(rules->policy, state);
- aa_apply_modes_to_perms(profile, &tmp);
aa_perms_accum(perms, &tmp);
}
if ((perms->allow & request) != request)
- return -EACCES;
+ return DFA_NOMATCH;
- return 0;
+ return state;
fail:
*perms = nullperms;
- return -EACCES;
+ return DFA_NOMATCH;
}
/**
@@ -1399,23 +1393,24 @@ fail:
* @rules: ruleset to search
* @label: label to match (NOT NULL)
* @state: state to start in
- * @subns: whether to match subns components
+ * @inview: whether to match labels in view or only in scope
* @request: permission request
* @perms: Returns computed perms (NOT NULL)
*
* Returns: the state the match finished in, may be the none matching state
*/
int aa_label_match(struct aa_profile *profile, struct aa_ruleset *rules,
- struct aa_label *label, aa_state_t state, bool subns,
+ struct aa_label *label, aa_state_t state, bool inview,
u32 request, struct aa_perms *perms)
{
- int error = label_compound_match(profile, rules, label, state, subns,
- request, perms);
- if (!error)
- return error;
+ aa_state_t tmp = label_compound_match(profile, rules, label, state,
+ inview, request, perms);
+ if ((perms->allow & request) == request)
+ return tmp;
+ /* failed compound_match try component matches */
*perms = allperms;
- return label_components_match(profile, rules, label, state, subns,
+ return label_components_match(profile, rules, label, state, inview,
request, perms);
}
diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c
index 82dbb97ad406..e41ff57798b2 100644
--- a/security/apparmor/lib.c
+++ b/security/apparmor/lib.c
@@ -44,6 +44,8 @@ static struct val_table_ent debug_values_table[] = {
{ "domain", DEBUG_DOMAIN },
{ "policy", DEBUG_POLICY },
{ "interface", DEBUG_INTERFACE },
+ { "unpack", DEBUG_UNPACK },
+ { "tags", DEBUG_TAGS },
{ NULL, 0 }
};
@@ -118,18 +120,18 @@ int aa_print_debug_params(char *buffer)
bool aa_resize_str_table(struct aa_str_table *t, int newsize, gfp_t gfp)
{
- char **n;
+ struct aa_str_table_ent *n;
int i;
if (t->size == newsize)
return true;
- n = kcalloc(newsize, sizeof(*n), gfp);
+ n = kzalloc_objs(*n, newsize, gfp);
if (!n)
return false;
for (i = 0; i < min(t->size, newsize); i++)
n[i] = t->table[i];
for (; i < t->size; i++)
- kfree_sensitive(t->table[i]);
+ kfree_sensitive(t->table[i].strs);
if (newsize > t->size)
memset(&n[t->size], 0, (newsize-t->size)*sizeof(*n));
kfree_sensitive(t->table);
@@ -140,10 +142,10 @@ bool aa_resize_str_table(struct aa_str_table *t, int newsize, gfp_t gfp)
}
/**
- * aa_free_str_table - free entries str table
+ * aa_destroy_str_table - free entries str table
* @t: the string table to free (MAYBE NULL)
*/
-void aa_free_str_table(struct aa_str_table *t)
+void aa_destroy_str_table(struct aa_str_table *t)
{
int i;
@@ -152,7 +154,7 @@ void aa_free_str_table(struct aa_str_table *t)
return;
for (i = 0; i < t->size; i++)
- kfree_sensitive(t->table[i]);
+ kfree_sensitive(t->table[i].strs);
kfree_sensitive(t->table);
t->table = NULL;
t->size = 0;
@@ -233,7 +235,7 @@ __counted char *aa_str_alloc(int size, gfp_t gfp)
{
struct counted_str *str;
- str = kmalloc(struct_size(str, name, size), gfp);
+ str = kmalloc_flex(*str, name, size, gfp);
if (!str)
return NULL;
@@ -478,19 +480,17 @@ bool aa_policy_init(struct aa_policy *policy, const char *prefix,
const char *name, gfp_t gfp)
{
char *hname;
+ size_t hname_sz;
+ hname_sz = (prefix ? strlen(prefix) + 2 : 0) + strlen(name) + 1;
/* freed by policy_free */
- if (prefix) {
- hname = aa_str_alloc(strlen(prefix) + strlen(name) + 3, gfp);
- if (hname)
- sprintf(hname, "%s//%s", prefix, name);
- } else {
- hname = aa_str_alloc(strlen(name) + 1, gfp);
- if (hname)
- strcpy(hname, name);
- }
+ hname = aa_str_alloc(hname_sz, gfp);
if (!hname)
return false;
+ if (prefix)
+ scnprintf(hname, hname_sz, "%s//%s", prefix, name);
+ else
+ strscpy(hname, name, hname_sz);
policy->hname = hname;
/* base.name is a substring of fqname */
policy->name = basename(policy->hname);
@@ -512,3 +512,4 @@ void aa_policy_destroy(struct aa_policy *policy)
/* don't free name as its a subset of hname */
aa_put_str(policy->hname);
}
+
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index a87cd60ed206..c1d42fc72fdb 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -520,33 +520,26 @@ static void apparmor_file_free_security(struct file *file)
aa_put_label(rcu_access_pointer(ctx->label));
}
-static int common_file_perm(const char *op, struct file *file, u32 mask,
- bool in_atomic)
+static int common_file_perm(const char *op, struct file *file, u32 mask)
{
struct aa_label *label;
int error = 0;
- bool needput;
-
- /* don't reaudit files closed during inheritance */
- if (unlikely(file->f_path.dentry == aa_null.dentry))
- return -EACCES;
- label = __begin_current_label_crit_section(&needput);
- error = aa_file_perm(op, current_cred(), label, file, mask, in_atomic);
- __end_current_label_crit_section(label, needput);
+ label = begin_current_label_crit_section();
+ error = aa_file_perm(op, current_cred(), label, file, mask, false);
+ end_current_label_crit_section(label);
return error;
}
static int apparmor_file_receive(struct file *file)
{
- return common_file_perm(OP_FRECEIVE, file, aa_map_file_to_perms(file),
- false);
+ return common_file_perm(OP_FRECEIVE, file, aa_map_file_to_perms(file));
}
static int apparmor_file_permission(struct file *file, int mask)
{
- return common_file_perm(OP_FPERM, file, mask, false);
+ return common_file_perm(OP_FPERM, file, mask);
}
static int apparmor_file_lock(struct file *file, unsigned int cmd)
@@ -556,11 +549,11 @@ static int apparmor_file_lock(struct file *file, unsigned int cmd)
if (cmd == F_WRLCK)
mask |= MAY_WRITE;
- return common_file_perm(OP_FLOCK, file, mask, false);
+ return common_file_perm(OP_FLOCK, file, mask);
}
static int common_mmap(const char *op, struct file *file, unsigned long prot,
- unsigned long flags, bool in_atomic)
+ unsigned long flags)
{
int mask = 0;
@@ -578,21 +571,20 @@ static int common_mmap(const char *op, struct file *file, unsigned long prot,
if (prot & PROT_EXEC)
mask |= AA_EXEC_MMAP;
- return common_file_perm(op, file, mask, in_atomic);
+ return common_file_perm(op, file, mask);
}
static int apparmor_mmap_file(struct file *file, unsigned long reqprot,
unsigned long prot, unsigned long flags)
{
- return common_mmap(OP_FMMAP, file, prot, flags, GFP_ATOMIC);
+ return common_mmap(OP_FMMAP, file, prot, flags);
}
static int apparmor_file_mprotect(struct vm_area_struct *vma,
unsigned long reqprot, unsigned long prot)
{
return common_mmap(OP_FMPROT, vma->vm_file, prot,
- !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0,
- false);
+ !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
}
#ifdef CONFIG_IO_URING
@@ -2133,6 +2125,23 @@ static int param_set_mode(const char *val, const struct kernel_param *kp)
return 0;
}
+/* arbitrary cap on how long to hold buffer because contention was
+ * encountered before trying to put it back into the global pool
+ */
+#define MAX_HOLD_COUNT 64
+
+/* the hold count is a heuristic for lock contention, and can be
+ * incremented async to actual buffer alloc/free. Because buffers
+ * may be put back onto a percpu cache different than the ->hold was
+ * added to the counts can be out of sync. Guard against underflow
+ * and overflow
+ */
+static void cache_hold_inc(unsigned int *hold)
+{
+ if (*hold > MAX_HOLD_COUNT)
+ (*hold)++;
+}
+
char *aa_get_buffer(bool in_atomic)
{
union aa_buffer *aa_buf;
@@ -2145,21 +2154,26 @@ char *aa_get_buffer(bool in_atomic)
if (!list_empty(&cache->head)) {
aa_buf = list_first_entry(&cache->head, union aa_buffer, list);
list_del(&aa_buf->list);
- cache->hold--;
+ if (cache->hold)
+ cache->hold--;
cache->count--;
put_cpu_ptr(&aa_local_buffers);
return &aa_buf->buffer[0];
}
+ /* exit percpu as spinlocks may sleep on realtime kernels */
put_cpu_ptr(&aa_local_buffers);
if (!spin_trylock(&aa_buffers_lock)) {
+ /* had contention on lock so increase hold count. Doesn't
+ * really matter if recorded before or after the spin lock
+ * as there is no way to guarantee the buffer will be put
+ * back on the same percpu cache. Instead rely on holds
+ * roughly averaging out over time.
+ */
cache = get_cpu_ptr(&aa_local_buffers);
- cache->hold += 1;
+ cache_hold_inc(&cache->hold);
put_cpu_ptr(&aa_local_buffers);
spin_lock(&aa_buffers_lock);
- } else {
- cache = get_cpu_ptr(&aa_local_buffers);
- put_cpu_ptr(&aa_local_buffers);
}
retry:
if (buffer_count > reserve_count ||
@@ -2214,13 +2228,11 @@ void aa_put_buffer(char *buf)
list_add(&aa_buf->list, &aa_global_buffers);
buffer_count++;
spin_unlock(&aa_buffers_lock);
- cache = get_cpu_ptr(&aa_local_buffers);
- put_cpu_ptr(&aa_local_buffers);
return;
}
/* contention on global list, fallback to percpu */
cache = get_cpu_ptr(&aa_local_buffers);
- cache->hold += 1;
+ cache_hold_inc(&cache->hold);
}
/* cache in percpu list */
@@ -2456,7 +2468,7 @@ static int __init aa_setup_dfa_engine(void)
goto fail;
}
nullpdb->dfa = aa_get_dfa(nulldfa);
- nullpdb->perms = kcalloc(2, sizeof(struct aa_perms), GFP_KERNEL);
+ nullpdb->perms = kzalloc_objs(struct aa_perms, 2);
if (!nullpdb->perms)
goto fail;
nullpdb->size = 2;
diff --git a/security/apparmor/match.c b/security/apparmor/match.c
index c5a91600842a..8fa0a1494acd 100644
--- a/security/apparmor/match.c
+++ b/security/apparmor/match.c
@@ -15,6 +15,7 @@
#include <linux/vmalloc.h>
#include <linux/err.h>
#include <linux/kref.h>
+#include <linux/unaligned.h>
#include "include/lib.h"
#include "include/match.h"
@@ -42,11 +43,11 @@ static struct table_header *unpack_table(char *blob, size_t bsize)
/* loaded td_id's start at 1, subtract 1 now to avoid doing
* it every time we use td_id as an index
*/
- th.td_id = be16_to_cpu(*(__be16 *) (blob)) - 1;
+ th.td_id = get_unaligned_be16(blob) - 1;
if (th.td_id > YYTD_ID_MAX)
goto out;
- th.td_flags = be16_to_cpu(*(__be16 *) (blob + 2));
- th.td_lolen = be32_to_cpu(*(__be32 *) (blob + 8));
+ th.td_flags = get_unaligned_be16(blob + 2);
+ th.td_lolen = get_unaligned_be32(blob + 8);
blob += sizeof(struct table_header);
if (!(th.td_flags == YYTD_DATA16 || th.td_flags == YYTD_DATA32 ||
@@ -66,14 +67,13 @@ static struct table_header *unpack_table(char *blob, size_t bsize)
table->td_flags = th.td_flags;
table->td_lolen = th.td_lolen;
if (th.td_flags == YYTD_DATA8)
- UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
- u8, u8, byte_to_byte);
+ memcpy(table->td_data, blob, th.td_lolen);
else if (th.td_flags == YYTD_DATA16)
UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
- u16, __be16, be16_to_cpu);
+ u16, __be16, get_unaligned_be16);
else if (th.td_flags == YYTD_DATA32)
UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
- u32, __be32, be32_to_cpu);
+ u32, __be32, get_unaligned_be32);
else
goto fail;
/* if table was vmalloced make sure the page tables are synced
@@ -301,7 +301,7 @@ struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags)
int error = -ENOMEM;
char *data = blob;
struct table_header *table = NULL;
- struct aa_dfa *dfa = kzalloc(sizeof(struct aa_dfa), GFP_KERNEL);
+ struct aa_dfa *dfa = kzalloc_obj(struct aa_dfa);
if (!dfa)
goto fail;
@@ -313,14 +313,14 @@ struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags)
if (size < sizeof(struct table_set_header))
goto fail;
- if (ntohl(*(__be32 *) data) != YYTH_MAGIC)
+ if (get_unaligned_be32(data) != YYTH_MAGIC)
goto fail;
- hsize = ntohl(*(__be32 *) (data + 4));
+ hsize = get_unaligned_be32(data + 4);
if (size < hsize)
goto fail;
- dfa->flags = ntohs(*(__be16 *) (data + 12));
+ dfa->flags = get_unaligned_be16(data + 12);
if (dfa->flags & ~(YYTH_FLAGS))
goto fail;
@@ -329,7 +329,7 @@ struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags)
* if (dfa->flags & YYTH_FLAGS_OOB_TRANS) {
* if (hsize < 16 + 4)
* goto fail;
- * dfa->max_oob = ntol(*(__be32 *) (data + 16));
+ * dfa->max_oob = get_unaligned_be32(data + 16);
* if (dfa->max <= MAX_OOB_SUPPORTED) {
* pr_err("AppArmor DFA OOB greater than supported\n");
* goto fail;
diff --git a/security/apparmor/net.c b/security/apparmor/net.c
index 45cf25605c34..44c04102062f 100644
--- a/security/apparmor/net.c
+++ b/security/apparmor/net.c
@@ -326,8 +326,10 @@ int aa_sock_file_perm(const struct cred *subj_cred, struct aa_label *label,
struct socket *sock = (struct socket *) file->private_data;
AA_BUG(!label);
- AA_BUG(!sock);
- AA_BUG(!sock->sk);
+
+ /* sock && sock->sk can be NULL for sockets being set up or torn down */
+ if (!sock || !sock->sk)
+ return 0;
if (sock->sk->sk_family == PF_UNIX)
return aa_unix_file_perm(subj_cred, label, op, request, file);
diff --git a/security/apparmor/path.c b/security/apparmor/path.c
index d6c74c357ffd..65a0ca5cc1bd 100644
--- a/security/apparmor/path.c
+++ b/security/apparmor/path.c
@@ -164,12 +164,15 @@ static int d_namespace_path(const struct path *path, char *buf, char **name,
}
out:
- /*
- * Append "/" to the pathname. The root directory is a special
- * case; it already ends in slash.
+ /* Append "/" to directory paths, except for root "/" which
+ * already ends in a slash.
*/
- if (!error && isdir && ((*name)[1] != '\0' || (*name)[0] != '/'))
- strcpy(&buf[aa_g_path_max - 2], "/");
+ if (!error && isdir) {
+ bool is_root = (*name)[0] == '/' && (*name)[1] == '\0';
+
+ if (!is_root)
+ buf[aa_g_path_max - 2] = '/';
+ }
return error;
}
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index 50d5345ff5cb..9108d74c6b46 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -98,13 +98,21 @@ const char *const aa_profile_mode_names[] = {
"user",
};
+void aa_destroy_tags(struct aa_tags_struct *tags)
+{
+ kfree_sensitive(tags->hdrs.table);
+ kfree_sensitive(tags->sets.table);
+ aa_destroy_str_table(&tags->strs);
+ memset(tags, 0, sizeof(*tags));
+}
static void aa_free_pdb(struct aa_policydb *pdb)
{
if (pdb) {
aa_put_dfa(pdb->dfa);
kvfree(pdb->perms);
- aa_free_str_table(&pdb->trans);
+ aa_destroy_str_table(&pdb->trans);
+ aa_destroy_tags(&pdb->tags);
kfree(pdb);
}
}
@@ -123,7 +131,7 @@ void aa_pdb_free_kref(struct kref *kref)
struct aa_policydb *aa_alloc_pdb(gfp_t gfp)
{
- struct aa_policydb *pdb = kzalloc(sizeof(struct aa_policydb), gfp);
+ struct aa_policydb *pdb = kzalloc_obj(struct aa_policydb, gfp);
if (!pdb)
return NULL;
@@ -224,6 +232,9 @@ static void aa_free_data(void *ptr, void *arg)
{
struct aa_data *data = ptr;
+ if (!ptr)
+ return;
+
kvfree_sensitive(data->data, data->size);
kfree_sensitive(data->key);
kfree_sensitive(data);
@@ -233,6 +244,9 @@ static void free_attachment(struct aa_attachment *attach)
{
int i;
+ if (!attach)
+ return;
+
for (i = 0; i < attach->xattr_count; i++)
kfree_sensitive(attach->xattrs[i]);
kfree_sensitive(attach->xattrs);
@@ -261,7 +275,7 @@ struct aa_ruleset *aa_alloc_ruleset(gfp_t gfp)
{
struct aa_ruleset *rules;
- rules = kzalloc(sizeof(*rules), gfp);
+ rules = kzalloc_obj(*rules, gfp);
return rules;
}
@@ -335,7 +349,7 @@ struct aa_profile *aa_alloc_profile(const char *hname, struct aa_proxy *proxy,
* this adds space for a single ruleset in the rules section of the
* label
*/
- profile = kzalloc(struct_size(profile, label.rules, 1), gfp);
+ profile = kzalloc_flex(*profile, label.rules, 1, gfp);
if (!profile)
return NULL;
@@ -697,24 +711,27 @@ struct aa_profile *aa_new_learning_profile(struct aa_profile *parent, bool hat,
struct aa_profile *p, *profile;
const char *bname;
char *name = NULL;
+ size_t name_sz;
AA_BUG(!parent);
if (base) {
- name = kmalloc(strlen(parent->base.hname) + 8 + strlen(base),
- gfp);
+ name_sz = strlen(parent->base.hname) + 8 + strlen(base);
+ name = kmalloc(name_sz, gfp);
if (name) {
- sprintf(name, "%s//null-%s", parent->base.hname, base);
+ snprintf(name, name_sz, "%s//null-%s",
+ parent->base.hname, base);
goto name;
}
/* fall through to try shorter uniq */
}
- name = kmalloc(strlen(parent->base.hname) + 2 + 7 + 8, gfp);
+ name_sz = strlen(parent->base.hname) + 2 + 7 + 8;
+ name = kmalloc(name_sz, gfp);
if (!name)
return NULL;
- sprintf(name, "%s//null-%x", parent->base.hname,
- atomic_inc_return(&parent->ns->uniq_null));
+ snprintf(name, name_sz, "%s//null-%x", parent->base.hname,
+ atomic_inc_return(&parent->ns->uniq_null));
name:
/* lookup to see if this is a dup creation */
diff --git a/security/apparmor/policy_compat.c b/security/apparmor/policy_compat.c
index cfc2207e5a12..5fc16d56fbf4 100644
--- a/security/apparmor/policy_compat.c
+++ b/security/apparmor/policy_compat.c
@@ -158,7 +158,7 @@ static struct aa_perms *compute_fperms(struct aa_dfa *dfa,
state_count = dfa->tables[YYTD_ID_BASE]->td_lolen;
/* DFAs are restricted from having a state_count of less than 2 */
- table = kvcalloc(state_count * 2, sizeof(struct aa_perms), GFP_KERNEL);
+ table = kvzalloc_objs(struct aa_perms, state_count * 2);
if (!table)
return NULL;
*size = state_count * 2;
@@ -182,7 +182,7 @@ static struct aa_perms *compute_xmatch_perms(struct aa_dfa *xmatch,
state_count = xmatch->tables[YYTD_ID_BASE]->td_lolen;
/* DFAs are restricted from having a state_count of less than 2 */
- perms = kvcalloc(state_count, sizeof(struct aa_perms), GFP_KERNEL);
+ perms = kvzalloc_objs(struct aa_perms, state_count);
if (!perms)
return NULL;
*size = state_count;
@@ -257,15 +257,21 @@ static struct aa_perms *compute_perms(struct aa_dfa *dfa, u32 version,
state_count = dfa->tables[YYTD_ID_BASE]->td_lolen;
/* DFAs are restricted from having a state_count of less than 2 */
- table = kvcalloc(state_count, sizeof(struct aa_perms), GFP_KERNEL);
+ table = kvzalloc_objs(struct aa_perms, state_count);
if (!table)
return NULL;
*size = state_count;
/* zero init so skip the trap state (state == 0) */
- for (state = 1; state < state_count; state++)
+ for (state = 1; state < state_count; state++) {
table[state] = compute_perms_entry(dfa, state, version);
-
+ AA_DEBUG(DEBUG_UNPACK,
+ "[%d]: (0x%x/0x%x/0x%x//0x%x/0x%x//0x%x), converted from accept1: 0x%x, accept2: 0x%x",
+ state, table[state].allow, table[state].deny,
+ table[state].prompt, table[state].audit,
+ table[state].quiet, table[state].xindex,
+ ACCEPT_TABLE(dfa)[state], ACCEPT_TABLE2(dfa)[state]);
+ }
return table;
}
diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c
index 64783ca3b0f2..01b653a3609b 100644
--- a/security/apparmor/policy_ns.c
+++ b/security/apparmor/policy_ns.c
@@ -106,7 +106,7 @@ static struct aa_ns *alloc_ns(const char *prefix, const char *name)
{
struct aa_ns *ns;
- ns = kzalloc(sizeof(*ns), GFP_KERNEL);
+ ns = kzalloc_obj(*ns);
AA_DEBUG(DEBUG_POLICY, "%s(%p)\n", __func__, ns);
if (!ns)
return NULL;
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index 7523971e37d9..1769417a9962 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -145,7 +145,7 @@ struct aa_loaddata *aa_loaddata_alloc(size_t size)
{
struct aa_loaddata *d;
- d = kzalloc(sizeof(*d), GFP_KERNEL);
+ d = kzalloc_obj(*d);
if (d == NULL)
return ERR_PTR(-ENOMEM);
d->data = kvzalloc(size, GFP_KERNEL);
@@ -450,20 +450,73 @@ static struct aa_dfa *unpack_dfa(struct aa_ext *e, int flags)
return dfa;
}
+static int process_strs_entry(char *str, int size, bool multi)
+{
+ int c = 1;
+
+ if (size <= 0)
+ return -1;
+ if (multi) {
+ if (size < 2)
+ return -2;
+ /* multi ends with double \0 */
+ if (str[size - 2])
+ return -3;
+ }
+
+ char *save = str;
+ char *pos = str;
+ char *end = multi ? str + size - 2 : str + size - 1;
+ /* count # of internal \0 */
+ while (str < end) {
+ if (str == pos) {
+ /* starts with ... */
+ if (!*str) {
+ AA_DEBUG(DEBUG_UNPACK,
+ "starting with null save=%lu size %d c=%d",
+ (unsigned long)(str - save), size, c);
+ return -4;
+ }
+ if (isspace(*str))
+ return -5;
+ if (*str == ':') {
+ /* :ns_str\0str\0
+ * first character after : must be valid
+ */
+ if (!str[1])
+ return -6;
+ }
+ } else if (!*str) {
+ if (*pos == ':')
+ *str = ':';
+ else
+ c++;
+ pos = str + 1;
+ }
+ str++;
+ } /* while */
+
+ return c;
+}
+
/**
- * unpack_trans_table - unpack a profile transition table
+ * unpack_strs_table - unpack a profile transition table
* @e: serialized data extent information (NOT NULL)
+ * @name: name of table (MAY BE NULL)
+ * @multi: allow multiple strings on a single entry
* @strs: str table to unpack to (NOT NULL)
*
- * Returns: true if table successfully unpacked or not present
+ * Returns: 0 if table successfully unpacked or not present, else error
*/
-static bool unpack_trans_table(struct aa_ext *e, struct aa_str_table *strs)
+static int unpack_strs_table(struct aa_ext *e, const char *name, bool multi,
+ struct aa_str_table *strs)
{
void *saved_pos = e->pos;
- char **table = NULL;
+ struct aa_str_table_ent *table = NULL;
+ int error = -EPROTO;
/* exec table is optional */
- if (aa_unpack_nameX(e, AA_STRUCT, "xtable")) {
+ if (aa_unpack_nameX(e, AA_STRUCT, name)) {
u16 size;
int i;
@@ -475,61 +528,46 @@ static bool unpack_trans_table(struct aa_ext *e, struct aa_str_table *strs)
* for size check here
*/
goto fail;
- table = kcalloc(size, sizeof(char *), GFP_KERNEL);
- if (!table)
+ table = kzalloc_objs(struct aa_str_table_ent, size);
+ if (!table) {
+ error = -ENOMEM;
goto fail;
-
+ }
strs->table = table;
strs->size = size;
for (i = 0; i < size; i++) {
char *str;
- int c, j, pos, size2 = aa_unpack_strdup(e, &str, NULL);
+ int c, size2 = aa_unpack_strdup(e, &str, NULL);
/* aa_unpack_strdup verifies that the last character is
* null termination byte.
*/
- if (!size2)
- goto fail;
- table[i] = str;
- /* verify that name doesn't start with space */
- if (isspace(*str))
+ c = process_strs_entry(str, size2, multi);
+ if (c <= 0) {
+ AA_DEBUG(DEBUG_UNPACK, "process_strs %d i %d pos %ld",
+ c, i,
+ (unsigned long)(e->pos - saved_pos));
goto fail;
-
- /* count internal # of internal \0 */
- for (c = j = 0; j < size2 - 1; j++) {
- if (!str[j]) {
- pos = j;
- c++;
- }
}
- if (*str == ':') {
- /* first character after : must be valid */
- if (!str[1])
- goto fail;
- /* beginning with : requires an embedded \0,
- * verify that exactly 1 internal \0 exists
- * trailing \0 already verified by aa_unpack_strdup
- *
- * convert \0 back to : for label_parse
- */
- if (c == 1)
- str[pos] = ':';
- else if (c > 1)
- goto fail;
- } else if (c)
+ if (!multi && c > 1) {
+ AA_DEBUG(DEBUG_UNPACK, "!multi && c > 1");
/* fail - all other cases with embedded \0 */
goto fail;
+ }
+ table[i].strs = str;
+ table[i].count = c;
+ table[i].size = size2;
}
if (!aa_unpack_nameX(e, AA_ARRAYEND, NULL))
goto fail;
if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
goto fail;
}
- return true;
+ return 0;
fail:
- aa_free_str_table(strs);
+ aa_destroy_str_table(strs);
e->pos = saved_pos;
- return false;
+ return error;
}
static bool unpack_xattrs(struct aa_ext *e, struct aa_profile *profile)
@@ -573,8 +611,7 @@ static bool unpack_secmark(struct aa_ext *e, struct aa_ruleset *rules)
if (!aa_unpack_array(e, NULL, &size))
goto fail;
- rules->secmark = kcalloc(size, sizeof(struct aa_secmark),
- GFP_KERNEL);
+ rules->secmark = kzalloc_objs(struct aa_secmark, size);
if (!rules->secmark)
goto fail;
@@ -644,6 +681,204 @@ fail:
return false;
}
+
+static bool verify_tags(struct aa_tags_struct *tags, const char **info)
+{
+ if ((tags->hdrs.size && !tags->hdrs.table) ||
+ (!tags->hdrs.size && tags->hdrs.table)) {
+ *info = "failed verification tag.hdrs disagree";
+ return false;
+ }
+ if ((tags->sets.size && !tags->sets.table) ||
+ (!tags->sets.size && tags->sets.table)) {
+ *info = "failed verification tag.sets disagree";
+ return false;
+ }
+ if ((tags->strs.size && !tags->strs.table) ||
+ (!tags->strs.size && tags->strs.table)) {
+ *info = "failed verification tags->strs disagree";
+ return false;
+ }
+ /* no data present */
+ if (!tags->sets.size && !tags->hdrs.size && !tags->strs.size) {
+ return true;
+ } else if (!(tags->sets.size && tags->hdrs.size && tags->strs.size)) {
+ /* some data present but not all */
+ *info = "failed verification tags partial data present";
+ return false;
+ }
+
+ u32 i;
+
+ for (i = 0; i < tags->sets.size; i++) {
+ /* count followed by count indexes into hdrs */
+ u32 cnt = tags->sets.table[i];
+
+ if (i+cnt >= tags->sets.size) {
+ AA_DEBUG(DEBUG_UNPACK,
+ "tagset too large %d+%d > sets.table[%d]",
+ i, cnt, tags->sets.size);
+ *info = "failed verification tagset too large";
+ return false;
+ }
+ for (; cnt; cnt--) {
+ if (tags->sets.table[++i] >= tags->hdrs.size) {
+ AA_DEBUG(DEBUG_UNPACK,
+ "tagsets idx out of bounds cnt %d sets.table[%d] >= %d",
+ cnt, i-1, tags->hdrs.size);
+ *info = "failed verification tagsets idx out of bounds";
+ return false;
+ }
+ }
+ }
+ for (i = 0; i < tags->hdrs.size; i++) {
+ u32 idx = tags->hdrs.table[i].tags;
+
+ if (idx >= tags->strs.size) {
+ AA_DEBUG(DEBUG_UNPACK,
+ "tag.hdrs idx oob idx %d > tags->strs.size=%d",
+ idx, tags->strs.size);
+ *info = "failed verification tags.hdrs idx out of bounds";
+ return false;
+ }
+ if (tags->hdrs.table[i].count != tags->strs.table[idx].count) {
+ AA_DEBUG(DEBUG_UNPACK, "hdrs.table[%d].count=%d != tags->strs.table[%d]=%d",
+ i, tags->hdrs.table[i].count, idx, tags->strs.table[idx].count);
+ *info = "failed verification tagd.hdrs[idx].count";
+ return false;
+ }
+ if (tags->hdrs.table[i].size != tags->strs.table[idx].size) {
+ AA_DEBUG(DEBUG_UNPACK, "hdrs.table[%d].size=%d != strs.table[%d].size=%d",
+ i, tags->hdrs.table[i].size, idx, tags->strs.table[idx].size);
+ *info = "failed verification tagd.hdrs[idx].size";
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static int unpack_tagsets(struct aa_ext *e, struct aa_tags_struct *tags)
+{
+ u32 *sets;
+ u16 i, size;
+ int error = -EPROTO;
+ void *pos = e->pos;
+
+ if (!aa_unpack_array(e, "sets", &size))
+ goto fail_reset;
+ sets = kcalloc(size, sizeof(u32), GFP_KERNEL);
+ if (!sets) {
+ error = -ENOMEM;
+ goto fail_reset;
+ }
+ for (i = 0; i < size; i++) {
+ if (!aa_unpack_u32(e, &sets[i], NULL))
+ goto fail;
+ }
+ if (!aa_unpack_nameX(e, AA_ARRAYEND, NULL))
+ goto fail;
+
+ tags->sets.size = size;
+ tags->sets.table = sets;
+
+ return 0;
+
+fail:
+ kfree_sensitive(sets);
+fail_reset:
+ e->pos = pos;
+ return error;
+}
+
+static bool unpack_tag_header_ent(struct aa_ext *e, struct aa_tags_header *h)
+{
+ return aa_unpack_u32(e, &h->mask, NULL) &&
+ aa_unpack_u32(e, &h->count, NULL) &&
+ aa_unpack_u32(e, &h->size, NULL) &&
+ aa_unpack_u32(e, &h->tags, NULL);
+}
+
+static int unpack_tag_headers(struct aa_ext *e, struct aa_tags_struct *tags)
+{
+ struct aa_tags_header *hdrs;
+ u16 i, size;
+ int error = -EPROTO;
+ void *pos = e->pos;
+
+ if (!aa_unpack_array(e, "hdrs", &size))
+ goto fail_reset;
+ hdrs = kzalloc_objs(struct aa_tags_header, size);
+ if (!hdrs) {
+ error = -ENOMEM;
+ goto fail_reset;
+ }
+ for (i = 0; i < size; i++) {
+ if (!unpack_tag_header_ent(e, &hdrs[i]))
+ goto fail;
+ }
+ if (!aa_unpack_nameX(e, AA_ARRAYEND, NULL))
+ goto fail;
+
+ tags->hdrs.size = size;
+ tags->hdrs.table = hdrs;
+ AA_DEBUG(DEBUG_UNPACK, "headers %ld size %d", (long) hdrs, size);
+ return true;
+
+fail:
+ kfree_sensitive(hdrs);
+fail_reset:
+ e->pos = pos;
+ return error;
+}
+
+
+static int unpack_tags(struct aa_ext *e, struct aa_tags_struct *tags,
+ const char **info)
+{
+ int error = -EPROTO;
+ void *pos = e->pos;
+
+ AA_BUG(!tags);
+ /* policy tags are optional */
+ if (aa_unpack_nameX(e, AA_STRUCT, "tags")) {
+ u32 version;
+
+ if (!aa_unpack_u32(e, &version, "version") || version != 1) {
+ *info = "invalid tags version";
+ goto fail_reset;
+ }
+ error = unpack_strs_table(e, "strs", true, &tags->strs);
+ if (error) {
+ *info = "failed to unpack profile tag.strs";
+ goto fail;
+ }
+ error = unpack_tag_headers(e, tags);
+ if (error) {
+ *info = "failed to unpack profile tag.headers";
+ goto fail;
+ }
+ error = unpack_tagsets(e, tags);
+ if (error) {
+ *info = "failed to unpack profile tag.sets";
+ goto fail;
+ }
+ if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
+ goto fail;
+
+ if (!verify_tags(tags, info))
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ aa_destroy_tags(tags);
+fail_reset:
+ e->pos = pos;
+ return error;
+}
+
static bool unpack_perm(struct aa_ext *e, u32 version, struct aa_perms *perm)
{
u32 reserved;
@@ -686,9 +921,11 @@ static ssize_t unpack_perms_table(struct aa_ext *e, struct aa_perms **perms)
goto fail_reset;
if (!aa_unpack_array(e, NULL, &size))
goto fail_reset;
- *perms = kcalloc(size, sizeof(struct aa_perms), GFP_KERNEL);
- if (!*perms)
- goto fail_reset;
+ *perms = kzalloc_objs(struct aa_perms, size);
+ if (!*perms) {
+ e->pos = pos;
+ return -ENOMEM;
+ }
for (i = 0; i < size; i++) {
if (!unpack_perm(e, version, &(*perms)[i]))
goto fail;
@@ -723,6 +960,11 @@ static int unpack_pdb(struct aa_ext *e, struct aa_policydb **policy,
if (!pdb)
return -ENOMEM;
+ AA_DEBUG(DEBUG_UNPACK, "unpacking tags");
+ if (unpack_tags(e, &pdb->tags, info) < 0)
+ goto fail;
+ AA_DEBUG(DEBUG_UNPACK, "done unpacking tags");
+
size = unpack_perms_table(e, &pdb->perms);
if (size < 0) {
error = size;
@@ -795,13 +1037,14 @@ static int unpack_pdb(struct aa_ext *e, struct aa_policydb **policy,
* transition table may be present even when the dfa is
* not. For compatibility reasons unpack and discard.
*/
- if (!unpack_trans_table(e, &pdb->trans) && required_trans) {
+ error = unpack_strs_table(e, "xtable", false, &pdb->trans);
+ if (error && required_trans) {
*info = "failed to unpack profile transition table";
goto fail;
}
if (!pdb->dfa && pdb->trans.table)
- aa_free_str_table(&pdb->trans);
+ aa_destroy_str_table(&pdb->trans);
/* TODO:
* - move compat mapping here, requires dfa merging first
@@ -1058,6 +1301,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
goto fail;
} else if (rules->file->dfa) {
if (!rules->file->perms) {
+ AA_DEBUG(DEBUG_UNPACK, "compat mapping perms");
error = aa_compat_map_file(rules->file);
if (error) {
info = "failed to remap file permission table";
@@ -1075,7 +1319,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
error = -EPROTO;
if (aa_unpack_nameX(e, AA_STRUCT, "data")) {
info = "out of memory";
- profile->data = kzalloc(sizeof(*profile->data), GFP_KERNEL);
+ profile->data = kzalloc_obj(*profile->data);
if (!profile->data) {
error = -ENOMEM;
goto fail;
@@ -1093,7 +1337,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
}
while (aa_unpack_strdup(e, &key, NULL)) {
- data = kzalloc(sizeof(*data), GFP_KERNEL);
+ data = kzalloc_obj(*data);
if (!data) {
kfree_sensitive(key);
error = -ENOMEM;
@@ -1260,7 +1504,7 @@ static bool verify_perms(struct aa_policydb *pdb)
if (xmax < xidx)
xmax = xidx;
}
- if (pdb->perms[i].tag && pdb->perms[i].tag >= pdb->trans.size)
+ if (pdb->perms[i].tag && pdb->perms[i].tag >= pdb->tags.sets.size)
return false;
if (pdb->perms[i].label &&
pdb->perms[i].label >= pdb->trans.size)
@@ -1268,7 +1512,7 @@ static bool verify_perms(struct aa_policydb *pdb)
}
/* deal with incorrectly constructed string tables */
if (xmax == -1) {
- aa_free_str_table(&pdb->trans);
+ aa_destroy_str_table(&pdb->trans);
} else if (pdb->trans.size > xmax + 1) {
if (!aa_resize_str_table(&pdb->trans, xmax + 1, GFP_KERNEL))
return false;
@@ -1338,7 +1582,7 @@ void aa_load_ent_free(struct aa_load_ent *ent)
struct aa_load_ent *aa_load_ent_alloc(void)
{
- struct aa_load_ent *ent = kzalloc(sizeof(*ent), GFP_KERNEL);
+ struct aa_load_ent *ent = kzalloc_obj(*ent);
if (ent)
INIT_LIST_HEAD(&ent->list);
return ent;
diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c
index 8e80db3ae21c..64212b39ba4b 100644
--- a/security/apparmor/resource.c
+++ b/security/apparmor/resource.c
@@ -196,6 +196,11 @@ void __aa_transition_rlimits(struct aa_label *old_l, struct aa_label *new_l)
rules->rlimits.limits[j].rlim_max);
/* soft limit should not exceed hard limit */
rlim->rlim_cur = min(rlim->rlim_cur, rlim->rlim_max);
+ if (j == RLIMIT_CPU &&
+ rlim->rlim_cur != RLIM_INFINITY &&
+ IS_ENABLED(CONFIG_POSIX_TIMERS))
+ (void) update_rlimit_cpu(current->group_leader,
+ rlim->rlim_cur);
}
}
}
diff --git a/security/apparmor/task.c b/security/apparmor/task.c
index c9bc9cc69475..0db0e81b4600 100644
--- a/security/apparmor/task.c
+++ b/security/apparmor/task.c
@@ -15,6 +15,7 @@
#include <linux/gfp.h>
#include <linux/ptrace.h>
+#include "include/path.h"
#include "include/audit.h"
#include "include/cred.h"
#include "include/policy.h"
@@ -300,16 +301,47 @@ int aa_may_ptrace(const struct cred *tracer_cred, struct aa_label *tracer,
xrequest, &sa));
}
+static const char *get_current_exe_path(char *buffer, int buffer_size)
+{
+ struct file *exe_file;
+ struct path p;
+ const char *path_str;
+
+ exe_file = get_task_exe_file(current);
+ if (!exe_file)
+ return ERR_PTR(-ENOENT);
+ p = exe_file->f_path;
+ path_get(&p);
+
+ if (aa_path_name(&p, FLAG_VIEW_SUBNS, buffer, &path_str, NULL, NULL))
+ return ERR_PTR(-ENOMEM);
+
+ fput(exe_file);
+ path_put(&p);
+
+ return path_str;
+}
+
/* call back to audit ptrace fields */
static void audit_ns_cb(struct audit_buffer *ab, void *va)
{
struct apparmor_audit_data *ad = aad_of_va(va);
+ char *buffer;
+ const char *path;
if (ad->request & AA_USERNS_CREATE)
audit_log_format(ab, " requested=\"userns_create\"");
if (ad->denied & AA_USERNS_CREATE)
audit_log_format(ab, " denied=\"userns_create\"");
+
+ buffer = aa_get_buffer(false);
+ if (!buffer)
+ return; // OOM
+ path = get_current_exe_path(buffer, aa_g_path_max);
+ if (!IS_ERR(path))
+ audit_log_format(ab, " execpath=\"%s\"", path);
+ aa_put_buffer(buffer);
}
int aa_profile_ns_perm(struct aa_profile *profile,
diff --git a/security/device_cgroup.c b/security/device_cgroup.c
index 7fec575d32d6..cd166dee66b7 100644
--- a/security/device_cgroup.c
+++ b/security/device_cgroup.c
@@ -223,7 +223,7 @@ devcgroup_css_alloc(struct cgroup_subsys_state *parent_css)
{
struct dev_cgroup *dev_cgroup;
- dev_cgroup = kzalloc(sizeof(*dev_cgroup), GFP_KERNEL);
+ dev_cgroup = kzalloc_obj(*dev_cgroup);
if (!dev_cgroup)
return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(&dev_cgroup->exceptions);
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
index 45c3e5dda355..75c684cce370 100644
--- a/security/integrity/digsig.c
+++ b/security/integrity/digsig.c
@@ -141,7 +141,7 @@ int __init integrity_init_keyring(const unsigned int id)
if (!IS_ENABLED(CONFIG_INTEGRITY_TRUSTED_KEYRING))
return 0;
- restriction = kzalloc(sizeof(struct key_restriction), GFP_KERNEL);
+ restriction = kzalloc_obj(struct key_restriction);
if (!restriction)
return -ENOMEM;
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 73d500a375cb..41b053c900f2 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -1045,7 +1045,7 @@ int evm_inode_init_security(struct inode *inode, struct inode *dir,
"%s: xattrs terminator is not the first non-filled slot\n",
__func__);
- xattr_data = kzalloc(sizeof(*xattr_data), GFP_NOFS);
+ xattr_data = kzalloc_obj(*xattr_data, GFP_NOFS);
if (!xattr_data)
return -ENOMEM;
diff --git a/security/integrity/evm/evm_secfs.c b/security/integrity/evm/evm_secfs.c
index c26724690cec..acd840461902 100644
--- a/security/integrity/evm/evm_secfs.c
+++ b/security/integrity/evm/evm_secfs.c
@@ -199,7 +199,7 @@ static ssize_t evm_write_xattrs(struct file *file, const char __user *buf,
if (!ab && IS_ENABLED(CONFIG_AUDIT))
return -ENOMEM;
- xattr = kmalloc(sizeof(struct xattr_list), GFP_KERNEL);
+ xattr = kmalloc_obj(struct xattr_list);
if (!xattr) {
err = -ENOMEM;
goto out;
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index c6d1c7be8a3e..d15becc8c640 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -48,13 +48,14 @@ int ima_alloc_init_template(struct ima_event_data *event_data,
else
template_desc = ima_template_desc_current();
- *entry = kzalloc(struct_size(*entry, template_data,
- template_desc->num_fields), GFP_NOFS);
+ *entry = kzalloc_flex(**entry, template_data, template_desc->num_fields,
+ GFP_NOFS);
if (!*entry)
return -ENOMEM;
- digests = kcalloc(NR_BANKS(ima_tpm_chip) + ima_extra_slots,
- sizeof(*digests), GFP_NOFS);
+ digests = kzalloc_objs(*digests,
+ NR_BANKS(ima_tpm_chip) + ima_extra_slots,
+ GFP_NOFS);
if (!digests) {
kfree(*entry);
*entry = NULL;
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
index 6f5696d999d0..aff61643415d 100644
--- a/security/integrity/ima/ima_crypto.c
+++ b/security/integrity/ima/ima_crypto.c
@@ -138,8 +138,8 @@ int __init ima_init_crypto(void)
if (ima_hash_algo_idx < 0)
ima_hash_algo_idx = NR_BANKS(ima_tpm_chip) + ima_extra_slots++;
- ima_algo_array = kcalloc(NR_BANKS(ima_tpm_chip) + ima_extra_slots,
- sizeof(*ima_algo_array), GFP_KERNEL);
+ ima_algo_array = kzalloc_objs(*ima_algo_array,
+ NR_BANKS(ima_tpm_chip) + ima_extra_slots);
if (!ima_algo_array) {
rc = -ENOMEM;
goto out;
diff --git a/security/integrity/ima/ima_modsig.c b/security/integrity/ima/ima_modsig.c
index 3265d744d5ce..9aa92fd35a03 100644
--- a/security/integrity/ima/ima_modsig.c
+++ b/security/integrity/ima/ima_modsig.c
@@ -65,7 +65,7 @@ int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len,
buf_len -= sig_len + sizeof(*sig);
/* Allocate sig_len additional bytes to hold the raw PKCS#7 data. */
- hdr = kzalloc(struct_size(hdr, raw_pkcs7, sig_len), GFP_KERNEL);
+ hdr = kzalloc_flex(*hdr, raw_pkcs7, sig_len);
if (!hdr)
return -ENOMEM;
diff --git a/security/integrity/ima/ima_mok.c b/security/integrity/ima/ima_mok.c
index 95cc31525c57..14d93d573a6a 100644
--- a/security/integrity/ima/ima_mok.c
+++ b/security/integrity/ima/ima_mok.c
@@ -27,7 +27,7 @@ static __init int ima_mok_init(void)
pr_notice("Allocating IMA blacklist keyring.\n");
- restriction = kzalloc(sizeof(struct key_restriction), GFP_KERNEL);
+ restriction = kzalloc_obj(struct key_restriction);
if (!restriction)
panic("Can't allocate IMA blacklist restriction.");
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 8fbd8755f5bc..bf2d7ba4c14a 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -342,7 +342,7 @@ static struct ima_rule_opt_list *ima_alloc_rule_opt_list(const substring_t *src)
return ERR_PTR(-EINVAL);
}
- opt_list = kzalloc(struct_size(opt_list, items, count), GFP_KERNEL);
+ opt_list = kzalloc_flex(*opt_list, items, count);
if (!opt_list) {
kfree(src_copy);
return ERR_PTR(-ENOMEM);
@@ -921,8 +921,7 @@ static int __init ima_init_arch_policy(void)
for (rules = arch_rules; *rules != NULL; rules++)
arch_entries++;
- arch_policy_entry = kcalloc(arch_entries + 1,
- sizeof(*arch_policy_entry), GFP_KERNEL);
+ arch_policy_entry = kzalloc_objs(*arch_policy_entry, arch_entries + 1);
if (!arch_policy_entry)
return 0;
@@ -1976,7 +1975,7 @@ ssize_t ima_parse_add_rule(char *rule)
if (*p == '#' || *p == '\0')
return len;
- entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ entry = kzalloc_obj(*entry);
if (!entry) {
integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL,
NULL, op, "-ENOMEM", -ENOMEM, audit_info);
diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
index 590637e81ad1..319522450854 100644
--- a/security/integrity/ima/ima_queue.c
+++ b/security/integrity/ima/ima_queue.c
@@ -103,7 +103,7 @@ static int ima_add_digest_entry(struct ima_template_entry *entry,
struct ima_queue_entry *qe;
unsigned int key;
- qe = kmalloc(sizeof(*qe), GFP_KERNEL);
+ qe = kmalloc_obj(*qe);
if (qe == NULL) {
pr_err("OUT OF MEMORY ERROR creating queue entry\n");
return -ENOMEM;
@@ -269,8 +269,8 @@ int __init ima_init_digests(void)
if (!ima_tpm_chip)
return 0;
- digests = kcalloc(ima_tpm_chip->nr_allocated_banks, sizeof(*digests),
- GFP_NOFS);
+ digests = kzalloc_objs(*digests, ima_tpm_chip->nr_allocated_banks,
+ GFP_NOFS);
if (!digests)
return -ENOMEM;
diff --git a/security/integrity/ima/ima_queue_keys.c b/security/integrity/ima/ima_queue_keys.c
index 4f0aea155bf9..b5ed33cbb272 100644
--- a/security/integrity/ima/ima_queue_keys.c
+++ b/security/integrity/ima/ima_queue_keys.c
@@ -72,7 +72,7 @@ static struct ima_key_entry *ima_alloc_key_entry(struct key *keyring,
const char *audit_cause = "ENOMEM";
struct ima_key_entry *entry;
- entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ entry = kzalloc_obj(*entry);
if (entry) {
entry->payload = kmemdup(payload, payload_len, GFP_KERNEL);
entry->keyring_name = kstrdup(keyring->description,
diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c
index 04c49f05cb74..7034573fb41e 100644
--- a/security/integrity/ima/ima_template.c
+++ b/security/integrity/ima/ima_template.c
@@ -245,7 +245,7 @@ int template_desc_init_fields(const char *template_fmt,
}
if (fields && num_fields) {
- *fields = kmalloc_array(i, sizeof(**fields), GFP_KERNEL);
+ *fields = kmalloc_objs(**fields, i);
if (*fields == NULL)
return -ENOMEM;
@@ -334,7 +334,7 @@ static struct ima_template_desc *restore_template_fmt(char *template_name)
goto out;
}
- template_desc = kzalloc(sizeof(*template_desc), GFP_KERNEL);
+ template_desc = kzalloc_obj(*template_desc);
if (!template_desc)
goto out;
@@ -362,13 +362,14 @@ static int ima_restore_template_data(struct ima_template_desc *template_desc,
int ret = 0;
int i;
- *entry = kzalloc(struct_size(*entry, template_data,
- template_desc->num_fields), GFP_NOFS);
+ *entry = kzalloc_flex(**entry, template_data, template_desc->num_fields,
+ GFP_NOFS);
if (!*entry)
return -ENOMEM;
- digests = kcalloc(NR_BANKS(ima_tpm_chip) + ima_extra_slots,
- sizeof(*digests), GFP_NOFS);
+ digests = kzalloc_objs(*digests,
+ NR_BANKS(ima_tpm_chip) + ima_extra_slots,
+ GFP_NOFS);
if (!digests) {
kfree(*entry);
return -ENOMEM;
diff --git a/security/ipe/digest.c b/security/ipe/digest.c
index 5006366837ba..6e597a6b7633 100644
--- a/security/ipe/digest.c
+++ b/security/ipe/digest.c
@@ -29,7 +29,7 @@ struct digest_info *ipe_digest_parse(const char *valstr)
char *alg = NULL;
int rc = 0;
- info = kzalloc(sizeof(*info), GFP_KERNEL);
+ info = kzalloc_obj(*info);
if (!info)
return ERR_PTR(-ENOMEM);
diff --git a/security/ipe/hooks.c b/security/ipe/hooks.c
index 603abdc9ce3b..0ae54a880405 100644
--- a/security/ipe/hooks.c
+++ b/security/ipe/hooks.c
@@ -287,7 +287,7 @@ int ipe_bdev_setintegrity(struct block_device *bdev, enum lsm_integrity_type typ
}
digest = value;
- info = kzalloc(sizeof(*info), GFP_KERNEL);
+ info = kzalloc_obj(*info);
if (!info)
return -ENOMEM;
diff --git a/security/ipe/policy.c b/security/ipe/policy.c
index 1c58c29886e8..827867be4fac 100644
--- a/security/ipe/policy.c
+++ b/security/ipe/policy.c
@@ -162,7 +162,7 @@ struct ipe_policy *ipe_new_policy(const char *text, size_t textlen,
struct ipe_policy *new = NULL;
int rc = 0;
- new = kzalloc(sizeof(*new), GFP_KERNEL);
+ new = kzalloc_obj(*new);
if (!new)
return ERR_PTR(-ENOMEM);
diff --git a/security/ipe/policy_parser.c b/security/ipe/policy_parser.c
index 7f27e39931d6..6fa5bebf8471 100644
--- a/security/ipe/policy_parser.c
+++ b/security/ipe/policy_parser.c
@@ -30,7 +30,7 @@ static struct ipe_parsed_policy *new_parsed_policy(void)
struct ipe_op_table *t = NULL;
size_t i = 0;
- p = kzalloc(sizeof(*p), GFP_KERNEL);
+ p = kzalloc_obj(*p);
if (!p)
return ERR_PTR(-ENOMEM);
@@ -305,7 +305,7 @@ static int parse_property(char *t, struct ipe_rule *r)
int token;
char *dup = NULL;
- p = kzalloc(sizeof(*p), GFP_KERNEL);
+ p = kzalloc_obj(*p);
if (!p)
return -ENOMEM;
@@ -373,7 +373,7 @@ static int parse_rule(char *line, struct ipe_parsed_policy *p)
if (IS_ERR_OR_NULL(line))
return -EBADMSG;
- r = kzalloc(sizeof(*r), GFP_KERNEL);
+ r = kzalloc_obj(*r);
if (!r)
return -ENOMEM;
diff --git a/security/keys/key.c b/security/keys/key.c
index 3bbdde778631..091ee084bc30 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -77,7 +77,7 @@ try_again:
spin_unlock(&key_user_lock);
user = NULL;
- candidate = kmalloc(sizeof(struct key_user), GFP_KERNEL);
+ candidate = kmalloc_obj(struct key_user);
if (unlikely(!candidate))
goto out;
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index ab927a142f51..ef855d69c97a 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -1796,13 +1796,13 @@ long keyctl_watch_key(key_serial_t id, int watch_queue_fd, int watch_id)
if (watch_id >= 0) {
ret = -ENOMEM;
if (!key->watchers) {
- wlist = kzalloc(sizeof(*wlist), GFP_KERNEL);
+ wlist = kzalloc_obj(*wlist);
if (!wlist)
goto err_wqueue;
init_watch_list(wlist, NULL);
}
- watch = kzalloc(sizeof(*watch), GFP_KERNEL);
+ watch = kzalloc_obj(*watch);
if (!watch)
goto err_wlist;
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index f331725d5a37..b39038f7dd31 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -977,7 +977,7 @@ static struct key_restriction *keyring_restriction_alloc(
key_restrict_link_func_t check)
{
struct key_restriction *keyres =
- kzalloc(sizeof(struct key_restriction), GFP_KERNEL);
+ kzalloc_obj(struct key_restriction);
if (!keyres)
return ERR_PTR(-ENOMEM);
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
index 8f33cd170e42..a7d7538c1f70 100644
--- a/security/keys/request_key_auth.c
+++ b/security/keys/request_key_auth.c
@@ -171,7 +171,7 @@ struct key *request_key_auth_new(struct key *target, const char *op,
kenter("%d,", target->serial);
/* allocate a auth record */
- rka = kzalloc(sizeof(*rka), GFP_KERNEL);
+ rka = kzalloc_obj(*rka);
if (!rka)
goto error;
rka->callout_info = kmemdup(callout_info, callout_len, GFP_KERNEL);
diff --git a/security/keys/trusted-keys/trusted_core.c b/security/keys/trusted-keys/trusted_core.c
index 9046123d94de..0b142d941cd2 100644
--- a/security/keys/trusted-keys/trusted_core.c
+++ b/security/keys/trusted-keys/trusted_core.c
@@ -134,7 +134,7 @@ static struct trusted_key_payload *trusted_payload_alloc(struct key *key)
ret = key_payload_reserve(key, sizeof(*p));
if (ret < 0)
goto err;
- p = kzalloc(sizeof(*p), GFP_KERNEL);
+ p = kzalloc_obj(*p);
if (!p)
goto err;
diff --git a/security/keys/trusted-keys/trusted_pkwm.c b/security/keys/trusted-keys/trusted_pkwm.c
index 4f391b77a907..bf42c6679245 100644
--- a/security/keys/trusted-keys/trusted_pkwm.c
+++ b/security/keys/trusted-keys/trusted_pkwm.c
@@ -62,10 +62,10 @@ static struct trusted_key_options *trusted_options_alloc(void)
struct trusted_key_options *options;
struct trusted_pkwm_options *pkwm;
- options = kzalloc(sizeof(*options), GFP_KERNEL);
+ options = kzalloc_obj(*options);
if (options) {
- pkwm = kzalloc(sizeof(*pkwm), GFP_KERNEL);
+ pkwm = kzalloc_obj(*pkwm);
if (!pkwm) {
kfree_sensitive(options);
diff --git a/security/keys/trusted-keys/trusted_tpm1.c b/security/keys/trusted-keys/trusted_tpm1.c
index c865c97aa1b4..6ea728f1eae6 100644
--- a/security/keys/trusted-keys/trusted_tpm1.c
+++ b/security/keys/trusted-keys/trusted_tpm1.c
@@ -440,7 +440,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
int i;
/* alloc some work space for all the hashes */
- td = kmalloc(sizeof *td, GFP_KERNEL);
+ td = kmalloc_obj(*td);
if (!td)
return -ENOMEM;
@@ -838,7 +838,7 @@ static struct trusted_key_options *trusted_options_alloc(void)
if (tpm2 < 0)
return NULL;
- options = kzalloc(sizeof *options, GFP_KERNEL);
+ options = kzalloc_obj(*options);
if (options) {
/* set any non-zero defaults */
options->keytype = SRK_keytype;
@@ -946,8 +946,7 @@ static int __init init_digests(void)
{
int i;
- digests = kcalloc(chip->nr_allocated_banks, sizeof(*digests),
- GFP_KERNEL);
+ digests = kzalloc_objs(*digests, chip->nr_allocated_banks);
if (!digests)
return -ENOMEM;
diff --git a/security/landlock/domain.c b/security/landlock/domain.c
index 79cb3bbdf4c5..f5b78d4766cd 100644
--- a/security/landlock/domain.c
+++ b/security/landlock/domain.c
@@ -95,7 +95,7 @@ static struct landlock_details *get_current_details(void)
* caller.
*/
details =
- kzalloc(struct_size(details, exe_path, path_size), GFP_KERNEL);
+ kzalloc_flex(*details, exe_path, path_size);
if (!details)
return ERR_PTR(-ENOMEM);
diff --git a/security/landlock/object.c b/security/landlock/object.c
index 1f50612f0185..0d6e159ef8b5 100644
--- a/security/landlock/object.c
+++ b/security/landlock/object.c
@@ -25,7 +25,7 @@ landlock_create_object(const struct landlock_object_underops *const underops,
if (WARN_ON_ONCE(!underops || !underobj))
return ERR_PTR(-ENOENT);
- new_object = kzalloc(sizeof(*new_object), GFP_KERNEL_ACCOUNT);
+ new_object = kzalloc_obj(*new_object, GFP_KERNEL_ACCOUNT);
if (!new_object)
return ERR_PTR(-ENOMEM);
refcount_set(&new_object->usage, 1);
diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
index 419b237de635..319873586385 100644
--- a/security/landlock/ruleset.c
+++ b/security/landlock/ruleset.c
@@ -33,8 +33,8 @@ static struct landlock_ruleset *create_ruleset(const u32 num_layers)
struct landlock_ruleset *new_ruleset;
new_ruleset =
- kzalloc(struct_size(new_ruleset, access_masks, num_layers),
- GFP_KERNEL_ACCOUNT);
+ kzalloc_flex(*new_ruleset, access_masks, num_layers,
+ GFP_KERNEL_ACCOUNT);
if (!new_ruleset)
return ERR_PTR(-ENOMEM);
refcount_set(&new_ruleset->usage, 1);
@@ -123,8 +123,8 @@ create_rule(const struct landlock_id id,
} else {
new_num_layers = num_layers;
}
- new_rule = kzalloc(struct_size(new_rule, layers, new_num_layers),
- GFP_KERNEL_ACCOUNT);
+ new_rule = kzalloc_flex(*new_rule, layers, new_num_layers,
+ GFP_KERNEL_ACCOUNT);
if (!new_rule)
return ERR_PTR(-ENOMEM);
RB_CLEAR_NODE(&new_rule->node);
@@ -559,8 +559,8 @@ landlock_merge_ruleset(struct landlock_ruleset *const parent,
if (IS_ERR(new_dom))
return new_dom;
- new_dom->hierarchy =
- kzalloc(sizeof(*new_dom->hierarchy), GFP_KERNEL_ACCOUNT);
+ new_dom->hierarchy = kzalloc_obj(*new_dom->hierarchy,
+ GFP_KERNEL_ACCOUNT);
if (!new_dom->hierarchy)
return ERR_PTR(-ENOMEM);
diff --git a/security/landlock/tsync.c b/security/landlock/tsync.c
index 0d2b9c646030..de01aa899751 100644
--- a/security/landlock/tsync.c
+++ b/security/landlock/tsync.c
@@ -237,7 +237,7 @@ static int tsync_works_grow_by(struct tsync_works *s, size_t n, gfp_t flags)
s->works = works;
for (i = s->capacity; i < new_capacity; i++) {
- work = kzalloc(sizeof(*work), flags);
+ work = kzalloc_obj(*work, flags);
if (!work) {
/*
* Leave the object in a consistent state,
diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c
index 6d5f3208f9ca..f71861f98e1a 100644
--- a/security/loadpin/loadpin.c
+++ b/security/loadpin/loadpin.c
@@ -327,7 +327,7 @@ static int read_trusted_verity_root_digests(unsigned int fd)
len /= 2;
- trd = kzalloc(struct_size(trd, data, len), GFP_KERNEL);
+ trd = kzalloc_flex(*trd, data, len);
if (!trd) {
rc = -ENOMEM;
goto err;
diff --git a/security/safesetid/securityfs.c b/security/safesetid/securityfs.c
index ece259f75b0d..a71e548065a9 100644
--- a/security/safesetid/securityfs.c
+++ b/security/safesetid/securityfs.c
@@ -118,7 +118,7 @@ static int verify_ruleset(struct setid_ruleset *pol)
res = -EINVAL;
/* fix it up */
- nrule = kmalloc(sizeof(struct setid_rule), GFP_KERNEL);
+ nrule = kmalloc_obj(struct setid_rule);
if (!nrule)
return -ENOMEM;
if (pol->type == UID){
@@ -146,7 +146,7 @@ static ssize_t handle_policy_update(struct file *file,
if (len >= KMALLOC_MAX_SIZE)
return -EINVAL;
- pol = kmalloc(sizeof(struct setid_ruleset), GFP_KERNEL);
+ pol = kmalloc_obj(struct setid_ruleset);
if (!pol)
return -ENOMEM;
pol->policy_str = NULL;
@@ -175,7 +175,7 @@ static ssize_t handle_policy_update(struct file *file,
}
*end = '\0';
- rule = kmalloc(sizeof(struct setid_rule), GFP_KERNEL);
+ rule = kmalloc_obj(struct setid_rule);
if (!rule) {
err = -ENOMEM;
goto out_free_buf;
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 8f77b9a732e1..813e82bcfc27 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -794,7 +794,7 @@ int __init avc_add_callback(int (*callback)(u32 event), u32 events)
struct avc_callback_node *c;
int rc = 0;
- c = kmalloc(sizeof(*c), GFP_KERNEL);
+ c = kmalloc_obj(*c);
if (!c) {
rc = -ENOMEM;
goto out;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index feda34b18d83..d8224ea113d1 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1030,7 +1030,7 @@ static int selinux_add_opt(int token, const char *s, void **mnt_opts)
}
if (!opts) {
- opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+ opts = kzalloc_obj(*opts);
if (!opts)
return -ENOMEM;
*mnt_opts = opts;
@@ -2822,7 +2822,7 @@ static int selinux_fs_context_submount(struct fs_context *fc,
if (!(sbsec->flags & (FSCONTEXT_MNT|CONTEXT_MNT|DEFCONTEXT_MNT)))
return 0;
- opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+ opts = kzalloc_obj(*opts);
if (!opts)
return -ENOMEM;
diff --git a/security/selinux/ibpkey.c b/security/selinux/ibpkey.c
index ea1d9b2c7d2b..93a5637fbcd8 100644
--- a/security/selinux/ibpkey.c
+++ b/security/selinux/ibpkey.c
@@ -147,7 +147,7 @@ static int sel_ib_pkey_sid_slow(u64 subnet_prefix, u16 pkey_num, u32 *sid)
if (ret)
goto out;
- new = kmalloc(sizeof(*new), GFP_ATOMIC);
+ new = kmalloc_obj(*new, GFP_ATOMIC);
if (!new) {
/* If this memory allocation fails still return 0. The SID
* is valid, it just won't be added to the cache.
diff --git a/security/selinux/netif.c b/security/selinux/netif.c
index e24b2cba28ea..fa6d24a37c39 100644
--- a/security/selinux/netif.c
+++ b/security/selinux/netif.c
@@ -161,7 +161,7 @@ static int sel_netif_sid_slow(struct net *ns, int ifindex, u32 *sid)
/* If this memory allocation fails still return 0. The SID
* is valid, it just won't be added to the cache.
*/
- new = kmalloc(sizeof(*new), GFP_ATOMIC);
+ new = kmalloc_obj(*new, GFP_ATOMIC);
if (new) {
new->nsec.ns = ns;
new->nsec.ifindex = ifindex;
diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c
index 9b3da5ce8d39..adb93003b8c4 100644
--- a/security/selinux/netnode.c
+++ b/security/selinux/netnode.c
@@ -205,7 +205,7 @@ static int sel_netnode_sid_slow(const void *addr, u16 family, u32 *sid)
/* If this memory allocation fails still return 0. The SID
* is valid, it just won't be added to the cache.
*/
- new = kmalloc(sizeof(*new), GFP_ATOMIC);
+ new = kmalloc_obj(*new, GFP_ATOMIC);
switch (family) {
case PF_INET:
ret = security_node_sid(PF_INET,
diff --git a/security/selinux/netport.c b/security/selinux/netport.c
index 9e62f7285e81..006a6ec71319 100644
--- a/security/selinux/netport.c
+++ b/security/selinux/netport.c
@@ -150,7 +150,7 @@ static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid)
/* If this memory allocation fails still return 0. The SID
* is valid, it just won't be added to the cache.
*/
- new = kmalloc(sizeof(*new), GFP_ATOMIC);
+ new = kmalloc_obj(*new, GFP_ATOMIC);
if (new) {
new->psec.port = pnum;
new->psec.protocol = protocol;
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 4d58c7ad1a23..3245cc531555 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -85,7 +85,7 @@ static int selinux_fs_info_create(struct super_block *sb)
{
struct selinux_fs_info *fsi;
- fsi = kzalloc(sizeof(*fsi), GFP_KERNEL);
+ fsi = kzalloc_obj(*fsi);
if (!fsi)
return -ENOMEM;
@@ -380,7 +380,7 @@ static int sel_open_policy(struct inode *inode, struct file *filp)
goto err;
rc = -ENOMEM;
- plm = kzalloc(sizeof(*plm), GFP_KERNEL);
+ plm = kzalloc_obj(*plm);
if (!plm)
goto err;
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c
index 1bebfcb9c6a1..824c3f896151 100644
--- a/security/selinux/ss/conditional.c
+++ b/security/selinux/ss/conditional.c
@@ -165,8 +165,8 @@ void cond_policydb_destroy(struct policydb *p)
int cond_init_bool_indexes(struct policydb *p)
{
kfree(p->bool_val_to_struct);
- p->bool_val_to_struct = kmalloc_array(
- p->p_bools.nprim, sizeof(*p->bool_val_to_struct), GFP_KERNEL);
+ p->bool_val_to_struct = kmalloc_objs(*p->bool_val_to_struct,
+ p->p_bools.nprim);
if (!p->bool_val_to_struct)
return -ENOMEM;
@@ -214,7 +214,7 @@ int cond_read_bool(struct policydb *p, struct symtab *s, struct policy_file *fp)
u32 len;
int rc;
- booldatum = kzalloc(sizeof(*booldatum), GFP_KERNEL);
+ booldatum = kzalloc_obj(*booldatum);
if (!booldatum)
return -ENOMEM;
@@ -334,7 +334,7 @@ static int cond_read_av_list(struct policydb *p, struct policy_file *fp,
if (len == 0)
return 0;
- list->nodes = kcalloc(len, sizeof(*list->nodes), GFP_KERNEL);
+ list->nodes = kzalloc_objs(*list->nodes, len);
if (!list->nodes)
return -ENOMEM;
@@ -383,7 +383,7 @@ static int cond_read_node(struct policydb *p, struct cond_node *node, struct pol
/* expr */
len = le32_to_cpu(buf[1]);
- node->expr.nodes = kcalloc(len, sizeof(*node->expr.nodes), GFP_KERNEL);
+ node->expr.nodes = kzalloc_objs(*node->expr.nodes, len);
if (!node->expr.nodes)
return -ENOMEM;
@@ -421,7 +421,7 @@ int cond_read_list(struct policydb *p, struct policy_file *fp)
len = le32_to_cpu(buf[0]);
- p->cond_list = kcalloc(len, sizeof(*p->cond_list), GFP_KERNEL);
+ p->cond_list = kzalloc_objs(*p->cond_list, len);
if (!p->cond_list)
return -ENOMEM;
@@ -605,7 +605,7 @@ static int cond_dup_av_list(struct cond_av_list *new,
memset(new, 0, sizeof(*new));
- new->nodes = kcalloc(orig->len, sizeof(*new->nodes), GFP_KERNEL);
+ new->nodes = kzalloc_objs(*new->nodes, orig->len);
if (!new->nodes)
return -ENOMEM;
@@ -631,8 +631,7 @@ static int duplicate_policydb_cond_list(struct policydb *newp,
return rc;
newp->cond_list_len = 0;
- newp->cond_list = kcalloc(origp->cond_list_len,
- sizeof(*newp->cond_list), GFP_KERNEL);
+ newp->cond_list = kzalloc_objs(*newp->cond_list, origp->cond_list_len);
if (!newp->cond_list)
goto error;
@@ -710,9 +709,8 @@ static int duplicate_policydb_bools(struct policydb *newdb,
struct cond_bool_datum **cond_bool_array;
int rc;
- cond_bool_array = kmalloc_array(orig->p_bools.nprim,
- sizeof(*orig->bool_val_to_struct),
- GFP_KERNEL);
+ cond_bool_array = kmalloc_objs(*orig->bool_val_to_struct,
+ orig->p_bools.nprim);
if (!cond_bool_array)
return -ENOMEM;
diff --git a/security/selinux/ss/hashtab.c b/security/selinux/ss/hashtab.c
index 1382eb3bfde1..9ffc8a371e23 100644
--- a/security/selinux/ss/hashtab.c
+++ b/security/selinux/ss/hashtab.c
@@ -40,8 +40,8 @@ int hashtab_init(struct hashtab *h, u32 nel_hint)
h->htable = NULL;
if (size) {
- h->htable = kcalloc(size, sizeof(*h->htable),
- GFP_KERNEL | __GFP_NOWARN);
+ h->htable = kzalloc_objs(*h->htable, size,
+ GFP_KERNEL | __GFP_NOWARN);
if (!h->htable)
return -ENOMEM;
h->size = size;
@@ -149,7 +149,7 @@ int hashtab_duplicate(struct hashtab *new, const struct hashtab *orig,
memset(new, 0, sizeof(*new));
- new->htable = kcalloc(orig->size, sizeof(*new->htable), GFP_KERNEL);
+ new->htable = kzalloc_objs(*new->htable, orig->size);
if (!new->htable)
return -ENOMEM;
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index 91df3db6a88c..738fd47f33e6 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -390,7 +390,7 @@ static int roles_init(struct policydb *p)
int rc;
struct role_datum *role;
- role = kzalloc(sizeof(*role), GFP_KERNEL);
+ role = kzalloc_obj(*role);
if (!role)
return -ENOMEM;
@@ -738,24 +738,23 @@ static int policydb_index(struct policydb *p)
avtab_hash_eval(&p->te_avtab, "rules");
symtab_hash_eval(p->symtab);
- p->class_val_to_struct = kcalloc(p->p_classes.nprim,
- sizeof(*p->class_val_to_struct),
- GFP_KERNEL);
+ p->class_val_to_struct = kzalloc_objs(*p->class_val_to_struct,
+ p->p_classes.nprim);
if (!p->class_val_to_struct)
return -ENOMEM;
- p->role_val_to_struct = kcalloc(
- p->p_roles.nprim, sizeof(*p->role_val_to_struct), GFP_KERNEL);
+ p->role_val_to_struct = kzalloc_objs(*p->role_val_to_struct,
+ p->p_roles.nprim);
if (!p->role_val_to_struct)
return -ENOMEM;
- p->user_val_to_struct = kcalloc(
- p->p_users.nprim, sizeof(*p->user_val_to_struct), GFP_KERNEL);
+ p->user_val_to_struct = kzalloc_objs(*p->user_val_to_struct,
+ p->p_users.nprim);
if (!p->user_val_to_struct)
return -ENOMEM;
- p->type_val_to_struct = kvcalloc(
- p->p_types.nprim, sizeof(*p->type_val_to_struct), GFP_KERNEL);
+ p->type_val_to_struct = kvzalloc_objs(*p->type_val_to_struct,
+ p->p_types.nprim);
if (!p->type_val_to_struct)
return -ENOMEM;
@@ -1131,7 +1130,7 @@ static int perm_read(struct policydb *p, struct symtab *s, struct policy_file *f
__le32 buf[2];
u32 len;
- perdatum = kzalloc(sizeof(*perdatum), GFP_KERNEL);
+ perdatum = kzalloc_obj(*perdatum);
if (!perdatum)
return -ENOMEM;
@@ -1164,7 +1163,7 @@ static int common_read(struct policydb *p, struct symtab *s, struct policy_file
u32 i, len, nel;
int rc;
- comdatum = kzalloc(sizeof(*comdatum), GFP_KERNEL);
+ comdatum = kzalloc_obj(*comdatum);
if (!comdatum)
return -ENOMEM;
@@ -1237,7 +1236,7 @@ static int read_cons_helper(struct policydb *p, struct constraint_node **nodep,
lc = NULL;
for (i = 0; i < ncons; i++) {
- c = kzalloc(sizeof(*c), GFP_KERNEL);
+ c = kzalloc_obj(*c);
if (!c)
return -ENOMEM;
@@ -1254,7 +1253,7 @@ static int read_cons_helper(struct policydb *p, struct constraint_node **nodep,
le = NULL;
depth = -1;
for (j = 0; j < nexpr; j++) {
- e = kzalloc(sizeof(*e), GFP_KERNEL);
+ e = kzalloc_obj(*e);
if (!e)
return -ENOMEM;
@@ -1297,9 +1296,7 @@ static int read_cons_helper(struct policydb *p, struct constraint_node **nodep,
return rc;
if (p->policyvers >=
POLICYDB_VERSION_CONSTRAINT_NAMES) {
- e->type_names =
- kzalloc(sizeof(*e->type_names),
- GFP_KERNEL);
+ e->type_names = kzalloc_obj(*e->type_names);
if (!e->type_names)
return -ENOMEM;
type_set_init(e->type_names);
@@ -1329,7 +1326,7 @@ static int class_read(struct policydb *p, struct symtab *s, struct policy_file *
u32 i, len, len2, ncons, nel;
int rc;
- cladatum = kzalloc(sizeof(*cladatum), GFP_KERNEL);
+ cladatum = kzalloc_obj(*cladatum);
if (!cladatum)
return -ENOMEM;
@@ -1427,7 +1424,7 @@ static int role_read(struct policydb *p, struct symtab *s, struct policy_file *f
__le32 buf[3];
u32 len;
- role = kzalloc(sizeof(*role), GFP_KERNEL);
+ role = kzalloc_obj(*role);
if (!role)
return -ENOMEM;
@@ -1484,7 +1481,7 @@ static int type_read(struct policydb *p, struct symtab *s, struct policy_file *f
__le32 buf[4];
u32 len;
- typdatum = kzalloc(sizeof(*typdatum), GFP_KERNEL);
+ typdatum = kzalloc_obj(*typdatum);
if (!typdatum)
return -ENOMEM;
@@ -1558,7 +1555,7 @@ static int user_read(struct policydb *p, struct symtab *s, struct policy_file *f
__le32 buf[3];
u32 len;
- usrdatum = kzalloc(sizeof(*usrdatum), GFP_KERNEL);
+ usrdatum = kzalloc_obj(*usrdatum);
if (!usrdatum)
return -ENOMEM;
@@ -1608,7 +1605,7 @@ static int sens_read(struct policydb *p, struct symtab *s, struct policy_file *f
__le32 buf[2];
u32 len;
- levdatum = kzalloc(sizeof(*levdatum), GFP_KERNEL);
+ levdatum = kzalloc_obj(*levdatum);
if (!levdatum)
return -ENOMEM;
@@ -1644,7 +1641,7 @@ static int cat_read(struct policydb *p, struct symtab *s, struct policy_file *fp
__le32 buf[3];
u32 len;
- catdatum = kzalloc(sizeof(*catdatum), GFP_KERNEL);
+ catdatum = kzalloc_obj(*catdatum);
if (!catdatum)
return -ENOMEM;
@@ -1864,7 +1861,7 @@ static int range_read(struct policydb *p, struct policy_file *fp)
for (i = 0; i < nel; i++) {
rc = -ENOMEM;
- rt = kzalloc(sizeof(*rt), GFP_KERNEL);
+ rt = kzalloc_obj(*rt);
if (!rt)
goto out;
@@ -1889,7 +1886,7 @@ static int range_read(struct policydb *p, struct policy_file *fp)
goto out;
rc = -ENOMEM;
- r = kzalloc(sizeof(*r), GFP_KERNEL);
+ r = kzalloc_obj(*r);
if (!r)
goto out;
@@ -1965,7 +1962,7 @@ static int filename_trans_read_helper_compat(struct policydb *p, struct policy_f
}
if (!datum) {
rc = -ENOMEM;
- datum = kmalloc(sizeof(*datum), GFP_KERNEL);
+ datum = kmalloc_obj(*datum);
if (!datum)
goto out;
@@ -2040,7 +2037,7 @@ static int filename_trans_read_helper(struct policydb *p, struct policy_file *fp
dst = &first;
for (i = 0; i < ndatum; i++) {
rc = -ENOMEM;
- datum = kmalloc(sizeof(*datum), GFP_KERNEL);
+ datum = kmalloc_obj(*datum);
if (!datum)
goto out;
@@ -2062,7 +2059,7 @@ static int filename_trans_read_helper(struct policydb *p, struct policy_file *fp
}
rc = -ENOMEM;
- ft = kmalloc(sizeof(*ft), GFP_KERNEL);
+ ft = kmalloc_obj(*ft);
if (!ft)
goto out;
@@ -2155,7 +2152,7 @@ static int genfs_read(struct policydb *p, struct policy_file *fp)
len = le32_to_cpu(buf[0]);
rc = -ENOMEM;
- newgenfs = kzalloc(sizeof(*newgenfs), GFP_KERNEL);
+ newgenfs = kzalloc_obj(*newgenfs);
if (!newgenfs)
goto out;
@@ -2194,7 +2191,7 @@ static int genfs_read(struct policydb *p, struct policy_file *fp)
len = le32_to_cpu(buf[0]);
rc = -ENOMEM;
- newc = kzalloc(sizeof(*newc), GFP_KERNEL);
+ newc = kzalloc_obj(*newc);
if (!newc)
goto out;
@@ -2266,7 +2263,7 @@ static int ocontext_read(struct policydb *p,
l = NULL;
for (j = 0; j < nel; j++) {
rc = -ENOMEM;
- c = kzalloc(sizeof(*c), GFP_KERNEL);
+ c = kzalloc_obj(*c);
if (!c)
goto out;
if (l)
@@ -2623,12 +2620,12 @@ int policydb_read(struct policydb *p, struct policy_file *fp)
goto bad;
for (i = 0; i < nel; i++) {
rc = -ENOMEM;
- rtk = kmalloc(sizeof(*rtk), GFP_KERNEL);
+ rtk = kmalloc_obj(*rtk);
if (!rtk)
goto bad;
rc = -ENOMEM;
- rtd = kmalloc(sizeof(*rtd), GFP_KERNEL);
+ rtd = kmalloc_obj(*rtd);
if (!rtd)
goto bad;
@@ -2671,7 +2668,7 @@ int policydb_read(struct policydb *p, struct policy_file *fp)
lra = NULL;
for (i = 0; i < nel; i++) {
rc = -ENOMEM;
- ra = kzalloc(sizeof(*ra), GFP_KERNEL);
+ ra = kzalloc_obj(*ra);
if (!ra)
goto bad;
if (lra)
@@ -2726,8 +2723,8 @@ int policydb_read(struct policydb *p, struct policy_file *fp)
goto bad;
rc = -ENOMEM;
- p->type_attr_map_array = kvcalloc(
- p->p_types.nprim, sizeof(*p->type_attr_map_array), GFP_KERNEL);
+ p->type_attr_map_array = kvzalloc_objs(*p->type_attr_map_array,
+ p->p_types.nprim);
if (!p->type_attr_map_array)
goto bad;
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 13fc712d5923..e8e7ccbd1e44 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -108,7 +108,7 @@ static int selinux_set_mapping(struct policydb *pol,
i++;
/* Allocate space for the class records, plus one for class zero */
- out_map->mapping = kcalloc(++i, sizeof(*out_map->mapping), GFP_ATOMIC);
+ out_map->mapping = kzalloc_objs(*out_map->mapping, ++i, GFP_ATOMIC);
if (!out_map->mapping)
return -ENOMEM;
@@ -2312,11 +2312,11 @@ int security_load_policy(void *data, size_t len,
int rc = 0;
struct policy_file file = { data, len }, *fp = &file;
- newpolicy = kzalloc(sizeof(*newpolicy), GFP_KERNEL);
+ newpolicy = kzalloc_obj(*newpolicy);
if (!newpolicy)
return -ENOMEM;
- newpolicy->sidtab = kzalloc(sizeof(*newpolicy->sidtab), GFP_KERNEL);
+ newpolicy->sidtab = kzalloc_obj(*newpolicy->sidtab);
if (!newpolicy->sidtab) {
rc = -ENOMEM;
goto err_policy;
@@ -2360,7 +2360,7 @@ int security_load_policy(void *data, size_t len,
* in the new SID table.
*/
- convert_data = kmalloc(sizeof(*convert_data), GFP_KERNEL);
+ convert_data = kmalloc_obj(*convert_data);
if (!convert_data) {
rc = -ENOMEM;
goto err_free_isids;
@@ -3065,7 +3065,7 @@ int security_get_bools(struct selinux_policy *policy,
goto err;
rc = -ENOMEM;
- *values = kcalloc(*len, sizeof(int), GFP_ATOMIC);
+ *values = kzalloc_objs(int, *len, GFP_ATOMIC);
if (!*values)
goto err;
@@ -3629,7 +3629,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule,
return -EINVAL;
}
- tmprule = kzalloc(sizeof(struct selinux_audit_rule), gfp);
+ tmprule = kzalloc_obj(struct selinux_audit_rule, gfp);
if (!tmprule)
return -ENOMEM;
context_init(&tmprule->au_ctxt);
@@ -3844,7 +3844,7 @@ static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr,
{
u32 *sid_cache;
- sid_cache = kmalloc(sizeof(*sid_cache), GFP_ATOMIC);
+ sid_cache = kmalloc_obj(*sid_cache, GFP_ATOMIC);
if (sid_cache == NULL)
return;
secattr->cache = netlbl_secattr_cache_alloc(GFP_ATOMIC);
diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c
index 59f8c09158ef..118af0aa2767 100644
--- a/security/selinux/ss/sidtab.c
+++ b/security/selinux/ss/sidtab.c
@@ -580,7 +580,7 @@ void sidtab_sid2str_put(struct sidtab *s, struct sidtab_entry *entry,
goto out_unlock;
}
- cache = kmalloc(struct_size(cache, str, str_len), GFP_ATOMIC);
+ cache = kmalloc_flex(*cache, str, str_len, GFP_ATOMIC);
if (!cache)
goto out_unlock;
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
index 61d56b0c2be1..8e00b3306574 100644
--- a/security/selinux/xfrm.c
+++ b/security/selinux/xfrm.c
@@ -88,7 +88,7 @@ static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
if (str_len >= PAGE_SIZE)
return -ENOMEM;
- ctx = kmalloc(struct_size(ctx, ctx_str, str_len + 1), gfp);
+ ctx = kmalloc_flex(*ctx, ctx_str, str_len + 1, gfp);
if (!ctx)
return -ENOMEM;
@@ -354,7 +354,7 @@ int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x,
if (rc)
return rc;
- ctx = kmalloc(struct_size(ctx, ctx_str, str_len), GFP_ATOMIC);
+ ctx = kmalloc_flex(*ctx, ctx_str, str_len, GFP_ATOMIC);
if (!ctx) {
rc = -ENOMEM;
goto out;
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index 86ad910d5631..350b88d582b3 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -592,7 +592,7 @@ smk_import_allocated_label(char *smack, gfp_t gfp)
if (skp != NULL)
goto freeout;
- skp = kzalloc(sizeof(*skp), gfp);
+ skp = kzalloc_obj(*skp, gfp);
if (skp == NULL) {
skp = ERR_PTR(-ENOMEM);
goto freeout;
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index a0bd4919a9d9..98af9d7b9434 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -372,7 +372,7 @@ static int smk_copy_relabel(struct list_head *nhead, struct list_head *ohead,
struct smack_known_list_elem *oklep;
list_for_each_entry(oklep, ohead, list) {
- nklep = kzalloc(sizeof(struct smack_known_list_elem), gfp);
+ nklep = kzalloc_obj(struct smack_known_list_elem, gfp);
if (nklep == NULL) {
smk_destroy_label_list(nhead);
return -ENOMEM;
@@ -562,7 +562,7 @@ static int smack_add_opt(int token, const char *s, void **mnt_opts)
struct smack_known *skp;
if (!opts) {
- opts = kzalloc(sizeof(struct smack_mnt_opts), GFP_KERNEL);
+ opts = kzalloc_obj(struct smack_mnt_opts);
if (!opts)
return -ENOMEM;
*mnt_opts = opts;
@@ -622,7 +622,7 @@ static int smack_fs_context_submount(struct fs_context *fc,
struct smack_mnt_opts *ctx;
struct inode_smack *isp;
- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ ctx = kzalloc_obj(*ctx);
if (!ctx)
return -ENOMEM;
fc->security = ctx;
@@ -673,7 +673,7 @@ static int smack_fs_context_dup(struct fs_context *fc,
if (!src)
return 0;
- fc->security = kzalloc(sizeof(struct smack_mnt_opts), GFP_KERNEL);
+ fc->security = kzalloc_obj(struct smack_mnt_opts);
if (!fc->security)
return -ENOMEM;
@@ -2817,7 +2817,7 @@ static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address)
/*
* A new port entry is required.
*/
- spp = kzalloc(sizeof(*spp), GFP_KERNEL);
+ spp = kzalloc_obj(*spp);
if (spp == NULL)
return;
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 8919e330d2f6..6e62dcb36f74 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -682,7 +682,7 @@ smk_cipso_doi(u32 ndoi, gfp_t gfp_flags)
smk_netlabel_audit_set(&nai);
- doip = kmalloc(sizeof(struct cipso_v4_doi), gfp_flags);
+ doip = kmalloc_obj(struct cipso_v4_doi, gfp_flags);
if (!doip) {
rc = -ENOMEM;
goto clr_doi_lock;
@@ -1249,7 +1249,7 @@ static ssize_t smk_write_net4addr(struct file *file, const char __user *buf,
smk_netlabel_audit_set(&audit_info);
if (found == 0) {
- snp = kzalloc(sizeof(*snp), GFP_KERNEL);
+ snp = kzalloc_obj(*snp);
if (snp == NULL)
rc = -ENOMEM;
else {
@@ -1526,7 +1526,7 @@ static ssize_t smk_write_net6addr(struct file *file, const char __user *buf,
break;
}
if (found == 0) {
- snp = kzalloc(sizeof(*snp), GFP_KERNEL);
+ snp = kzalloc_obj(*snp);
if (snp == NULL)
rc = -ENOMEM;
else {
@@ -1970,7 +1970,7 @@ static int smk_parse_label_list(char *data, struct list_head *list)
if (IS_ERR(skp))
return PTR_ERR(skp);
- sklep = kzalloc(sizeof(*sklep), GFP_KERNEL);
+ sklep = kzalloc_obj(*sklep);
if (sklep == NULL)
return -ENOMEM;
diff --git a/security/tomoyo/audit.c b/security/tomoyo/audit.c
index 610c1536cf70..bfacb3f2e2ed 100644
--- a/security/tomoyo/audit.c
+++ b/security/tomoyo/audit.c
@@ -376,7 +376,7 @@ void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt,
buf = tomoyo_init_log(r, len, fmt, args);
if (!buf)
goto out;
- entry = kzalloc(sizeof(*entry), GFP_NOFS);
+ entry = kzalloc_obj(*entry, GFP_NOFS);
if (!entry) {
kfree(buf);
goto out;
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c
index 7e1f825d903b..fdaeaff01fc1 100644
--- a/security/tomoyo/common.c
+++ b/security/tomoyo/common.c
@@ -493,7 +493,7 @@ static struct tomoyo_profile *tomoyo_assign_profile
ptr = ns->profile_ptr[profile];
if (ptr)
return ptr;
- entry = kzalloc(sizeof(*entry), GFP_NOFS | __GFP_NOWARN);
+ entry = kzalloc_obj(*entry, GFP_NOFS | __GFP_NOWARN);
if (mutex_lock_interruptible(&tomoyo_policy_lock))
goto out;
ptr = ns->profile_ptr[profile];
@@ -2553,7 +2553,7 @@ static int tomoyo_write_stat(struct tomoyo_io_buffer *head)
*/
int tomoyo_open_control(const u8 type, struct file *file)
{
- struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_NOFS);
+ struct tomoyo_io_buffer *head = kzalloc_obj(*head, GFP_NOFS);
if (!head)
return -ENOMEM;
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c
index 0612eac7f2f2..eeaad421f15b 100644
--- a/security/tomoyo/domain.c
+++ b/security/tomoyo/domain.c
@@ -708,7 +708,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
bool reject_on_transition_failure = false;
const struct tomoyo_path_info *candidate;
struct tomoyo_path_info exename;
- struct tomoyo_execve *ee = kzalloc(sizeof(*ee), GFP_NOFS);
+ struct tomoyo_execve *ee = kzalloc_obj(*ee, GFP_NOFS);
if (!ee)
return -ENOMEM;
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c
index 38b21ee0c560..cef3776cf3b2 100644
--- a/security/yama/yama_lsm.c
+++ b/security/yama/yama_lsm.c
@@ -89,7 +89,7 @@ static void report_access(const char *access, struct task_struct *target,
return;
}
- info = kmalloc(sizeof(*info), GFP_ATOMIC);
+ info = kmalloc_obj(*info, GFP_ATOMIC);
if (!info)
return;
init_task_work(&info->work, __report_access);
@@ -143,7 +143,7 @@ static int yama_ptracer_add(struct task_struct *tracer,
{
struct ptrace_relation *relation, *added;
- added = kmalloc(sizeof(*added), GFP_KERNEL);
+ added = kmalloc_obj(*added);
if (!added)
return -ENOMEM;