diff options
Diffstat (limited to 'security/apparmor/match.c')
| -rw-r--r-- | security/apparmor/match.c | 99 | 
1 files changed, 87 insertions, 12 deletions
diff --git a/security/apparmor/match.c b/security/apparmor/match.c index 5cb4dc1f699..727eb4200d5 100644 --- a/security/apparmor/match.c +++ b/security/apparmor/match.c @@ -4,7 +4,7 @@   * This file contains AppArmor dfa based regular expression matching engine   *   * Copyright (C) 1998-2008 Novell/SUSE - * Copyright 2009-2010 Canonical Ltd. + * Copyright 2009-2012 Canonical Ltd.   *   * This program is free software; you can redistribute it and/or   * modify it under the terms of the GNU General Public License as @@ -23,6 +23,8 @@  #include "include/apparmor.h"  #include "include/match.h" +#define base_idx(X) ((X) & 0xffffff) +  /**   * unpack_table - unpack a dfa table (one of accept, default, base, next check)   * @blob: data to unpack (NOT NULL) @@ -30,7 +32,7 @@   *   * Returns: pointer to table else NULL on failure   * - * NOTE: must be freed by kvfree (not kmalloc) + * NOTE: must be freed by kvfree (not kfree)   */  static struct table_header *unpack_table(char *blob, size_t bsize)  { @@ -57,7 +59,7 @@ static struct table_header *unpack_table(char *blob, size_t bsize)  	if (bsize < tsize)  		goto out; -	table = kvmalloc(tsize); +	table = kvzalloc(tsize);  	if (table) {  		*table = th;  		if (th.td_flags == YYTD_DATA8) @@ -137,8 +139,7 @@ static int verify_dfa(struct aa_dfa *dfa, int flags)  		for (i = 0; i < state_count; i++) {  			if (DEFAULT_TABLE(dfa)[i] >= state_count)  				goto out; -			/* TODO: do check that DEF state recursion terminates */ -			if (BASE_TABLE(dfa)[i] + 255 >= trans_count) { +			if (base_idx(BASE_TABLE(dfa)[i]) + 255 >= trans_count) {  				printk(KERN_ERR "AppArmor DFA next/check upper "  				       "bounds error\n");  				goto out; @@ -194,8 +195,8 @@ void aa_dfa_free_kref(struct kref *kref)   * @flags: flags controlling what type of accept tables are acceptable   *   * Unpack a dfa that has been serialized.  To find information on the dfa - * format look in Documentation/apparmor.txt - * Assumes the dfa @blob stream has been aligned on a 8 byte boundry + * format look in Documentation/security/apparmor.txt + * Assumes the dfa @blob stream has been aligned on a 8 byte boundary   *   * Returns: an unpacked dfa ready for matching or ERR_PTR on failure   */ @@ -314,7 +315,7 @@ unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start,  		u8 *equiv = EQUIV_TABLE(dfa);  		/* default is direct to next state */  		for (; len; len--) { -			pos = base[state] + equiv[(u8) *str++]; +			pos = base_idx(base[state]) + equiv[(u8) *str++];  			if (check[pos] == state)  				state = next[pos];  			else @@ -323,7 +324,7 @@ unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start,  	} else {  		/* default is direct to next state */  		for (; len; len--) { -			pos = base[state] + (u8) *str++; +			pos = base_idx(base[state]) + (u8) *str++;  			if (check[pos] == state)  				state = next[pos];  			else @@ -335,12 +336,12 @@ unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start,  }  /** - * aa_dfa_next_state - traverse @dfa to find state @str stops at + * aa_dfa_match - traverse @dfa to find state @str stops at   * @dfa: the dfa to match @str against  (NOT NULL)   * @start: the state of the dfa to start matching in   * @str: the null terminated string of bytes to match against the dfa (NOT NULL)   * - * aa_dfa_next_state will match @str against the dfa and return the state it + * aa_dfa_match will match @str against the dfa and return the state it   * finished matching in. The final state can be used to look up the accepting   * label, or as the start state of a continuing match.   * @@ -349,5 +350,79 @@ unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start,  unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start,  			  const char *str)  { -	return aa_dfa_match_len(dfa, start, str, strlen(str)); +	u16 *def = DEFAULT_TABLE(dfa); +	u32 *base = BASE_TABLE(dfa); +	u16 *next = NEXT_TABLE(dfa); +	u16 *check = CHECK_TABLE(dfa); +	unsigned int state = start, pos; + +	if (state == 0) +		return 0; + +	/* current state is <state>, matching character *str */ +	if (dfa->tables[YYTD_ID_EC]) { +		/* Equivalence class table defined */ +		u8 *equiv = EQUIV_TABLE(dfa); +		/* default is direct to next state */ +		while (*str) { +			pos = base_idx(base[state]) + equiv[(u8) *str++]; +			if (check[pos] == state) +				state = next[pos]; +			else +				state = def[state]; +		} +	} else { +		/* default is direct to next state */ +		while (*str) { +			pos = base_idx(base[state]) + (u8) *str++; +			if (check[pos] == state) +				state = next[pos]; +			else +				state = def[state]; +		} +	} + +	return state; +} + +/** + * aa_dfa_next - step one character to the next state in the dfa + * @dfa: the dfa to tranverse (NOT NULL) + * @state: the state to start in + * @c: the input character to transition on + * + * aa_dfa_match will step through the dfa by one input character @c + * + * Returns: state reach after input @c + */ +unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state, +			  const char c) +{ +	u16 *def = DEFAULT_TABLE(dfa); +	u32 *base = BASE_TABLE(dfa); +	u16 *next = NEXT_TABLE(dfa); +	u16 *check = CHECK_TABLE(dfa); +	unsigned int pos; + +	/* current state is <state>, matching character *str */ +	if (dfa->tables[YYTD_ID_EC]) { +		/* Equivalence class table defined */ +		u8 *equiv = EQUIV_TABLE(dfa); +		/* default is direct to next state */ + +		pos = base_idx(base[state]) + equiv[(u8) c]; +		if (check[pos] == state) +			state = next[pos]; +		else +			state = def[state]; +	} else { +		/* default is direct to next state */ +		pos = base_idx(base[state]) + (u8) c; +		if (check[pos] == state) +			state = next[pos]; +		else +			state = def[state]; +	} + +	return state;  }  | 
