Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

apparmor: move resource checks to using labels

Signed-off-by: John Johansen <john.johansen@canonical.com>

+79 -41
+2 -2
security/apparmor/include/resource.h
··· 37 37 extern struct aa_sfs_entry aa_sfs_entry_rlimit[]; 38 38 39 39 int aa_map_resource(int resource); 40 - int aa_task_setrlimit(struct aa_profile *profile, struct task_struct *, 40 + int aa_task_setrlimit(struct aa_label *label, struct task_struct *task, 41 41 unsigned int resource, struct rlimit *new_rlim); 42 42 43 - void __aa_transition_rlimits(struct aa_profile *old, struct aa_profile *new); 43 + void __aa_transition_rlimits(struct aa_label *old, struct aa_label *new); 44 44 45 45 static inline void aa_free_rlimit_rules(struct aa_rlimit *rlims) 46 46 {
+2 -4
security/apparmor/lsm.c
··· 625 625 current->pdeath_signal = 0; 626 626 627 627 /* reset soft limits and set hard limits for the new label */ 628 - __aa_transition_rlimits(labels_profile(label), 629 - labels_profile(new_ctx->label)); 628 + __aa_transition_rlimits(label, new_ctx->label); 630 629 } 631 630 632 631 /** ··· 645 646 int error = 0; 646 647 647 648 if (!unconfined(label)) 648 - error = aa_task_setrlimit(labels_profile(label), task, 649 - resource, new_rlim); 649 + error = aa_task_setrlimit(label, task, resource, new_rlim); 650 650 __end_current_label_crit_section(label); 651 651 652 652 return error;
+75 -35
security/apparmor/resource.c
··· 13 13 */ 14 14 15 15 #include <linux/audit.h> 16 + #include <linux/security.h> 16 17 17 18 #include "include/audit.h" 18 19 #include "include/context.h" ··· 37 36 38 37 audit_log_format(ab, " rlimit=%s value=%lu", 39 38 rlim_names[aad(sa)->rlim.rlim], aad(sa)->rlim.max); 39 + if (aad(sa)->peer) { 40 + audit_log_format(ab, " peer="); 41 + aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer, 42 + FLAGS_NONE, GFP_ATOMIC); 43 + } 40 44 } 41 45 42 46 /** ··· 54 48 * Returns: 0 or sa->error else other error code on failure 55 49 */ 56 50 static int audit_resource(struct aa_profile *profile, unsigned int resource, 57 - unsigned long value, int error) 51 + unsigned long value, struct aa_label *peer, 52 + const char *info, int error) 58 53 { 59 54 DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_SETRLIMIT); 60 55 61 56 aad(&sa)->rlim.rlim = resource; 62 57 aad(&sa)->rlim.max = value; 58 + aad(&sa)->peer = peer; 59 + aad(&sa)->info = info; 63 60 aad(&sa)->error = error; 61 + 64 62 return aa_audit(AUDIT_APPARMOR_AUTO, profile, &sa, audit_cb); 65 63 } 66 64 ··· 82 72 return rlim_map[resource]; 83 73 } 84 74 75 + static int profile_setrlimit(struct aa_profile *profile, unsigned int resource, 76 + struct rlimit *new_rlim) 77 + { 78 + int e = 0; 79 + 80 + if (profile->rlimits.mask & (1 << resource) && new_rlim->rlim_max > 81 + profile->rlimits.limits[resource].rlim_max) 82 + e = -EACCES; 83 + return audit_resource(profile, resource, new_rlim->rlim_max, NULL, NULL, 84 + e); 85 + } 86 + 85 87 /** 86 88 * aa_task_setrlimit - test permission to set an rlimit 87 - * @profile - profile confining the task (NOT NULL) 89 + * @label - label confining the task (NOT NULL) 88 90 * @task - task the resource is being set on 89 91 * @resource - the resource being set 90 92 * @new_rlim - the new resource limit (NOT NULL) ··· 105 83 * 106 84 * Returns: 0 or error code if setting resource failed 107 85 */ 108 - int aa_task_setrlimit(struct aa_profile *profile, struct task_struct *task, 86 + int aa_task_setrlimit(struct aa_label *label, struct task_struct *task, 109 87 unsigned int resource, struct rlimit *new_rlim) 110 88 { 111 - struct aa_label *task_label; 89 + struct aa_profile *profile; 90 + struct aa_label *peer; 112 91 int error = 0; 113 92 114 93 rcu_read_lock(); 115 - task_label = aa_get_newest_cred_label((__task_cred(task))); 94 + peer = aa_get_newest_cred_label(__task_cred(task)); 116 95 rcu_read_unlock(); 117 96 118 97 /* TODO: extend resource control to handle other (non current) ··· 122 99 * the same profile or that the task setting the resource of another 123 100 * task has CAP_SYS_RESOURCE. 124 101 */ 125 - if ((profile != labels_profile(task_label) && 126 - aa_capable(&profile->label, CAP_SYS_RESOURCE, 1)) || 127 - (profile->rlimits.mask & (1 << resource) && 128 - new_rlim->rlim_max > profile->rlimits.limits[resource].rlim_max)) 129 - error = -EACCES; 130 102 131 - aa_put_label(task_label); 103 + if (label != peer && 104 + !aa_capable(label, CAP_SYS_RESOURCE, SECURITY_CAP_NOAUDIT)) 105 + error = fn_for_each(label, profile, 106 + audit_resource(profile, resource, 107 + new_rlim->rlim_max, peer, 108 + "cap_sys_resoure", -EACCES)); 109 + else 110 + error = fn_for_each_confined(label, profile, 111 + profile_setrlimit(profile, resource, new_rlim)); 112 + aa_put_label(peer); 132 113 133 - return audit_resource(profile, resource, new_rlim->rlim_max, error); 114 + return error; 134 115 } 135 116 136 117 /** 137 118 * __aa_transition_rlimits - apply new profile rlimits 138 - * @old: old profile on task (NOT NULL) 139 - * @new: new profile with rlimits to apply (NOT NULL) 119 + * @old_l: old label on task (NOT NULL) 120 + * @new_l: new label with rlimits to apply (NOT NULL) 140 121 */ 141 - void __aa_transition_rlimits(struct aa_profile *old, struct aa_profile *new) 122 + void __aa_transition_rlimits(struct aa_label *old_l, struct aa_label *new_l) 142 123 { 143 124 unsigned int mask = 0; 144 125 struct rlimit *rlim, *initrlim; 145 - int i; 126 + struct aa_profile *old, *new; 127 + struct label_it i; 146 128 147 - /* for any rlimits the profile controlled reset the soft limit 148 - * to the less of the tasks hard limit and the init tasks soft limit 129 + old = labels_profile(old_l); 130 + new = labels_profile(new_l); 131 + 132 + /* for any rlimits the profile controlled, reset the soft limit 133 + * to the lesser of the tasks hard limit and the init tasks soft limit 149 134 */ 150 - if (old->rlimits.mask) { 151 - for (i = 0, mask = 1; i < RLIM_NLIMITS; i++, mask <<= 1) { 152 - if (old->rlimits.mask & mask) { 153 - rlim = current->signal->rlim + i; 154 - initrlim = init_task.signal->rlim + i; 155 - rlim->rlim_cur = min(rlim->rlim_max, 156 - initrlim->rlim_cur); 135 + label_for_each_confined(i, old_l, old) { 136 + if (old->rlimits.mask) { 137 + int j; 138 + 139 + for (j = 0, mask = 1; j < RLIM_NLIMITS; j++, 140 + mask <<= 1) { 141 + if (old->rlimits.mask & mask) { 142 + rlim = current->signal->rlim + j; 143 + initrlim = init_task.signal->rlim + j; 144 + rlim->rlim_cur = min(rlim->rlim_max, 145 + initrlim->rlim_cur); 146 + } 157 147 } 158 148 } 159 149 } 160 150 161 151 /* set any new hard limits as dictated by the new profile */ 162 - if (!new->rlimits.mask) 163 - return; 164 - for (i = 0, mask = 1; i < RLIM_NLIMITS; i++, mask <<= 1) { 165 - if (!(new->rlimits.mask & mask)) 166 - continue; 152 + label_for_each_confined(i, new_l, new) { 153 + int j; 167 154 168 - rlim = current->signal->rlim + i; 169 - rlim->rlim_max = min(rlim->rlim_max, 170 - new->rlimits.limits[i].rlim_max); 171 - /* soft limit should not exceed hard limit */ 172 - rlim->rlim_cur = min(rlim->rlim_cur, rlim->rlim_max); 155 + if (!new->rlimits.mask) 156 + continue; 157 + for (j = 0, mask = 1; j < RLIM_NLIMITS; j++, mask <<= 1) { 158 + if (!(new->rlimits.mask & mask)) 159 + continue; 160 + 161 + rlim = current->signal->rlim + j; 162 + rlim->rlim_max = min(rlim->rlim_max, 163 + new->rlimits.limits[j].rlim_max); 164 + /* soft limit should not exceed hard limit */ 165 + rlim->rlim_cur = min(rlim->rlim_cur, rlim->rlim_max); 166 + } 173 167 } 174 168 }