Skip to content

Commit 623a9d2

Browse files
jrjohansengregkh
authored andcommitted
apparmor: fix differential encoding verification
commit 39440b1 upstream. Differential encoding allows loops to be created if it is abused. To prevent this the unpack should verify that a diff-encode chain terminates. Unfortunately the differential encode verification had two bugs. 1. it conflated states that had gone through check and already been marked, with states that were currently being checked and marked. This means that loops in the current chain being verified are treated as a chain that has already been verified. 2. the order bailout on already checked states compared current chain check iterators j,k instead of using the outer loop iterator i. Meaning a step backwards in states in the current chain verification was being mistaken for moving to an already verified state. Move to a double mark scheme where already verified states get a different mark, than the current chain being kept. This enables us to also drop the backwards verification check that was the cause of the second error as any already verified state is already marked. Fixes: 031dcc8 ("apparmor: dfa add support for state differential encoding") Reported-by: Qualys Security Advisory <qsa@qualys.com> Tested-by: Salvatore Bonaccorso <carnil@debian.org> Reviewed-by: Georgia Garcia <georgia.garcia@canonical.com> Reviewed-by: Cengiz Can <cengiz.can@canonical.com> Signed-off-by: John Johansen <john.johansen@canonical.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent b60b3f7 commit 623a9d2

2 files changed

Lines changed: 20 additions & 4 deletions

File tree

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/match.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -202,16 +202,31 @@ static int verify_dfa(struct aa_dfa *dfa)
202202
size_t j, k;
203203

204204
for (j = i;
205-
(BASE_TABLE(dfa)[j] & MATCH_FLAG_DIFF_ENCODE) &&
206-
!(BASE_TABLE(dfa)[j] & MARK_DIFF_ENCODE);
205+
((BASE_TABLE(dfa)[j] & MATCH_FLAG_DIFF_ENCODE) &&
206+
!(BASE_TABLE(dfa)[j] & MARK_DIFF_ENCODE_VERIFIED));
207207
j = k) {
208+
if (BASE_TABLE(dfa)[j] & MARK_DIFF_ENCODE)
209+
/* loop in current chain */
210+
goto out;
208211
k = DEFAULT_TABLE(dfa)[j];
209212
if (j == k)
213+
/* self loop */
210214
goto out;
211-
if (k < j)
212-
break; /* already verified */
213215
BASE_TABLE(dfa)[j] |= MARK_DIFF_ENCODE;
214216
}
217+
/* move mark to verified */
218+
for (j = i;
219+
(BASE_TABLE(dfa)[j] & MATCH_FLAG_DIFF_ENCODE);
220+
j = k) {
221+
k = DEFAULT_TABLE(dfa)[j];
222+
if (j < i)
223+
/* jumps to state/chain that has been
224+
* verified
225+
*/
226+
break;
227+
BASE_TABLE(dfa)[j] &= ~MARK_DIFF_ENCODE;
228+
BASE_TABLE(dfa)[j] |= MARK_DIFF_ENCODE_VERIFIED;
229+
}
215230
}
216231
error = 0;
217232

0 commit comments

Comments
 (0)