static void free_replacedby(struct aa_replacedby *r) { if (r) { /* r->label will not updated any more as r is dead */ aa_put_label(rcu_dereference_protected(r->label, true)); kzfree(r); } }
int aa_umount(struct aa_label *label, struct vfsmount *mnt, int flags) { struct aa_profile *profile; char *buffer = NULL; int error; struct path path = { .mnt = mnt, .dentry = mnt->mnt_root }; AA_BUG(!label); AA_BUG(!mnt); get_buffers(buffer); error = fn_for_each_confined(label, profile, profile_umount(profile, &path, buffer)); put_buffers(buffer); return error; } /* helper fn for transition on pivotroot * * Returns: label for transition or ERR_PTR. Does not return NULL */ static struct aa_label *build_pivotroot(struct aa_profile *profile, const struct path *new_path, char *new_buffer, const struct path *old_path, char *old_buffer) { const char *old_name, *new_name = NULL, *info = NULL; const char *trans_name = NULL; struct aa_perms perms = { }; unsigned int state; int error; AA_BUG(!profile); AA_BUG(!new_path); AA_BUG(!old_path); if (profile_unconfined(profile) || !PROFILE_MEDIATES(profile, AA_CLASS_MOUNT)) return aa_get_newest_label(&profile->label); error = aa_path_name(old_path, path_flags(profile, old_path), old_buffer, &old_name, &info, profile->disconnected); if (error) goto audit; error = aa_path_name(new_path, path_flags(profile, new_path), new_buffer, &new_name, &info, profile->disconnected); if (error) goto audit; error = -EACCES; state = aa_dfa_match(profile->policy.dfa, profile->policy.start[AA_CLASS_MOUNT], new_name); state = aa_dfa_null_transition(profile->policy.dfa, state); state = aa_dfa_match(profile->policy.dfa, state, old_name); perms = compute_mnt_perms(profile->policy.dfa, state); if (AA_MAY_PIVOTROOT & perms.allow) error = 0; audit: error = audit_mount(profile, OP_PIVOTROOT, new_name, old_name, NULL, trans_name, 0, NULL, AA_MAY_PIVOTROOT, &perms, info, error); if (error) return ERR_PTR(error); return aa_get_newest_label(&profile->label); } int aa_pivotroot(struct aa_label *label, const struct path *old_path, const struct path *new_path) { struct aa_profile *profile; struct aa_label *target = NULL; char *old_buffer = NULL, *new_buffer = NULL, *info = NULL; int error; AA_BUG(!label); AA_BUG(!old_path); AA_BUG(!new_path); get_buffers(old_buffer, new_buffer); target = fn_label_build(label, profile, GFP_ATOMIC, build_pivotroot(profile, new_path, new_buffer, old_path, old_buffer)); if (!target) { info = "label build failed"; error = -ENOMEM; goto fail; } else if (!IS_ERR(target)) { error = aa_replace_current_label(target); if (error) { /* TODO: audit target */ aa_put_label(target); goto out; } } else /* already audited error */ error = PTR_ERR(target); out: put_buffers(old_buffer, new_buffer); return error; fail: /* TODO: add back in auditing of new_name and old_name */ error = fn_for_each(label, profile, audit_mount(profile, OP_PIVOTROOT, NULL /*new_name */, NULL /* old_name */, NULL, NULL, 0, NULL, AA_MAY_PIVOTROOT, &nullperms, info, error)); goto out; }
/* * put the associated labels */ static void apparmor_cred_free(struct cred *cred) { aa_put_label(cred_label(cred)); cred_label(cred) = NULL; }