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

Configure Feed

Select the types of activity you want to include in your feed.

apparmor: add ability to mediate caps with policy state machine

Currently the caps encoding is very limited and can't be used with
conditionals. Allow capabilities to be mediated by the state
machine. This will allow us to add conditionals to capabilities that
aren't possible with the current encoding.

This patch only adds support for using the state machine and retains
the old encoding lookup as part of the runtime mediation code to
support older policy abis. A follow on patch will move backwards
compatibility to a mapping function done at policy load time.

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

+62 -6
+56
security/apparmor/capability.c
··· 27 27 28 28 struct aa_sfs_entry aa_sfs_entry_caps[] = { 29 29 AA_SFS_FILE_STRING("mask", AA_SFS_CAPS_MASK), 30 + AA_SFS_FILE_BOOLEAN("extended", 1), 30 31 { } 31 32 }; 32 33 ··· 124 123 { 125 124 struct aa_ruleset *rules = list_first_entry(&profile->rules, 126 125 typeof(*rules), list); 126 + aa_state_t state; 127 127 int error; 128 128 129 + state = RULE_MEDIATES(rules, ad->class); 130 + if (state) { 131 + struct aa_perms perms = { }; 132 + u32 request; 133 + 134 + /* caps broken into 256 x 32 bit permission chunks */ 135 + state = aa_dfa_next(rules->policy->dfa, state, cap >> 5); 136 + request = 1 << (cap & 0x1f); 137 + perms = *aa_lookup_perms(rules->policy, state); 138 + aa_apply_modes_to_perms(profile, &perms); 139 + 140 + if (opts & CAP_OPT_NOAUDIT) { 141 + if (perms.complain & request) 142 + ad->info = "optional: no audit"; 143 + else 144 + ad = NULL; 145 + } 146 + return aa_check_perms(profile, &perms, request, ad, 147 + audit_cb); 148 + } 149 + 150 + /* fallback to old caps mediation that doesn't support conditionals */ 129 151 if (cap_raised(rules->caps.allow, cap) && 130 152 !cap_raised(rules->caps.denied, cap)) 131 153 error = 0; ··· 191 167 profile_capable(profile, cap, opts, &ad)); 192 168 193 169 return error; 170 + } 171 + 172 + kernel_cap_t aa_profile_capget(struct aa_profile *profile) 173 + { 174 + struct aa_ruleset *rules = list_first_entry(&profile->rules, 175 + typeof(*rules), list); 176 + aa_state_t state; 177 + 178 + state = RULE_MEDIATES(rules, AA_CLASS_CAP); 179 + if (state) { 180 + kernel_cap_t caps = CAP_EMPTY_SET; 181 + int i; 182 + 183 + /* caps broken into up to 256, 32 bit permission chunks */ 184 + for (i = 0; i < (CAP_LAST_CAP >> 5); i++) { 185 + struct aa_perms perms = { }; 186 + aa_state_t tmp; 187 + 188 + tmp = aa_dfa_next(rules->policy->dfa, state, i); 189 + perms = *aa_lookup_perms(rules->policy, tmp); 190 + aa_apply_modes_to_perms(profile, &perms); 191 + caps.val |= ((u64)(perms.allow)) << (i * 5); 192 + caps.val |= ((u64)(perms.complain)) << (i * 5); 193 + } 194 + return caps; 195 + } 196 + 197 + /* fallback to old caps */ 198 + if (COMPLAIN_MODE(profile)) 199 + return CAP_FULL_SET; 200 + 201 + return rules->caps.allow; 194 202 }
+1
security/apparmor/include/capability.h
··· 36 36 37 37 extern struct aa_sfs_entry aa_sfs_entry_caps[]; 38 38 39 + kernel_cap_t aa_profile_capget(struct aa_profile *profile); 39 40 int aa_capable(const struct cred *subj_cred, struct aa_label *label, 40 41 int cap, unsigned int opts); 41 42
+5 -6
security/apparmor/lsm.c
··· 177 177 178 178 label_for_each_confined(i, label, profile) { 179 179 struct aa_ruleset *rules; 180 - if (COMPLAIN_MODE(profile)) 181 - continue; 180 + kernel_cap_t allowed; 181 + 182 182 rules = list_first_entry(&profile->rules, 183 183 typeof(*rules), list); 184 - *effective = cap_intersect(*effective, 185 - rules->caps.allow); 186 - *permitted = cap_intersect(*permitted, 187 - rules->caps.allow); 184 + allowed = aa_profile_capget(profile); 185 + *effective = cap_intersect(*effective, allowed); 186 + *permitted = cap_intersect(*permitted, allowed); 188 187 } 189 188 } 190 189 rcu_read_unlock();