int aa_new_mount(struct aa_label *label, const char *dev_name, const struct path *path, const char *type, unsigned long flags, void *data) { struct aa_profile *profile; char *buffer = NULL, *dev_buffer = NULL; bool binary = true; int error; int requires_dev = 0; struct path tmp_path, *dev_path = NULL; AA_BUG(!label); AA_BUG(!path); if (type) { struct file_system_type *fstype; fstype = get_fs_type(type); if (!fstype) return -ENODEV; binary = fstype->fs_flags & FS_BINARY_MOUNTDATA; requires_dev = fstype->fs_flags & FS_REQUIRES_DEV; put_filesystem(fstype); if (requires_dev) { if (!dev_name || !*dev_name) return -ENOENT; error = kern_path(dev_name, LOOKUP_FOLLOW, &tmp_path); if (error) return error; dev_path = &tmp_path; } } get_buffers(buffer, dev_buffer); if (dev_path) { error = fn_for_each_confined(label, profile, match_mnt(profile, path, buffer, dev_path, dev_buffer, type, flags, data, binary)); } else { error = fn_for_each_confined(label, profile, match_mnt_path_str(profile, path, buffer, dev_name, type, flags, data, binary, NULL)); } put_buffers(buffer, dev_buffer); if (dev_path) path_put(dev_path); return error; }
int aa_move_mount(struct aa_label *label, const struct path *path, const char *orig_name) { struct aa_profile *profile; char *buffer = NULL, *old_buffer = NULL; struct path old_path; int error; AA_BUG(!label); AA_BUG(!path); if (!orig_name || !*orig_name) return -EINVAL; error = kern_path(orig_name, LOOKUP_FOLLOW, &old_path); if (error) return error; get_buffers(buffer, old_buffer); error = fn_for_each_confined(label, profile, match_mnt(profile, path, buffer, &old_path, old_buffer, NULL, MS_MOVE, NULL, false)); put_buffers(buffer, old_buffer); path_put(&old_path); return error; }
int aa_bind_mount(struct aa_label *label, const struct path *path, const char *dev_name, unsigned long flags) { struct aa_profile *profile; char *buffer = NULL, *old_buffer = NULL; struct path old_path; int error; AA_BUG(!label); AA_BUG(!path); if (!dev_name || !*dev_name) return -EINVAL; flags &= MS_REC | MS_BIND; error = kern_path(dev_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path); if (error) return error; get_buffers(buffer, old_buffer); error = fn_for_each_confined(label, profile, match_mnt(profile, path, buffer, &old_path, old_buffer, NULL, flags, NULL, false)); put_buffers(buffer, old_buffer); path_put(&old_path); return error; }
int aa_af_perm(struct aa_label *label, int op, u32 request, u16 family, int type, int protocol, struct sock *sk) { struct aa_profile *profile; return fn_for_each_confined(label, profile, aa_profile_af_perm(profile, op, family, type, protocol, sk)); }
int apparmor_secmark_check(struct aa_label *label, char *op, u32 request, u32 secid, struct sock *sk) { struct aa_profile *profile; DEFINE_AUDIT_SK(sa, op, sk); return fn_for_each_confined(label, profile, aa_secmark_perm(profile, request, secid, &sa, sk)); }
int aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family, int type, int protocol) { struct aa_profile *profile; DEFINE_AUDIT_NET(sa, op, NULL, family, type, protocol); return fn_for_each_confined(label, profile, aa_profile_af_perm(profile, &sa, request, family, type)); }
/** * aa_capable - test permission to use capability * @label: label being tested for capability (NOT NULL) * @cap: capability to be tested * @audit: whether an audit record should be generated * * Look up capability in profile capability set. * * Returns: 0 on success, or else an error code. */ int aa_capable(struct aa_label *label, int cap, int audit) { struct aa_profile *profile; int error = 0; DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_CAP, OP_CAPABLE); sa.u.cap = cap; error = fn_for_each_confined(label, profile, profile_capable(profile, cap, audit ? &sa : NULL)); return error; }
/** * aa_capable - test permission to use capability * @label: label being tested for capability (NOT NULL) * @cap: capability to be tested * @opts: CAP_OPT_NOAUDIT bit determines whether audit record is generated * * Look up capability in profile capability set. * * Returns: 0 on success, or else an error code. */ int aa_capable(struct aa_label *label, int cap, unsigned int opts) { struct aa_profile *profile; int error = 0; DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_CAP, OP_CAPABLE); sa.u.cap = cap; error = fn_for_each_confined(label, profile, profile_capable(profile, cap, opts, &sa)); return error; }
static int aa_label_sk_perm(struct aa_label *label, int op, u32 request, struct sock *sk) { struct aa_profile *profile; AA_BUG(!label); AA_BUG(!sk); if (unconfined(label)) return 0; return fn_for_each_confined(label, profile, aa_profile_af_perm(profile, op, sk->sk_family, sk->sk_type, sk->sk_protocol, sk)); }
static int aa_label_sk_perm(struct aa_label *label, const char *op, u32 request, struct sock *sk) { int error = 0; AA_BUG(!label); AA_BUG(!sk); if (!unconfined(label)) { struct aa_profile *profile; DEFINE_AUDIT_SK(sa, op, sk); error = fn_for_each_confined(label, profile, aa_profile_af_sk_perm(profile, &sa, request, sk)); } return error; }
static int path_name(const char *op, struct aa_label *label, const struct path *path, int flags, char *buffer, const char **name, struct path_cond *cond, u32 request) { struct aa_profile *profile; const char *info = NULL; int error; error = aa_path_name(path, flags, buffer, name, &info, labels_profile(label)->disconnected); if (error) { fn_for_each_confined(label, profile, aa_audit_file(profile, &nullperms, op, request, *name, NULL, NULL, cond->uid, info, error)); return error; } return 0; }
int aa_remount(struct aa_label *label, const struct path *path, unsigned long flags, void *data) { struct aa_profile *profile; char *buffer = NULL; bool binary; int error; AA_BUG(!label); AA_BUG(!path); binary = path->dentry->d_sb->s_type->fs_flags & FS_BINARY_MOUNTDATA; get_buffers(buffer); error = fn_for_each_confined(label, profile, match_mnt(profile, path, buffer, NULL, NULL, NULL, flags, data, binary)); put_buffers(buffer); return error; }
int aa_mount_change_type(struct aa_label *label, const struct path *path, unsigned long flags) { struct aa_profile *profile; char *buffer = NULL; int error; AA_BUG(!label); AA_BUG(!path); /* These are the flags allowed by do_change_type() */ flags &= (MS_REC | MS_SILENT | MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE); get_buffers(buffer); error = fn_for_each_confined(label, profile, match_mnt(profile, path, buffer, NULL, NULL, NULL, flags, NULL, false)); put_buffers(buffer); return error; }
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; }