Skip to content

Commit 281f36d

Browse files
committed
Merge tag 'apparmor-pr-mainline-2026-03-09' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor
Pull AppArmor fixes from John Johansen: - fix race between freeing data and fs accessing it - fix race on unreferenced rawdata dereference - fix differential encoding verification - fix unconfined unprivileged local user can do privileged policy management - Fix double free of ns_name in aa_replace_profiles() - fix missing bounds check on DEFAULT table in verify_dfa() - fix side-effect bug in match_char() macro usage - fix: limit the number of levels of policy namespaces - replace recursive profile removal with iterative approach - fix memory leak in verify_header - validate DFA start states are in bounds in unpack_pdb * tag 'apparmor-pr-mainline-2026-03-09' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor: apparmor: fix race between freeing data and fs accessing it apparmor: fix race on rawdata dereference apparmor: fix differential encoding verification apparmor: fix unprivileged local user can do privileged policy management apparmor: Fix double free of ns_name in aa_replace_profiles() apparmor: fix missing bounds check on DEFAULT table in verify_dfa() apparmor: fix side-effect bug in match_char() macro usage apparmor: fix: limit the number of levels of policy namespaces apparmor: replace recursive profile removal with iterative approach apparmor: fix memory leak in verify_header apparmor: validate DFA start states are in bounds in unpack_pdb
2 parents 80234b5 + 8e135b8 commit 281f36d

12 files changed

Lines changed: 363 additions & 176 deletions

File tree

security/apparmor/apparmorfs.c

Lines changed: 134 additions & 91 deletions
Large diffs are not rendered by default.

security/apparmor/include/label.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ enum label_flags {
102102

103103
struct aa_label;
104104
struct aa_proxy {
105-
struct kref count;
105+
struct aa_common_ref count;
106106
struct aa_label __rcu *label;
107107
};
108108

@@ -125,7 +125,7 @@ struct label_it {
125125
* vec: vector of profiles comprising the compound label
126126
*/
127127
struct aa_label {
128-
struct kref count;
128+
struct aa_common_ref count;
129129
struct rb_node node;
130130
struct rcu_head rcu;
131131
struct aa_proxy *proxy;
@@ -357,7 +357,7 @@ int aa_label_match(struct aa_profile *profile, struct aa_ruleset *rules,
357357
*/
358358
static inline struct aa_label *__aa_get_label(struct aa_label *l)
359359
{
360-
if (l && kref_get_unless_zero(&l->count))
360+
if (l && kref_get_unless_zero(&l->count.count))
361361
return l;
362362

363363
return NULL;
@@ -366,7 +366,7 @@ static inline struct aa_label *__aa_get_label(struct aa_label *l)
366366
static inline struct aa_label *aa_get_label(struct aa_label *l)
367367
{
368368
if (l)
369-
kref_get(&(l->count));
369+
kref_get(&(l->count.count));
370370

371371
return l;
372372
}
@@ -386,7 +386,7 @@ static inline struct aa_label *aa_get_label_rcu(struct aa_label __rcu **l)
386386
rcu_read_lock();
387387
do {
388388
c = rcu_dereference(*l);
389-
} while (c && !kref_get_unless_zero(&c->count));
389+
} while (c && !kref_get_unless_zero(&c->count.count));
390390
rcu_read_unlock();
391391

392392
return c;
@@ -426,7 +426,7 @@ static inline struct aa_label *aa_get_newest_label(struct aa_label *l)
426426
static inline void aa_put_label(struct aa_label *l)
427427
{
428428
if (l)
429-
kref_put(&l->count, aa_label_kref);
429+
kref_put(&l->count.count, aa_label_kref);
430430
}
431431

432432
/* wrapper fn to indicate semantics of the check */
@@ -443,15 +443,15 @@ void aa_proxy_kref(struct kref *kref);
443443
static inline struct aa_proxy *aa_get_proxy(struct aa_proxy *proxy)
444444
{
445445
if (proxy)
446-
kref_get(&(proxy->count));
446+
kref_get(&(proxy->count.count));
447447

448448
return proxy;
449449
}
450450

451451
static inline void aa_put_proxy(struct aa_proxy *proxy)
452452
{
453453
if (proxy)
454-
kref_put(&proxy->count, aa_proxy_kref);
454+
kref_put(&proxy->count.count, aa_proxy_kref);
455455
}
456456

457457
void __aa_proxy_redirect(struct aa_label *orig, struct aa_label *new);

security/apparmor/include/lib.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,18 @@ void aa_info_message(const char *str);
102102
/* Security blob offsets */
103103
extern struct lsm_blob_sizes apparmor_blob_sizes;
104104

105+
enum reftype {
106+
REF_NS,
107+
REF_PROXY,
108+
REF_RAWDATA,
109+
};
110+
111+
/* common reference count used by data the shows up in aafs */
112+
struct aa_common_ref {
113+
struct kref count;
114+
enum reftype reftype;
115+
};
116+
105117
/**
106118
* aa_strneq - compare null terminated @str to a non null terminated substring
107119
* @str: a null terminated string

security/apparmor/include/match.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ static inline void aa_put_dfa(struct aa_dfa *dfa)
185185
#define MATCH_FLAG_DIFF_ENCODE 0x80000000
186186
#define MARK_DIFF_ENCODE 0x40000000
187187
#define MATCH_FLAG_OOB_TRANSITION 0x20000000
188+
#define MARK_DIFF_ENCODE_VERIFIED 0x10000000
188189
#define MATCH_FLAGS_MASK 0xff000000
189190
#define MATCH_FLAGS_VALID (MATCH_FLAG_DIFF_ENCODE | MATCH_FLAG_OOB_TRANSITION)
190191
#define MATCH_FLAGS_INVALID (MATCH_FLAGS_MASK & ~MATCH_FLAGS_VALID)

security/apparmor/include/policy.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ static inline bool profile_mediates_safe(struct aa_profile *profile,
379379
static inline struct aa_profile *aa_get_profile(struct aa_profile *p)
380380
{
381381
if (p)
382-
kref_get(&(p->label.count));
382+
kref_get(&(p->label.count.count));
383383

384384
return p;
385385
}
@@ -393,7 +393,7 @@ static inline struct aa_profile *aa_get_profile(struct aa_profile *p)
393393
*/
394394
static inline struct aa_profile *aa_get_profile_not0(struct aa_profile *p)
395395
{
396-
if (p && kref_get_unless_zero(&p->label.count))
396+
if (p && kref_get_unless_zero(&p->label.count.count))
397397
return p;
398398

399399
return NULL;
@@ -413,7 +413,7 @@ static inline struct aa_profile *aa_get_profile_rcu(struct aa_profile __rcu **p)
413413
rcu_read_lock();
414414
do {
415415
c = rcu_dereference(*p);
416-
} while (c && !kref_get_unless_zero(&c->label.count));
416+
} while (c && !kref_get_unless_zero(&c->label.count.count));
417417
rcu_read_unlock();
418418

419419
return c;
@@ -426,7 +426,7 @@ static inline struct aa_profile *aa_get_profile_rcu(struct aa_profile __rcu **p)
426426
static inline void aa_put_profile(struct aa_profile *p)
427427
{
428428
if (p)
429-
kref_put(&p->label.count, aa_label_kref);
429+
kref_put(&p->label.count.count, aa_label_kref);
430430
}
431431

432432
static inline int AUDIT_MODE(struct aa_profile *profile)
@@ -443,7 +443,7 @@ bool aa_policy_admin_capable(const struct cred *subj_cred,
443443
struct aa_label *label, struct aa_ns *ns);
444444
int aa_may_manage_policy(const struct cred *subj_cred,
445445
struct aa_label *label, struct aa_ns *ns,
446-
u32 mask);
446+
const struct cred *ocred, u32 mask);
447447
bool aa_current_policy_view_capable(struct aa_ns *ns);
448448
bool aa_current_policy_admin_capable(struct aa_ns *ns);
449449

security/apparmor/include/policy_ns.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#include "label.h"
1919
#include "policy.h"
2020

21+
/* Match max depth of user namespaces */
22+
#define MAX_NS_DEPTH 32
2123

2224
/* struct aa_ns_acct - accounting of profiles in namespace
2325
* @max_size: maximum space allowed for all profiles in namespace

security/apparmor/include/policy_unpack.h

Lines changed: 45 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -87,17 +87,29 @@ struct aa_ext {
8787
u32 version;
8888
};
8989

90-
/*
91-
* struct aa_loaddata - buffer of policy raw_data set
90+
/* struct aa_loaddata - buffer of policy raw_data set
91+
* @count: inode/filesystem refcount - use aa_get_i_loaddata()
92+
* @pcount: profile refcount - use aa_get_profile_loaddata()
93+
* @list: list the loaddata is on
94+
* @work: used to do a delayed cleanup
95+
* @dents: refs to dents created in aafs
96+
* @ns: the namespace this loaddata was loaded into
97+
* @name:
98+
* @size: the size of the data that was loaded
99+
* @compressed_size: the size of the data when it is compressed
100+
* @revision: unique revision count that this data was loaded as
101+
* @abi: the abi number the loaddata uses
102+
* @hash: a hash of the loaddata, used to help dedup data
92103
*
93-
* there is no loaddata ref for being on ns list, nor a ref from
94-
* d_inode(@dentry) when grab a ref from these, @ns->lock must be held
95-
* && __aa_get_loaddata() needs to be used, and the return value
96-
* checked, if NULL the loaddata is already being reaped and should be
97-
* considered dead.
104+
* There is no loaddata ref for being on ns->rawdata_list, so
105+
* @ns->lock must be held when walking the list. Dentries and
106+
* inode opens hold refs on @count; profiles hold refs on @pcount.
107+
* When the last @pcount drops, do_ploaddata_rmfs() removes the
108+
* fs entries and drops the associated @count ref.
98109
*/
99110
struct aa_loaddata {
100-
struct kref count;
111+
struct aa_common_ref count;
112+
struct kref pcount;
101113
struct list_head list;
102114
struct work_struct work;
103115
struct dentry *dents[AAFS_LOADDATA_NDENTS];
@@ -119,50 +131,53 @@ struct aa_loaddata {
119131
int aa_unpack(struct aa_loaddata *udata, struct list_head *lh, const char **ns);
120132

121133
/**
122-
* __aa_get_loaddata - get a reference count to uncounted data reference
134+
* aa_get_loaddata - get a reference count from a counted data reference
123135
* @data: reference to get a count on
124136
*
125-
* Returns: pointer to reference OR NULL if race is lost and reference is
126-
* being repeated.
127-
* Requires: @data->ns->lock held, and the return code MUST be checked
128-
*
129-
* Use only from inode->i_private and @data->list found references
137+
* Returns: pointer to reference
138+
* Requires: @data to have a valid reference count on it. It is a bug
139+
* if the race to reap can be encountered when it is used.
130140
*/
131141
static inline struct aa_loaddata *
132-
__aa_get_loaddata(struct aa_loaddata *data)
142+
aa_get_i_loaddata(struct aa_loaddata *data)
133143
{
134-
if (data && kref_get_unless_zero(&(data->count)))
135-
return data;
136144

137-
return NULL;
145+
if (data)
146+
kref_get(&(data->count.count));
147+
return data;
138148
}
139149

150+
140151
/**
141-
* aa_get_loaddata - get a reference count from a counted data reference
152+
* aa_get_profile_loaddata - get a profile reference count on loaddata
142153
* @data: reference to get a count on
143154
*
144-
* Returns: point to reference
145-
* Requires: @data to have a valid reference count on it. It is a bug
146-
* if the race to reap can be encountered when it is used.
155+
* Returns: pointer to reference
156+
* Requires: @data to have a valid reference count on it.
147157
*/
148158
static inline struct aa_loaddata *
149-
aa_get_loaddata(struct aa_loaddata *data)
159+
aa_get_profile_loaddata(struct aa_loaddata *data)
150160
{
151-
struct aa_loaddata *tmp = __aa_get_loaddata(data);
152-
153-
AA_BUG(data && !tmp);
154-
155-
return tmp;
161+
if (data)
162+
kref_get(&(data->pcount));
163+
return data;
156164
}
157165

158166
void __aa_loaddata_update(struct aa_loaddata *data, long revision);
159167
bool aa_rawdata_eq(struct aa_loaddata *l, struct aa_loaddata *r);
160168
void aa_loaddata_kref(struct kref *kref);
169+
void aa_ploaddata_kref(struct kref *kref);
161170
struct aa_loaddata *aa_loaddata_alloc(size_t size);
162-
static inline void aa_put_loaddata(struct aa_loaddata *data)
171+
static inline void aa_put_i_loaddata(struct aa_loaddata *data)
172+
{
173+
if (data)
174+
kref_put(&data->count.count, aa_loaddata_kref);
175+
}
176+
177+
static inline void aa_put_profile_loaddata(struct aa_loaddata *data)
163178
{
164179
if (data)
165-
kref_put(&data->count, aa_loaddata_kref);
180+
kref_put(&data->pcount, aa_ploaddata_kref);
166181
}
167182

168183
#if IS_ENABLED(CONFIG_KUNIT)

security/apparmor/label.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ static void free_proxy(struct aa_proxy *proxy)
5252

5353
void aa_proxy_kref(struct kref *kref)
5454
{
55-
struct aa_proxy *proxy = container_of(kref, struct aa_proxy, count);
55+
struct aa_proxy *proxy = container_of(kref, struct aa_proxy,
56+
count.count);
5657

5758
free_proxy(proxy);
5859
}
@@ -63,7 +64,8 @@ struct aa_proxy *aa_alloc_proxy(struct aa_label *label, gfp_t gfp)
6364

6465
new = kzalloc_obj(struct aa_proxy, gfp);
6566
if (new) {
66-
kref_init(&new->count);
67+
kref_init(&new->count.count);
68+
new->count.reftype = REF_PROXY;
6769
rcu_assign_pointer(new->label, aa_get_label(label));
6870
}
6971
return new;
@@ -375,7 +377,8 @@ static void label_free_rcu(struct rcu_head *head)
375377

376378
void aa_label_kref(struct kref *kref)
377379
{
378-
struct aa_label *label = container_of(kref, struct aa_label, count);
380+
struct aa_label *label = container_of(kref, struct aa_label,
381+
count.count);
379382
struct aa_ns *ns = labels_ns(label);
380383

381384
if (!ns) {
@@ -412,7 +415,8 @@ bool aa_label_init(struct aa_label *label, int size, gfp_t gfp)
412415

413416
label->size = size; /* doesn't include null */
414417
label->vec[size] = NULL; /* null terminate */
415-
kref_init(&label->count);
418+
kref_init(&label->count.count);
419+
label->count.reftype = REF_NS; /* for aafs purposes */
416420
RB_CLEAR_NODE(&label->node);
417421

418422
return true;

0 commit comments

Comments
 (0)