| 1 | |
| 2 | |
| 3 | * AppArmor security module
|
| 4 | *
|
| 5 | * This file contains AppArmor resource mediation and attachment
|
| 6 | *
|
| 7 | * Copyright (C) 1998-2008 Novell/SUSE
|
| 8 | * Copyright 2009-2010 Canonical Ltd.
|
| 9 |
|
| 10 |
|
| 11 | #include <linux/audit.h>
|
| 12 | #include <linux/security.h>
|
| 13 |
|
| 14 | #include "include/audit.h"
|
| 15 | #include "include/cred.h"
|
| 16 | #include "include/resource.h"
|
| 17 | #include "include/policy.h"
|
| 18 |
|
| 19 | |
| 20 | * Table of rlimit names: we generate it from resource.h.
|
| 21 |
|
| 22 | #include "rlim_names.h"
|
| 23 |
|
| 24 | struct aa_sfs_entry aa_sfs_entry_rlimit[] = {
|
| 25 | AA_SFS_FILE_STRING("mask", AA_SFS_RLIMIT_MASK),
|
| 26 | { }
|
| 27 | };
|
| 28 |
|
| 29 |
|
| 30 | static void audit_cb(struct audit_buffer *ab, void *va)
|
| 31 | {
|
| 32 | struct common_audit_data *sa = va;
|
| 33 | struct apparmor_audit_data *ad = aad(sa);
|
| 34 |
|
| 35 | audit_log_format(ab, " rlimit=%s value=%lu",
|
| 36 | rlim_names[ad->rlim.rlim], ad->rlim.max);
|
| 37 | if (ad->peer) {
|
| 38 | audit_log_format(ab, " peer=");
|
| 39 | aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer,
|
| 40 | FLAGS_NONE, GFP_ATOMIC);
|
| 41 | }
|
| 42 | }
|
| 43 |
|
| 44 | |
| 45 | * audit_resource - audit setting resource limit
|
| 46 | * @subj_cred: cred setting the resource
|
| 47 | * @profile: profile being enforced (NOT NULL)
|
| 48 | * @resource: rlimit being auditing
|
| 49 | * @value: value being set
|
| 50 | * @peer: aa_albel of the task being set
|
| 51 | * @info: info being auditing
|
| 52 | * @error: error value
|
| 53 | *
|
| 54 | * Returns: 0 or ad->error else other error code on failure
|
| 55 |
|
| 56 | static int audit_resource(const struct cred *subj_cred,
|
| 57 | struct aa_profile *profile, unsigned int resource,
|
| 58 | unsigned long value, struct aa_label *peer,
|
| 59 | const char *info, int error)
|
| 60 | {
|
| 61 | DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_RLIMITS,
|
| 62 | OP_SETRLIMIT);
|
| 63 |
|
| 64 | ad.subj_cred = subj_cred;
|
| 65 | ad.rlim.rlim = resource;
|
| 66 | ad.rlim.max = value;
|
| 67 | ad.peer = peer;
|
| 68 | ad.info = info;
|
| 69 | ad.error = error;
|
| 70 |
|
| 71 | return aa_audit(AUDIT_APPARMOR_AUTO, profile, &ad, audit_cb);
|
| 72 | }
|
| 73 |
|
| 74 | |
| 75 | * aa_map_resource - map compiled policy resource to internal #
|
| 76 | * @resource: flattened policy resource number
|
| 77 | *
|
| 78 | * Returns: resource # for the current architecture.
|
| 79 | *
|
| 80 | * rlimit resource can vary based on architecture, map the compiled policy
|
| 81 | * resource # to the internal representation for the architecture.
|
| 82 |
|
| 83 | int aa_map_resource(int resource)
|
| 84 | {
|
| 85 | return rlim_map[resource];
|
| 86 | }
|
| 87 |
|
| 88 | static int profile_setrlimit(const struct cred *subj_cred,
|
| 89 | struct aa_profile *profile, unsigned int resource,
|
| 90 | struct rlimit *new_rlim)
|
| 91 | {
|
| 92 | struct aa_ruleset *rules = profile->label.rules[0];
|
| 93 | int e = 0;
|
| 94 |
|
| 95 | if (rules->rlimits.mask & (1 << resource) && new_rlim->rlim_max >
|
| 96 | rules->rlimits.limits[resource].rlim_max)
|
| 97 | e = -EACCES;
|
| 98 | return audit_resource(subj_cred, profile, resource, new_rlim->rlim_max,
|
| 99 | NULL, NULL, e);
|
| 100 | }
|
| 101 |
|
| 102 | |
| 103 | * aa_task_setrlimit - test permission to set an rlimit
|
| 104 | * @subj_cred: cred setting the limit
|
| 105 | * @label: label confining the task (NOT NULL)
|
| 106 | * @task: task the resource is being set on
|
| 107 | * @resource: the resource being set
|
| 108 | * @new_rlim: the new resource limit (NOT NULL)
|
| 109 | *
|
| 110 | * Control raising the processes hard limit.
|
| 111 | *
|
| 112 | * Returns: 0 or error code if setting resource failed
|
| 113 |
|
| 114 | int aa_task_setrlimit(const struct cred *subj_cred, struct aa_label *label,
|
| 115 | struct task_struct *task,
|
| 116 | unsigned int resource, struct rlimit *new_rlim)
|
| 117 | {
|
| 118 | struct aa_profile *profile;
|
| 119 | struct aa_label *peer;
|
| 120 | int error = 0;
|
| 121 |
|
| 122 | rcu_read_lock();
|
| 123 | peer = aa_get_newest_cred_label(__task_cred(task));
|
| 124 | rcu_read_unlock();
|
| 125 |
|
| 126 | |
| 127 | * profiles. AppArmor rules currently have the implicit assumption
|
| 128 | * that the task is setting the resource of a task confined with
|
| 129 | * the same profile or that the task setting the resource of another
|
| 130 | * task has CAP_SYS_RESOURCE.
|
| 131 |
|
| 132 |
|
| 133 | if (label != peer &&
|
| 134 | aa_capable(subj_cred, label, CAP_SYS_RESOURCE, CAP_OPT_NOAUDIT) != 0)
|
| 135 | error = fn_for_each(label, profile,
|
| 136 | audit_resource(subj_cred, profile, resource,
|
| 137 | new_rlim->rlim_max, peer,
|
| 138 | "cap_sys_resource", -EACCES));
|
| 139 | else
|
| 140 | error = fn_for_each_confined(label, profile,
|
| 141 | profile_setrlimit(subj_cred, profile, resource,
|
| 142 | new_rlim));
|
| 143 | aa_put_label(peer);
|
| 144 |
|
| 145 | return error;
|
| 146 | }
|
| 147 |
|
| 148 | |
| 149 | * __aa_transition_rlimits - apply new profile rlimits
|
| 150 | * @old_l: old label on task (NOT NULL)
|
| 151 | * @new_l: new label with rlimits to apply (NOT NULL)
|
| 152 |
|
| 153 | void __aa_transition_rlimits(struct aa_label *old_l, struct aa_label *new_l)
|
| 154 | {
|
| 155 | unsigned int mask = 0;
|
| 156 | struct rlimit *rlim, *initrlim;
|
| 157 | struct aa_profile *old, *new;
|
| 158 | struct label_it i;
|
| 159 |
|
| 160 | old = labels_profile(old_l);
|
| 161 | new = labels_profile(new_l);
|
| 162 |
|
| 163 | |
| 164 | * to the lesser of the tasks hard limit and the init tasks soft limit
|
| 165 |
|
| 166 | label_for_each_confined(i, old_l, old) {
|
| 167 | struct aa_ruleset *rules = old->label.rules[0];
|
| 168 | if (rules->rlimits.mask) {
|
| 169 | int j;
|
| 170 |
|
| 171 | for (j = 0, mask = 1; j < RLIM_NLIMITS; j++,
|
| 172 | mask <<= 1) {
|
| 173 | if (rules->rlimits.mask & mask) {
|
| 174 | rlim = current->signal->rlim + j;
|
| 175 | initrlim = init_task.signal->rlim + j;
|
| 176 | rlim->rlim_cur = min(rlim->rlim_max,
|
| 177 | initrlim->rlim_cur);
|
| 178 | }
|
| 179 | }
|
| 180 | }
|
| 181 | }
|
| 182 |
|
| 183 |
|
| 184 | label_for_each_confined(i, new_l, new) {
|
| 185 | struct aa_ruleset *rules = new->label.rules[0];
|
| 186 | int j;
|
| 187 |
|
| 188 | if (!rules->rlimits.mask)
|
| 189 | continue;
|
| 190 | for (j = 0, mask = 1; j < RLIM_NLIMITS; j++, mask <<= 1) {
|
| 191 | if (!(rules->rlimits.mask & mask))
|
| 192 | continue;
|
| 193 |
|
| 194 | rlim = current->signal->rlim + j;
|
| 195 | rlim->rlim_max = min(rlim->rlim_max,
|
| 196 | rules->rlimits.limits[j].rlim_max);
|
| 197 |
|
| 198 | rlim->rlim_cur = min(rlim->rlim_cur, rlim->rlim_max);
|
| 199 | if (j == RLIMIT_CPU &&
|
| 200 | rlim->rlim_cur != RLIM_INFINITY &&
|
| 201 | IS_ENABLED(CONFIG_POSIX_TIMERS))
|
| 202 | (void) update_rlimit_cpu(current->group_leader,
|
| 203 | rlim->rlim_cur);
|
| 204 | }
|
| 205 | }
|
| 206 | }
|