struct aa_ns *ns = NULL;
struct aa_load_ent *ent, *tmp;
int op = OP_PROF_REPL;
- ssize_t error;
+ ssize_t count, error;
LIST_HEAD(lh);
/* released below */
if (error)
goto out;
- /* released below */
- ns = aa_prepare_ns(view, ns_name);
- if (!ns) {
- error = audit_policy(__aa_current_profile(), op, GFP_KERNEL,
- NULL, ns_name,
- "failed to prepare namespace", -ENOMEM);
- goto free;
+ /* ensure that profiles are all for the same ns
+ * TODO: update locking to remove this constaint. All profiles in
+ * the load set must succeed as a set or the load will
+ * fail. Sort ent list and take ns locks in hierarchy order
+ */
+ count = 0;
+ list_for_each_entry(ent, &lh, list) {
+ if (ns_name) {
+ if (ent->ns_name &&
+ strcmp(ent->ns_name, ns_name) != 0) {
+ info = "policy load has mixed namespaces";
+ error = -EACCES;
+ goto fail;
+ }
+ } else if (ent->ns_name) {
+ if (count) {
+ info = "policy load has mixed namespaces";
+ error = -EACCES;
+ goto fail;
+ }
+ ns_name = ent->ns_name;
+ } else
+ count++;
}
+ if (ns_name) {
+ ns = aa_prepare_ns(view, ns_name);
+ if (IS_ERR(ns)) {
+ info = "failed to prepare namespace";
+ error = PTR_ERR(ns);
+ ns = NULL;
+ goto fail;
+ }
+ } else
+ ns = aa_get_ns(view);
mutex_lock(&ns->lock);
/* setup parent and ns info */
/* audit cause of failure */
op = (!ent->old) ? OP_PROF_LOAD : OP_PROF_REPL;
- audit_policy(__aa_current_profile(), op, GFP_KERNEL, NULL,
+fail:
+ audit_policy(__aa_current_profile(), op, GFP_KERNEL, ns_name,
ent->new->base.hname, info, error);
/* audit status that rest of profiles in the atomic set failed too */
info = "valid profile in failed atomic policy load";
continue;
}
op = (!ent->old) ? OP_PROF_LOAD : OP_PROF_REPL;
- audit_policy(__aa_current_profile(), op, GFP_KERNEL, NULL,
+ audit_policy(__aa_current_profile(), op, GFP_KERNEL, ns_name,
tmp->new->base.hname, info, error);
}
-free:
list_for_each_entry_safe(ent, tmp, &lh, list) {
list_del_init(&ent->list);
aa_load_ent_free(ent);
struct aa_ns *root = NULL, *ns = NULL;
struct aa_profile *profile = NULL;
const char *name = fqname, *info = NULL;
+ char *ns_name = NULL;
ssize_t error = 0;
if (*fqname == 0) {
root = view;
if (fqname[0] == ':') {
- char *ns_name;
name = aa_split_fqname(fqname, &ns_name);
/* released below */
ns = aa_find_ns(root, ns_name);
/* don't fail removal if audit fails */
(void) audit_policy(__aa_current_profile(), OP_PROF_RM, GFP_KERNEL,
- NULL, name, info, error);
+ ns_name, name, info, error);
aa_put_ns(ns);
aa_put_profile(profile);
return size;
fail:
(void) audit_policy(__aa_current_profile(), OP_PROF_RM, GFP_KERNEL,
- NULL, name, info, error);
+ ns_name, name, info, error);
return error;
}
/**
* audit_iface - do audit message for policy unpacking/load/replace/remove
* @new: profile if it has been allocated (MAYBE NULL)
+ * @ns_name: name of the ns the profile is to be loaded to (MAY BE NULL)
* @name: name of the profile being manipulated (MAYBE NULL)
* @info: any extra info about the failure (MAYBE NULL)
* @e: buffer position info
*
* Returns: %0 or error
*/
-static int audit_iface(struct aa_profile *new, const char *name,
- const char *info, struct aa_ext *e, int error)
+static int audit_iface(struct aa_profile *new, const char *ns_name,
+ const char *name, const char *info, struct aa_ext *e,
+ int error)
{
struct aa_profile *profile = __aa_current_profile();
struct common_audit_data sa;
struct apparmor_audit_data aad = {0,};
sa.type = LSM_AUDIT_DATA_NONE;
sa.aad = &aad;
+ aad.iface.ns = ns_name;
if (e)
aad.iface.pos = e->pos - e->start;
aad.iface.target = new;
*
* NOTE: unpack profile sets audit struct if there is a failure
*/
-static struct aa_profile *unpack_profile(struct aa_ext *e)
+static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
{
struct aa_profile *profile = NULL;
- const char *name = NULL;
+ const char *tmpname, *tmpns = NULL, *name = NULL;
+ size_t ns_len;
int i, error = -EPROTO;
kernel_cap_t tmpcap;
u32 tmp;
+ *ns_name = NULL;
+
/* check that we have the right struct being passed */
if (!unpack_nameX(e, AA_STRUCT, "profile"))
goto fail;
if (!unpack_str(e, &name, NULL))
goto fail;
+ if (*name == '\0')
+ goto fail;
+
+ tmpname = aa_splitn_fqname(name, strlen(name), &tmpns, &ns_len);
+ if (tmpns) {
+ *ns_name = kstrndup(tmpns, ns_len, GFP_KERNEL);
+ if (!*ns_name)
+ goto fail;
+ name = tmpname;
+ }
profile = aa_alloc_profile(name, GFP_KERNEL);
if (!profile)
name = NULL;
else if (!name)
name = "unknown";
- audit_iface(profile, name, "failed to unpack profile", e, error);
+ audit_iface(profile, NULL, name, "failed to unpack profile", e,
+ error);
aa_free_profile(profile);
return ERR_PTR(error);
/* get the interface version */
if (!unpack_u32(e, &e->version, "version")) {
if (required) {
- audit_iface(NULL, NULL, "invalid profile format",
+ audit_iface(NULL, NULL, NULL, "invalid profile format",
e, error);
return error;
}
* Mask off everything that is not kernel abi version
*/
if (VERSION_LT(e->version, v5) && VERSION_GT(e->version, v7)) {
- audit_iface(NULL, NULL, "unsupported interface version",
+ audit_iface(NULL, NULL, NULL, "unsupported interface version",
e, error);
return error;
}
/* read the namespace if present */
if (unpack_str(e, &name, "namespace")) {
+ if (*name == '\0') {
+ audit_iface(NULL, NULL, NULL, "invalid namespace name",
+ e, error);
+ return error;
+ }
if (*ns && strcmp(*ns, name))
- audit_iface(NULL, NULL, "invalid ns change", e, error);
+ audit_iface(NULL, NULL, NULL, "invalid ns change", e,
+ error);
else if (!*ns)
*ns = name;
}
if (profile->file.dfa &&
!verify_dfa_xindex(profile->file.dfa,
profile->file.trans.size)) {
- audit_iface(profile, NULL, "Invalid named transition",
+ audit_iface(profile, NULL, NULL, "Invalid named transition",
NULL, -EPROTO);
return -EPROTO;
}
aa_put_profile(ent->rename);
aa_put_profile(ent->old);
aa_put_profile(ent->new);
+ kfree(ent->ns_name);
kzfree(ent);
}
}
*ns = NULL;
while (e.pos < e.end) {
+ char *ns_name = NULL;
void *start;
error = verify_header(&e, e.pos == e.start, ns);
if (error)
goto fail;
start = e.pos;
- profile = unpack_profile(&e);
+ profile = unpack_profile(&e, &ns_name);
if (IS_ERR(profile)) {
error = PTR_ERR(profile);
goto fail;
}
ent->new = profile;
+ ent->ns_name = ns_name;
list_add_tail(&ent->list, lh);
}
udata->abi = e.version & K_ABI_MASK;