Skip to content

Commit 219d766

Browse files
committed
Merge tag 'apparmor-pr-2026-02-18' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor
Pull AppArmor updates from John Johansen: "Features: - add .kunitconfig - audit execpath in userns mediation - add support loading per permission tagging Cleanups: - remove unused percpu critical sections in buffer management - document the buffer hold, add an overflow guard - split xxx_in_ns into its two separate semantic use cases - remove apply_modes_to_perms from label_match - refactor/cleanup cred helper fns. - guard against free attachment/data routines being called with NULL - drop in_atomic flag in common_mmap, common_file_perm, and cleanup - make str table more generic and be able to have multiple entries - Replace deprecated strcpy with memcpy in gen_symlink_name - Replace deprecated strcpy in d_namespace_path - Replace sprintf/strcpy with scnprintf/strscpy in aa_policy_init - replace sprintf with snprintf in aa_new_learning_profile Bug Fixes: - fix cast in format string DEBUG statement - fix make aa_labelmatch return consistent - fix fmt string type error in process_strs_entry - fix kernel-doc comments for inview - fix invalid deref of rawdata when export_binary is unset - avoid per-cpu hold underflow in aa_get_buffer - fix fast path cache check for unix sockets - fix rlimit for posix cpu timers - fix label and profile debug macros - move check for aa_null file to cover all cases - return -ENOMEM in unpack_perms_table upon alloc failure - fix boolean argument in apparmor_mmap_file - Fix & Optimize table creation from possibly unaligned memory - Allow apparmor to handle unaligned dfa tables - fix NULL deref in aa_sock_file_perm - fix NULL pointer dereference in __unix_needs_revalidation - fix signedness bug in unpack_tags()" * tag 'apparmor-pr-2026-02-18' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor: (34 commits) apparmor: fix signedness bug in unpack_tags() apparmor: fix cast in format string DEBUG statement apparmor: fix aa_label to return state from compount and component match apparmor: fix fmt string type error in process_strs_entry apparmor: fix kernel-doc comments for inview apparmor: fix invalid deref of rawdata when export_binary is unset apparmor: add .kunitconfig apparmor: cleanup remove unused percpu critical sections in buffer management apparmor: document the buffer hold, add an overflow guard apparmor: avoid per-cpu hold underflow in aa_get_buffer apparmor: split xxx_in_ns into its two separate semantic use cases apparmor: make label_match return a consistent value apparmor: remove apply_modes_to_perms from label_match apparmor: fix fast path cache check for unix sockets apparmor: fix rlimit for posix cpu timers apparmor: refactor/cleanup cred helper fns. apparmor: fix label and profile debug macros apparmor: move check for aa_null file to cover all cases apparmor: guard against free routines being called with a NULL apparmor: return -ENOMEM in unpack_perms_table upon alloc failure ...
2 parents 43257b2 + 08020db commit 219d766

21 files changed

Lines changed: 687 additions & 240 deletions

security/apparmor/.kunitconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
CONFIG_KUNIT=y
2+
CONFIG_NET=y
3+
CONFIG_SECURITY=y
4+
CONFIG_SECURITY_APPARMOR=y
5+
CONFIG_SECURITY_APPARMOR_KUNIT_TEST=y

security/apparmor/af_unix.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ static int profile_peer_perm(struct aa_profile *profile, u32 request,
416416
unix_sk(sk),
417417
peer_addr, peer_addrlen, &p, &ad->info);
418418

419-
return fn_for_each_in_ns(peer_label, peerp,
419+
return fn_for_each_in_scope(peer_label, peerp,
420420
match_label(profile, rules, state, request,
421421
peerp, p, ad));
422422
}

security/apparmor/apparmorfs.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -801,7 +801,7 @@ static ssize_t query_label(char *buf, size_t buf_len,
801801

802802
perms = allperms;
803803
if (view_only) {
804-
label_for_each_in_ns(i, labels_ns(label), label, profile) {
804+
label_for_each_in_scope(i, labels_ns(label), label, profile) {
805805
profile_query_cb(profile, &perms, match_str, match_len);
806806
}
807807
} else {
@@ -1607,16 +1607,20 @@ static char *gen_symlink_name(int depth, const char *dirname, const char *fname)
16071607
{
16081608
char *buffer, *s;
16091609
int error;
1610-
int size = depth * 6 + strlen(dirname) + strlen(fname) + 11;
1610+
const char *path = "../../";
1611+
size_t path_len = strlen(path);
1612+
int size;
16111613

1614+
/* Extra 11 bytes: "raw_data" (9) + two slashes "//" (2) */
1615+
size = depth * path_len + strlen(dirname) + strlen(fname) + 11;
16121616
s = buffer = kmalloc(size, GFP_KERNEL);
16131617
if (!buffer)
16141618
return ERR_PTR(-ENOMEM);
16151619

16161620
for (; depth > 0; depth--) {
1617-
strcpy(s, "../../");
1618-
s += 6;
1619-
size -= 6;
1621+
memcpy(s, path, path_len);
1622+
s += path_len;
1623+
size -= path_len;
16201624
}
16211625

16221626
error = snprintf(s, size, "raw_data/%s/%s", dirname, fname);
@@ -1644,6 +1648,15 @@ static const char *rawdata_get_link_base(struct dentry *dentry,
16441648

16451649
label = aa_get_label_rcu(&proxy->label);
16461650
profile = labels_profile(label);
1651+
1652+
/* rawdata can be null when aa_g_export_binary is unset during
1653+
* runtime and a profile is replaced
1654+
*/
1655+
if (!profile->rawdata) {
1656+
aa_put_label(label);
1657+
return ERR_PTR(-ENOENT);
1658+
}
1659+
16471660
depth = profile_depth(profile);
16481661
target = gen_symlink_name(depth, profile->rawdata->name, name);
16491662
aa_put_label(label);

security/apparmor/domain.c

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ static inline aa_state_t match_component(struct aa_profile *profile,
115115
* @label: label to check access permissions for
116116
* @stack: whether this is a stacking request
117117
* @state: state to start match in
118-
* @subns: whether to do permission checks on components in a subns
118+
* @inview: whether to match labels in view or only in scope
119119
* @request: permissions to request
120120
* @perms: perms struct to set
121121
*
@@ -127,17 +127,17 @@ static inline aa_state_t match_component(struct aa_profile *profile,
127127
*/
128128
static int label_compound_match(struct aa_profile *profile,
129129
struct aa_label *label, bool stack,
130-
aa_state_t state, bool subns, u32 request,
130+
aa_state_t state, bool inview, u32 request,
131131
struct aa_perms *perms)
132132
{
133133
struct aa_ruleset *rules = profile->label.rules[0];
134134
struct aa_profile *tp;
135135
struct label_it i;
136136
struct path_cond cond = { };
137137

138-
/* find first subcomponent that is visible */
138+
/* find first subcomponent that is in view and going to be interated with */
139139
label_for_each(i, label, tp) {
140-
if (!aa_ns_visible(profile->ns, tp->ns, subns))
140+
if (!aa_ns_visible(profile->ns, tp->ns, inview))
141141
continue;
142142
state = match_component(profile, tp, stack, state);
143143
if (!state)
@@ -151,7 +151,7 @@ static int label_compound_match(struct aa_profile *profile,
151151

152152
next:
153153
label_for_each_cont(i, label, tp) {
154-
if (!aa_ns_visible(profile->ns, tp->ns, subns))
154+
if (!aa_ns_visible(profile->ns, tp->ns, inview))
155155
continue;
156156
state = aa_dfa_match(rules->file->dfa, state, "//&");
157157
state = match_component(profile, tp, false, state);
@@ -177,7 +177,7 @@ static int label_compound_match(struct aa_profile *profile,
177177
* @label: label to check access permissions for
178178
* @stack: whether this is a stacking request
179179
* @start: state to start match in
180-
* @subns: whether to do permission checks on components in a subns
180+
* @inview: whether to match labels in view or only in scope
181181
* @request: permissions to request
182182
* @perms: an initialized perms struct to add accumulation to
183183
*
@@ -189,7 +189,7 @@ static int label_compound_match(struct aa_profile *profile,
189189
*/
190190
static int label_components_match(struct aa_profile *profile,
191191
struct aa_label *label, bool stack,
192-
aa_state_t start, bool subns, u32 request,
192+
aa_state_t start, bool inview, u32 request,
193193
struct aa_perms *perms)
194194
{
195195
struct aa_ruleset *rules = profile->label.rules[0];
@@ -201,7 +201,7 @@ static int label_components_match(struct aa_profile *profile,
201201

202202
/* find first subcomponent to test */
203203
label_for_each(i, label, tp) {
204-
if (!aa_ns_visible(profile->ns, tp->ns, subns))
204+
if (!aa_ns_visible(profile->ns, tp->ns, inview))
205205
continue;
206206
state = match_component(profile, tp, stack, start);
207207
if (!state)
@@ -218,7 +218,7 @@ static int label_components_match(struct aa_profile *profile,
218218
aa_apply_modes_to_perms(profile, &tmp);
219219
aa_perms_accum(perms, &tmp);
220220
label_for_each_cont(i, label, tp) {
221-
if (!aa_ns_visible(profile->ns, tp->ns, subns))
221+
if (!aa_ns_visible(profile->ns, tp->ns, inview))
222222
continue;
223223
state = match_component(profile, tp, stack, start);
224224
if (!state)
@@ -245,26 +245,26 @@ static int label_components_match(struct aa_profile *profile,
245245
* @label: label to match (NOT NULL)
246246
* @stack: whether this is a stacking request
247247
* @state: state to start in
248-
* @subns: whether to match subns components
248+
* @inview: whether to match labels in view or only in scope
249249
* @request: permission request
250250
* @perms: Returns computed perms (NOT NULL)
251251
*
252252
* Returns: the state the match finished in, may be the none matching state
253253
*/
254254
static int label_match(struct aa_profile *profile, struct aa_label *label,
255-
bool stack, aa_state_t state, bool subns, u32 request,
255+
bool stack, aa_state_t state, bool inview, u32 request,
256256
struct aa_perms *perms)
257257
{
258258
int error;
259259

260260
*perms = nullperms;
261-
error = label_compound_match(profile, label, stack, state, subns,
261+
error = label_compound_match(profile, label, stack, state, inview,
262262
request, perms);
263263
if (!error)
264264
return error;
265265

266266
*perms = allperms;
267-
return label_components_match(profile, label, stack, state, subns,
267+
return label_components_match(profile, label, stack, state, inview,
268268
request, perms);
269269
}
270270

@@ -529,7 +529,7 @@ struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex,
529529
/* TODO: move lookup parsing to unpack time so this is a straight
530530
* index into the resultant label
531531
*/
532-
for (next = rules->file->trans.table[index]; next;
532+
for (next = rules->file->trans.table[index].strs; next;
533533
next = next_name(xtype, next)) {
534534
const char *lookup = (*next == '&') ? next + 1 : next;
535535
*name = next;
@@ -880,14 +880,16 @@ static struct aa_label *handle_onexec(const struct cred *subj_cred,
880880
AA_BUG(!bprm);
881881
AA_BUG(!buffer);
882882

883-
/* TODO: determine how much we want to loosen this */
884-
error = fn_for_each_in_ns(label, profile,
883+
/* TODO: determine how much we want to loosen this
884+
* only check profiles in scope for permission to change at exec
885+
*/
886+
error = fn_for_each_in_scope(label, profile,
885887
profile_onexec(subj_cred, profile, onexec, stack,
886888
bprm, buffer, cond, unsafe));
887889
if (error)
888890
return ERR_PTR(error);
889891

890-
new = fn_label_build_in_ns(label, profile, GFP_KERNEL,
892+
new = fn_label_build_in_scope(label, profile, GFP_KERNEL,
891893
stack ? aa_label_merge(&profile->label, onexec,
892894
GFP_KERNEL)
893895
: aa_get_newest_label(onexec),
@@ -897,7 +899,7 @@ static struct aa_label *handle_onexec(const struct cred *subj_cred,
897899
return new;
898900

899901
/* TODO: get rid of GLOBAL_ROOT_UID */
900-
error = fn_for_each_in_ns(label, profile,
902+
error = fn_for_each_in_scope(label, profile,
901903
aa_audit_file(subj_cred, profile, &nullperms,
902904
OP_CHANGE_ONEXEC,
903905
AA_MAY_ONEXEC, bprm->filename, NULL,
@@ -1123,7 +1125,7 @@ static struct aa_label *change_hat(const struct cred *subj_cred,
11231125
/*find first matching hat */
11241126
for (i = 0; i < count && !hat; i++) {
11251127
name = hats[i];
1126-
label_for_each_in_ns(it, labels_ns(label), label, profile) {
1128+
label_for_each_in_scope(it, labels_ns(label), label, profile) {
11271129
if (sibling && PROFILE_IS_HAT(profile)) {
11281130
root = aa_get_profile_rcu(&profile->parent);
11291131
} else if (!sibling && !PROFILE_IS_HAT(profile)) {
@@ -1159,7 +1161,7 @@ static struct aa_label *change_hat(const struct cred *subj_cred,
11591161
* change_hat.
11601162
*/
11611163
name = NULL;
1162-
label_for_each_in_ns(it, labels_ns(label), label, profile) {
1164+
label_for_each_in_scope(it, labels_ns(label), label, profile) {
11631165
if (!list_empty(&profile->base.profiles)) {
11641166
info = "hat not found";
11651167
error = -ENOENT;
@@ -1170,7 +1172,7 @@ static struct aa_label *change_hat(const struct cred *subj_cred,
11701172
error = -ECHILD;
11711173

11721174
fail:
1173-
label_for_each_in_ns(it, labels_ns(label), label, profile) {
1175+
label_for_each_in_scope(it, labels_ns(label), label, profile) {
11741176
/*
11751177
* no target as it has failed to be found or built
11761178
*
@@ -1188,7 +1190,7 @@ static struct aa_label *change_hat(const struct cred *subj_cred,
11881190
return ERR_PTR(error);
11891191

11901192
build:
1191-
new = fn_label_build_in_ns(label, profile, GFP_KERNEL,
1193+
new = fn_label_build_in_scope(label, profile, GFP_KERNEL,
11921194
build_change_hat(subj_cred, profile, name,
11931195
sibling),
11941196
aa_get_label(&profile->label));
@@ -1251,7 +1253,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags)
12511253
bool empty = true;
12521254

12531255
rcu_read_lock();
1254-
label_for_each_in_ns(i, labels_ns(label), label, profile) {
1256+
label_for_each_in_scope(i, labels_ns(label), label, profile) {
12551257
empty &= list_empty(&profile->base.profiles);
12561258
}
12571259
rcu_read_unlock();
@@ -1338,7 +1340,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags)
13381340
perms.kill = AA_MAY_CHANGEHAT;
13391341

13401342
fail:
1341-
fn_for_each_in_ns(label, profile,
1343+
fn_for_each_in_scope(label, profile,
13421344
aa_audit_file(subj_cred, profile, &perms, OP_CHANGE_HAT,
13431345
AA_MAY_CHANGEHAT, NULL, NULL, target,
13441346
GLOBAL_ROOT_UID, info, error));
@@ -1446,7 +1448,7 @@ int aa_change_profile(const char *fqname, int flags)
14461448
*/
14471449
stack = true;
14481450
perms.audit = request;
1449-
(void) fn_for_each_in_ns(label, profile,
1451+
(void) fn_for_each_in_scope(label, profile,
14501452
aa_audit_file(subj_cred, profile, &perms, op,
14511453
request, auditname, NULL, target,
14521454
GLOBAL_ROOT_UID, stack_msg, 0));
@@ -1492,7 +1494,7 @@ int aa_change_profile(const char *fqname, int flags)
14921494
*
14931495
* if (!stack) {
14941496
*/
1495-
error = fn_for_each_in_ns(label, profile,
1497+
error = fn_for_each_in_scope(label, profile,
14961498
change_profile_perms_wrapper(op, auditname,
14971499
subj_cred,
14981500
profile, target, stack,
@@ -1506,7 +1508,7 @@ int aa_change_profile(const char *fqname, int flags)
15061508
check:
15071509
/* check if tracing task is allowed to trace target domain */
15081510
error = may_change_ptraced_domain(subj_cred, target, &info);
1509-
if (error && !fn_for_each_in_ns(label, profile,
1511+
if (error && !fn_for_each_in_scope(label, profile,
15101512
COMPLAIN_MODE(profile)))
15111513
goto audit;
15121514

@@ -1522,7 +1524,7 @@ int aa_change_profile(const char *fqname, int flags)
15221524

15231525
/* stacking is always a subset, so only check the nonstack case */
15241526
if (!stack) {
1525-
new = fn_label_build_in_ns(label, profile, GFP_KERNEL,
1527+
new = fn_label_build_in_scope(label, profile, GFP_KERNEL,
15261528
aa_get_label(target),
15271529
aa_get_label(&profile->label));
15281530
/*
@@ -1565,7 +1567,7 @@ int aa_change_profile(const char *fqname, int flags)
15651567
}
15661568

15671569
audit:
1568-
error = fn_for_each_in_ns(label, profile,
1570+
error = fn_for_each_in_scope(label, profile,
15691571
aa_audit_file(subj_cred,
15701572
profile, &perms, op, request, auditname,
15711573
NULL, new ? new : target,

0 commit comments

Comments
 (0)