* FAILED: patch "[PATCH] apparmor: fix out-of-bounds write when null terminating a" failed to apply to 6.6-stable tree
@ 2026-09-03 11:07 gregkh
2026-09-04 10:29 ` [PATCH 6.6.y] apparmor: fix out-of-bounds write when null terminating a label vec Sasha Levin
0 siblings, 1 reply; 2+ messages in thread
From: gregkh @ 2026-09-03 11:07 UTC (permalink / raw)
To: imv4bel, john.johansen; +Cc: stable
The patch below does not apply to the 6.6-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable@vger.kernel.org>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.6.y
git checkout FETCH_HEAD
git cherry-pick -x 9f1e40193eef7f047e6b77cfb4b4cafdecd7a123
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<stable@vger.kernel.org>' --in-reply-to '2026090321-librarian-canopy-80fd@gregkh' --subject-prefix 'PATCH 6.6.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 9f1e40193eef7f047e6b77cfb4b4cafdecd7a123 Mon Sep 17 00:00:00 2001
From: Hyunwoo Kim <imv4bel@gmail.com>
Date: Mon, 10 Aug 2026 18:51:33 +0900
Subject: [PATCH] apparmor: fix out-of-bounds write when null terminating a
label vec
aa_vec_unique() null terminates at vec[n - dups] when VEC_FLAG_TERMINATE
is passed. If the components are all distinct no duplicates are dropped,
dups is 0 and the terminator goes to vec[n], so the caller has to provide
room for n + 1 entries.
aa_label_strn_parse() sets up its vector with vec_setup(profile, vec, len,
gfp) and then calls aa_vec_unique(vec, len, VEC_FLAG_TERMINATE), but
vec_setup() does not reserve the terminator entry. Up to LOCAL_VEC_ENTRIES
it uses the local array of LOCAL_VEC_ENTRIES pointers, above that it
allocates exactly len pointers. The terminator therefore lands one entry
past the end of the local array when len is LOCAL_VEC_ENTRIES, and one
entry past the end of the allocation when len is larger.
len comes from the number of "//&" separated components in the label name
and label_count_strn_entries() does not bound it. An unprivileged task
reaches the parse by writing to /proc/self/attr/apparmor/current or through
lsm_set_self_attr(2), both of which go through do_setattr(), and the name
is parsed before the change_profile permission is checked.
The query_label() path behind the securityfs .access file, which is
mode 0666, performs no permission check at all. Every component has to
resolve to a loaded profile, so a system with policy loaded is required.
The other two VEC_FLAG_TERMINATE users work on a label vec that
aa_label_alloc() has already sized with "+ 1 for null terminator entry on
vec". Reserve the same entry in vec_setup() and DEFINE_VEC(). Passing
len + 1 from the caller instead would move len == LOCAL_VEC_ENTRIES out of
the local array and into kzalloc().
Fixes: f1bd904175e8 ("apparmor: add the base fns() for domain labels")
Cc: stable@vger.kernel.org
Signed-off-by: Hyunwoo Kim <imv4bel@gmail.com>
Signed-off-by: John Johansen <john.johansen@canonical.com>
diff --git a/security/apparmor/include/label.h b/security/apparmor/include/label.h
index b5a722a47fd2..37cb135de323 100644
--- a/security/apparmor/include/label.h
+++ b/security/apparmor/include/label.h
@@ -23,7 +23,7 @@ struct aa_ruleset;
#define LOCAL_VEC_ENTRIES 8
#define DEFINE_VEC(T, V) \
- struct aa_ ## T *(_ ## V ## _localtmp)[LOCAL_VEC_ENTRIES]; \
+ struct aa_ ## T *(_ ## V ## _localtmp)[LOCAL_VEC_ENTRIES + 1]; \
struct aa_ ## T **(V)
#define vec_setup(T, V, N, GFP) \
@@ -31,10 +31,10 @@ struct aa_ruleset;
if ((N) <= LOCAL_VEC_ENTRIES) { \
typeof(N) i; \
(V) = (_ ## V ## _localtmp); \
- for (i = 0; i < (N); i++) \
+ for (i = 0; i <= (N); i++) \
(V)[i] = NULL; \
} else \
- (V) = kzalloc(sizeof(struct aa_ ## T *) * (N), (GFP)); \
+ (V) = kzalloc_objs(struct aa_ ## T *, (N) + 1, (GFP)); \
(V) ? 0 : -ENOMEM; \
})
^ permalink raw reply related [flat|nested] 2+ messages in thread* [PATCH 6.6.y] apparmor: fix out-of-bounds write when null terminating a label vec
2026-09-03 11:07 FAILED: patch "[PATCH] apparmor: fix out-of-bounds write when null terminating a" failed to apply to 6.6-stable tree gregkh
@ 2026-09-04 10:29 ` Sasha Levin
0 siblings, 0 replies; 2+ messages in thread
From: Sasha Levin @ 2026-09-04 10:29 UTC (permalink / raw)
To: stable; +Cc: Hyunwoo Kim, John Johansen, Sasha Levin
From: Hyunwoo Kim <imv4bel@gmail.com>
[ Upstream commit 9f1e40193eef7f047e6b77cfb4b4cafdecd7a123 ]
aa_vec_unique() null terminates at vec[n - dups] when VEC_FLAG_TERMINATE
is passed. If the components are all distinct no duplicates are dropped,
dups is 0 and the terminator goes to vec[n], so the caller has to provide
room for n + 1 entries.
aa_label_strn_parse() sets up its vector with vec_setup(profile, vec, len,
gfp) and then calls aa_vec_unique(vec, len, VEC_FLAG_TERMINATE), but
vec_setup() does not reserve the terminator entry. Up to LOCAL_VEC_ENTRIES
it uses the local array of LOCAL_VEC_ENTRIES pointers, above that it
allocates exactly len pointers. The terminator therefore lands one entry
past the end of the local array when len is LOCAL_VEC_ENTRIES, and one
entry past the end of the allocation when len is larger.
len comes from the number of "//&" separated components in the label name
and label_count_strn_entries() does not bound it. An unprivileged task
reaches the parse by writing to /proc/self/attr/apparmor/current or through
lsm_set_self_attr(2), both of which go through do_setattr(), and the name
is parsed before the change_profile permission is checked.
The query_label() path behind the securityfs .access file, which is
mode 0666, performs no permission check at all. Every component has to
resolve to a loaded profile, so a system with policy loaded is required.
The other two VEC_FLAG_TERMINATE users work on a label vec that
aa_label_alloc() has already sized with "+ 1 for null terminator entry on
vec". Reserve the same entry in vec_setup() and DEFINE_VEC(). Passing
len + 1 from the caller instead would move len == LOCAL_VEC_ENTRIES out of
the local array and into kzalloc().
Fixes: f1bd904175e8 ("apparmor: add the base fns() for domain labels")
Cc: stable@vger.kernel.org
Signed-off-by: Hyunwoo Kim <imv4bel@gmail.com>
Signed-off-by: John Johansen <john.johansen@canonical.com>
[ replaced unavailable kzalloc_objs() with equivalent kcalloc() allocation ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
security/apparmor/include/label.h | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/security/apparmor/include/label.h b/security/apparmor/include/label.h
index 5aca0f612f8fd..55b5372ecf240 100644
--- a/security/apparmor/include/label.h
+++ b/security/apparmor/include/label.h
@@ -22,7 +22,7 @@ struct aa_ns;
#define LOCAL_VEC_ENTRIES 8
#define DEFINE_VEC(T, V) \
- struct aa_ ## T *(_ ## V ## _localtmp)[LOCAL_VEC_ENTRIES]; \
+ struct aa_ ## T *(_ ## V ## _localtmp)[LOCAL_VEC_ENTRIES + 1]; \
struct aa_ ## T **(V)
#define vec_setup(T, V, N, GFP) \
@@ -30,10 +30,10 @@ struct aa_ns;
if ((N) <= LOCAL_VEC_ENTRIES) { \
typeof(N) i; \
(V) = (_ ## V ## _localtmp); \
- for (i = 0; i < (N); i++) \
+ for (i = 0; i <= (N); i++) \
(V)[i] = NULL; \
} else \
- (V) = kzalloc(sizeof(struct aa_ ## T *) * (N), (GFP)); \
+ (V) = kcalloc((N) + 1, sizeof(struct aa_ ## T *), (GFP)); \
(V) ? 0 : -ENOMEM; \
})
--
2.53.0
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-09-04 10:29 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-03 11:07 FAILED: patch "[PATCH] apparmor: fix out-of-bounds write when null terminating a" failed to apply to 6.6-stable tree gregkh
2026-09-04 10:29 ` [PATCH 6.6.y] apparmor: fix out-of-bounds write when null terminating a label vec Sasha Levin
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.