Skip to content

Commit 29caf07

Browse files
committed
Merge tag 'apparmor-pr-2024-11-27' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor
Pull apparmor updates from John Johansen: "Features: - extend next/check table to add support for 2^24 states to the state machine. - rework capability audit cache to use broader cred information instead of just the profile. Also add a time stamp so old entries can be aged out of the cache. Bug Fixes: - fix 'Do simple duplicate message elimination' to clear previous state when updating in capability audit cache - Fix memory leak for aa_unpack_strdup() - properly handle cx/px lookup failure when in complain mode - allocate xmatch for nullpdb inside aa_alloc_null fixing a NULL ptr deref of tracking profiles in when in complain mode Cleanups: - Remove everything being reported as deadcode - replace misleading 'scrubbing environment' phrase in debug print - Remove unnecessary NULL check before kvfree() - clean up duplicated parts of handle_onexec() - Use IS_ERR_OR_NULL() helper function - move new_profile declaration to top of block instead immediately after label to remove C23 extension warning Documentation: - add comment to document capability.c:profile_capable ad ptr parameter can not be NULL - add comment to document first entry is in packed perms struct is reserved for future planned expansion. - Update LSM/apparmor.rst add blurb for DEFAULT_SECURITY_APPARMOR" * tag 'apparmor-pr-2024-11-27' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor: apparmor: lift new_profile declaration to remove C23 extension warning apparmor: replace misleading 'scrubbing environment' phrase in debug print parser: drop dead code for XXX_comb macros apparmor: Remove unused parameter L1 in macro next_comb Docs: Update LSM/apparmor.rst apparmor: audit_cap dedup based on subj_cred instead of profile apparmor: add a cache entry expiration time aging out capability audit cache apparmor: document capability.c:profile_capable ad ptr not being NULL apparmor: fix 'Do simple duplicate message elimination' apparmor: document first entry is in packed perms struct is reserved apparmor: test: Fix memory leak for aa_unpack_strdup() apparmor: Remove deadcode apparmor: Remove unnecessary NULL check before kvfree() apparmor: domain: clean up duplicated parts of handle_onexec() apparmor: Use IS_ERR_OR_NULL() helper function apparmor: add support for 2^24 states to the dfa state machine. apparmor: properly handle cx/px lookup failure for complain apparmor: allocate xmatch for nullpdb inside aa_alloc_null
2 parents 509f806 + 04b5f0a commit 29caf07

File tree

18 files changed

+141
-246
lines changed

18 files changed

+141
-246
lines changed

Documentation/admin-guide/LSM/apparmor.rst

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@ set ``CONFIG_SECURITY_APPARMOR=y``
1818

1919
If AppArmor should be selected as the default security module then set::
2020

21-
CONFIG_DEFAULT_SECURITY="apparmor"
22-
CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1
21+
CONFIG_DEFAULT_SECURITY_APPARMOR=y
22+
23+
The CONFIG_LSM parameter manages the order and selection of LSMs.
24+
Specify apparmor as the first "major" module (e.g. AppArmor, SELinux, Smack)
25+
in the list.
2326

2427
Build the kernel
2528

security/apparmor/apparmorfs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2366,6 +2366,7 @@ static struct aa_sfs_entry aa_sfs_entry_policy[] = {
23662366
AA_SFS_FILE_U64("outofband", MAX_OOB_SUPPORTED),
23672367
AA_SFS_FILE_U64("permstable32_version", 1),
23682368
AA_SFS_FILE_STRING("permstable32", PERMS32STR),
2369+
AA_SFS_FILE_U64("state32", 1),
23692370
AA_SFS_DIR("unconfined_restrictions", aa_sfs_entry_unconfined),
23702371
{ }
23712372
};

security/apparmor/capability.c

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <linux/errno.h>
1313
#include <linux/gfp.h>
1414
#include <linux/security.h>
15+
#include <linux/timekeeping.h>
1516

1617
#include "include/apparmor.h"
1718
#include "include/capability.h"
@@ -30,8 +31,9 @@ struct aa_sfs_entry aa_sfs_entry_caps[] = {
3031
};
3132

3233
struct audit_cache {
33-
struct aa_profile *profile;
34-
kernel_cap_t caps;
34+
const struct cred *ad_subj_cred;
35+
/* Capabilities go from 0 to CAP_LAST_CAP */
36+
u64 ktime_ns_expiration[CAP_LAST_CAP+1];
3537
};
3638

3739
static DEFINE_PER_CPU(struct audit_cache, audit_cache);
@@ -64,6 +66,8 @@ static void audit_cb(struct audit_buffer *ab, void *va)
6466
static int audit_caps(struct apparmor_audit_data *ad, struct aa_profile *profile,
6567
int cap, int error)
6668
{
69+
const u64 AUDIT_CACHE_TIMEOUT_NS = 1000*1000*1000; /* 1 second */
70+
6771
struct aa_ruleset *rules = list_first_entry(&profile->rules,
6872
typeof(*rules), list);
6973
struct audit_cache *ent;
@@ -89,15 +93,16 @@ static int audit_caps(struct apparmor_audit_data *ad, struct aa_profile *profile
8993

9094
/* Do simple duplicate message elimination */
9195
ent = &get_cpu_var(audit_cache);
92-
if (profile == ent->profile && cap_raised(ent->caps, cap)) {
96+
/* If the capability was never raised the timestamp check would also catch that */
97+
if (ad->subj_cred == ent->ad_subj_cred && ktime_get_ns() <= ent->ktime_ns_expiration[cap]) {
9398
put_cpu_var(audit_cache);
9499
if (COMPLAIN_MODE(profile))
95100
return complain_error(error);
96101
return error;
97102
} else {
98-
aa_put_profile(ent->profile);
99-
ent->profile = aa_get_profile(profile);
100-
cap_raise(ent->caps, cap);
103+
put_cred(ent->ad_subj_cred);
104+
ent->ad_subj_cred = get_cred(ad->subj_cred);
105+
ent->ktime_ns_expiration[cap] = ktime_get_ns() + AUDIT_CACHE_TIMEOUT_NS;
101106
}
102107
put_cpu_var(audit_cache);
103108

@@ -109,7 +114,7 @@ static int audit_caps(struct apparmor_audit_data *ad, struct aa_profile *profile
109114
* @profile: profile being enforced (NOT NULL, NOT unconfined)
110115
* @cap: capability to test if allowed
111116
* @opts: CAP_OPT_NOAUDIT bit determines whether audit record is generated
112-
* @ad: audit data (MAY BE NULL indicating no auditing)
117+
* @ad: audit data (NOT NULL)
113118
*
114119
* Returns: 0 if allowed else -EPERM
115120
*/

security/apparmor/domain.c

Lines changed: 28 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,7 @@ static struct aa_label *profile_transition(const struct cred *subj_cred,
636636
struct aa_ruleset *rules = list_first_entry(&profile->rules,
637637
typeof(*rules), list);
638638
struct aa_label *new = NULL;
639+
struct aa_profile *new_profile = NULL;
639640
const char *info = NULL, *name = NULL, *target = NULL;
640641
aa_state_t state = rules->file->start[AA_CLASS_FILE];
641642
struct aa_perms perms = {};
@@ -680,15 +681,18 @@ static struct aa_label *profile_transition(const struct cred *subj_cred,
680681
/* hack ix fallback - improve how this is detected */
681682
goto audit;
682683
} else if (!new) {
683-
error = -EACCES;
684684
info = "profile transition not found";
685-
/* remove MAY_EXEC to audit as failure */
685+
/* remove MAY_EXEC to audit as failure or complaint */
686686
perms.allow &= ~MAY_EXEC;
687+
if (COMPLAIN_MODE(profile)) {
688+
/* create null profile instead of failing */
689+
goto create_learning_profile;
690+
}
691+
error = -EACCES;
687692
}
688693
} else if (COMPLAIN_MODE(profile)) {
694+
create_learning_profile:
689695
/* no exec permission - learning mode */
690-
struct aa_profile *new_profile = NULL;
691-
692696
new_profile = aa_new_learning_profile(profile, false, name,
693697
GFP_KERNEL);
694698
if (!new_profile) {
@@ -709,8 +713,8 @@ static struct aa_label *profile_transition(const struct cred *subj_cred,
709713

710714
if (!(perms.xindex & AA_X_UNSAFE)) {
711715
if (DEBUG_ON) {
712-
dbg_printk("apparmor: scrubbing environment variables"
713-
" for %s profile=", name);
716+
dbg_printk("apparmor: setting AT_SECURE for %s profile=",
717+
name);
714718
aa_label_printk(new, GFP_KERNEL);
715719
dbg_printk("\n");
716720
}
@@ -789,8 +793,8 @@ static int profile_onexec(const struct cred *subj_cred,
789793

790794
if (!(perms.xindex & AA_X_UNSAFE)) {
791795
if (DEBUG_ON) {
792-
dbg_printk("apparmor: scrubbing environment "
793-
"variables for %s label=", xname);
796+
dbg_printk("apparmor: setting AT_SECURE for %s label=",
797+
xname);
794798
aa_label_printk(onexec, GFP_KERNEL);
795799
dbg_printk("\n");
796800
}
@@ -821,33 +825,19 @@ static struct aa_label *handle_onexec(const struct cred *subj_cred,
821825
AA_BUG(!bprm);
822826
AA_BUG(!buffer);
823827

824-
if (!stack) {
825-
error = fn_for_each_in_ns(label, profile,
826-
profile_onexec(subj_cred, profile, onexec, stack,
827-
bprm, buffer, cond, unsafe));
828-
if (error)
829-
return ERR_PTR(error);
830-
new = fn_label_build_in_ns(label, profile, GFP_KERNEL,
831-
aa_get_newest_label(onexec),
832-
profile_transition(subj_cred, profile, bprm,
833-
buffer,
834-
cond, unsafe));
835-
836-
} else {
837-
/* TODO: determine how much we want to loosen this */
838-
error = fn_for_each_in_ns(label, profile,
839-
profile_onexec(subj_cred, profile, onexec, stack, bprm,
840-
buffer, cond, unsafe));
841-
if (error)
842-
return ERR_PTR(error);
843-
new = fn_label_build_in_ns(label, profile, GFP_KERNEL,
844-
aa_label_merge(&profile->label, onexec,
845-
GFP_KERNEL),
846-
profile_transition(subj_cred, profile, bprm,
847-
buffer,
848-
cond, unsafe));
849-
}
828+
/* TODO: determine how much we want to loosen this */
829+
error = fn_for_each_in_ns(label, profile,
830+
profile_onexec(subj_cred, profile, onexec, stack,
831+
bprm, buffer, cond, unsafe));
832+
if (error)
833+
return ERR_PTR(error);
850834

835+
new = fn_label_build_in_ns(label, profile, GFP_KERNEL,
836+
stack ? aa_label_merge(&profile->label, onexec,
837+
GFP_KERNEL)
838+
: aa_get_newest_label(onexec),
839+
profile_transition(subj_cred, profile, bprm,
840+
buffer, cond, unsafe));
851841
if (new)
852842
return new;
853843

@@ -960,8 +950,8 @@ int apparmor_bprm_creds_for_exec(struct linux_binprm *bprm)
960950

961951
if (unsafe) {
962952
if (DEBUG_ON) {
963-
dbg_printk("scrubbing environment variables for %s "
964-
"label=", bprm->filename);
953+
dbg_printk("setting AT_SECURE for %s label=",
954+
bprm->filename);
965955
aa_label_printk(new, GFP_KERNEL);
966956
dbg_printk("\n");
967957
}
@@ -971,8 +961,8 @@ int apparmor_bprm_creds_for_exec(struct linux_binprm *bprm)
971961
if (label->proxy != new->proxy) {
972962
/* when transitioning clear unsafe personality bits */
973963
if (DEBUG_ON) {
974-
dbg_printk("apparmor: clearing unsafe personality "
975-
"bits. %s label=", bprm->filename);
964+
dbg_printk("apparmor: clearing unsafe personality bits. %s label=",
965+
bprm->filename);
976966
aa_label_printk(new, GFP_KERNEL);
977967
dbg_printk("\n");
978968
}

security/apparmor/include/label.h

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -160,31 +160,7 @@ int aa_label_next_confined(struct aa_label *l, int i);
160160
#define label_for_each_cont(I, L, P) \
161161
for (++((I).i); ((P) = (L)->vec[(I).i]); ++((I).i))
162162

163-
#define next_comb(I, L1, L2) \
164-
do { \
165-
(I).j++; \
166-
if ((I).j >= (L2)->size) { \
167-
(I).i++; \
168-
(I).j = 0; \
169-
} \
170-
} while (0)
171-
172163

173-
/* for each combination of P1 in L1, and P2 in L2 */
174-
#define label_for_each_comb(I, L1, L2, P1, P2) \
175-
for ((I).i = (I).j = 0; \
176-
((P1) = (L1)->vec[(I).i]) && ((P2) = (L2)->vec[(I).j]); \
177-
(I) = next_comb(I, L1, L2))
178-
179-
#define fn_for_each_comb(L1, L2, P1, P2, FN) \
180-
({ \
181-
struct label_it i; \
182-
int __E = 0; \
183-
label_for_each_comb(i, (L1), (L2), (P1), (P2)) { \
184-
last_error(__E, (FN)); \
185-
} \
186-
__E; \
187-
})
188164

189165
/* for each profile that is enforcing confinement in a label */
190166
#define label_for_each_confined(I, L, P) \
@@ -291,8 +267,6 @@ bool aa_label_replace(struct aa_label *old, struct aa_label *new);
291267
bool aa_label_make_newest(struct aa_labelset *ls, struct aa_label *old,
292268
struct aa_label *new);
293269

294-
struct aa_label *aa_label_find(struct aa_label *l);
295-
296270
struct aa_profile *aa_label_next_in_merge(struct label_it *I,
297271
struct aa_label *a,
298272
struct aa_label *b);
@@ -320,8 +294,6 @@ void aa_label_seq_xprint(struct seq_file *f, struct aa_ns *ns,
320294
struct aa_label *label, int flags, gfp_t gfp);
321295
void aa_label_xprintk(struct aa_ns *ns, struct aa_label *label, int flags,
322296
gfp_t gfp);
323-
void aa_label_audit(struct audit_buffer *ab, struct aa_label *label, gfp_t gfp);
324-
void aa_label_seq_print(struct seq_file *f, struct aa_label *label, gfp_t gfp);
325297
void aa_label_printk(struct aa_label *label, gfp_t gfp);
326298

327299
struct aa_label *aa_label_strn_parse(struct aa_label *base, const char *str,

security/apparmor/include/lib.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ extern int apparmor_initialized;
5959

6060
/* fn's in lib */
6161
const char *skipn_spaces(const char *str, size_t n);
62-
char *aa_split_fqname(char *args, char **ns_name);
6362
const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name,
6463
size_t *ns_len);
6564
void aa_info_message(const char *str);

security/apparmor/include/match.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,12 @@ struct table_header {
8787
char td_data[];
8888
};
8989

90-
#define DEFAULT_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_DEF]->td_data))
90+
#define TABLE_DATAU16(TABLE) ((u16 *)((TABLE)->td_data))
91+
#define TABLE_DATAU32(TABLE) ((u32 *)((TABLE)->td_data))
92+
#define DEFAULT_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_DEF]->td_data))
9193
#define BASE_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_BASE]->td_data))
92-
#define NEXT_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_NXT]->td_data))
93-
#define CHECK_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_CHK]->td_data))
94+
#define NEXT_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_NXT]->td_data))
95+
#define CHECK_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_CHK]->td_data))
9496
#define EQUIV_TABLE(DFA) ((u8 *)((DFA)->tables[YYTD_ID_EC]->td_data))
9597
#define ACCEPT_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT]->td_data))
9698
#define ACCEPT_TABLE2(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT2]->td_data))

security/apparmor/include/perms.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -213,9 +213,6 @@ void aa_perms_accum_raw(struct aa_perms *accum, struct aa_perms *addend);
213213
void aa_profile_match_label(struct aa_profile *profile,
214214
struct aa_ruleset *rules, struct aa_label *label,
215215
int type, u32 request, struct aa_perms *perms);
216-
int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target,
217-
u32 request, int type, u32 *deny,
218-
struct apparmor_audit_data *ad);
219216
int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms,
220217
u32 request, struct apparmor_audit_data *ad,
221218
void (*cb)(struct audit_buffer *, void *));

security/apparmor/include/policy.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,6 @@ void aa_free_profile(struct aa_profile *profile);
264264
struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name);
265265
struct aa_profile *aa_lookupn_profile(struct aa_ns *ns, const char *hname,
266266
size_t n);
267-
struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *name);
268267
struct aa_profile *aa_fqlookupn_profile(struct aa_label *base,
269268
const char *fqname, size_t n);
270269

security/apparmor/include/secid.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,5 @@ void apparmor_release_secctx(char *secdata, u32 seclen);
3434

3535
int aa_alloc_secid(struct aa_label *label, gfp_t gfp);
3636
void aa_free_secid(u32 secid);
37-
void aa_secid_update(u32 secid, struct aa_label *label);
3837

3938
#endif /* __AA_SECID_H */

0 commit comments

Comments
 (0)