Skip to content

Commit ce9e3b3

Browse files
committed
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>
1 parent a9eb185 commit ce9e3b3

File tree

3 files changed

+62
-6
lines changed

3 files changed

+62
-6
lines changed

security/apparmor/capability.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
struct aa_sfs_entry aa_sfs_entry_caps[] = {
2929
AA_SFS_FILE_STRING("mask", AA_SFS_CAPS_MASK),
30+
AA_SFS_FILE_BOOLEAN("extended", 1),
3031
{ }
3132
};
3233

@@ -123,8 +124,31 @@ static int profile_capable(struct aa_profile *profile, int cap,
123124
{
124125
struct aa_ruleset *rules = list_first_entry(&profile->rules,
125126
typeof(*rules), list);
127+
aa_state_t state;
126128
int error;
127129

130+
state = RULE_MEDIATES(rules, ad->class);
131+
if (state) {
132+
struct aa_perms perms = { };
133+
u32 request;
134+
135+
/* caps broken into 256 x 32 bit permission chunks */
136+
state = aa_dfa_next(rules->policy->dfa, state, cap >> 5);
137+
request = 1 << (cap & 0x1f);
138+
perms = *aa_lookup_perms(rules->policy, state);
139+
aa_apply_modes_to_perms(profile, &perms);
140+
141+
if (opts & CAP_OPT_NOAUDIT) {
142+
if (perms.complain & request)
143+
ad->info = "optional: no audit";
144+
else
145+
ad = NULL;
146+
}
147+
return aa_check_perms(profile, &perms, request, ad,
148+
audit_cb);
149+
}
150+
151+
/* fallback to old caps mediation that doesn't support conditionals */
128152
if (cap_raised(rules->caps.allow, cap) &&
129153
!cap_raised(rules->caps.denied, cap))
130154
error = 0;
@@ -168,3 +192,35 @@ int aa_capable(const struct cred *subj_cred, struct aa_label *label,
168192

169193
return error;
170194
}
195+
196+
kernel_cap_t aa_profile_capget(struct aa_profile *profile)
197+
{
198+
struct aa_ruleset *rules = list_first_entry(&profile->rules,
199+
typeof(*rules), list);
200+
aa_state_t state;
201+
202+
state = RULE_MEDIATES(rules, AA_CLASS_CAP);
203+
if (state) {
204+
kernel_cap_t caps = CAP_EMPTY_SET;
205+
int i;
206+
207+
/* caps broken into up to 256, 32 bit permission chunks */
208+
for (i = 0; i < (CAP_LAST_CAP >> 5); i++) {
209+
struct aa_perms perms = { };
210+
aa_state_t tmp;
211+
212+
tmp = aa_dfa_next(rules->policy->dfa, state, i);
213+
perms = *aa_lookup_perms(rules->policy, tmp);
214+
aa_apply_modes_to_perms(profile, &perms);
215+
caps.val |= ((u64)(perms.allow)) << (i * 5);
216+
caps.val |= ((u64)(perms.complain)) << (i * 5);
217+
}
218+
return caps;
219+
}
220+
221+
/* fallback to old caps */
222+
if (COMPLAIN_MODE(profile))
223+
return CAP_FULL_SET;
224+
225+
return rules->caps.allow;
226+
}

security/apparmor/include/capability.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ struct aa_caps {
3636

3737
extern struct aa_sfs_entry aa_sfs_entry_caps[];
3838

39+
kernel_cap_t aa_profile_capget(struct aa_profile *profile);
3940
int aa_capable(const struct cred *subj_cred, struct aa_label *label,
4041
int cap, unsigned int opts);
4142

security/apparmor/lsm.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -177,14 +177,13 @@ static int apparmor_capget(const struct task_struct *target, kernel_cap_t *effec
177177

178178
label_for_each_confined(i, label, profile) {
179179
struct aa_ruleset *rules;
180-
if (COMPLAIN_MODE(profile))
181-
continue;
180+
kernel_cap_t allowed;
181+
182182
rules = list_first_entry(&profile->rules,
183183
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);
188187
}
189188
}
190189
rcu_read_unlock();

0 commit comments

Comments
 (0)