2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-10-15 14:16:18 +00:00
Files
apparmor/kernel-patches/for-mainline/apparmor-single_module.diff
2007-02-06 18:57:06 +00:00

4241 lines
127 KiB
Diff

Index: linux-2.6/security/apparmor/Makefile
===================================================================
--- linux-2.6.orig/security/apparmor/Makefile
+++ linux-2.6/security/apparmor/Makefile
@@ -1,6 +1,6 @@
# Makefile for AppArmor Linux Security Module
#
-obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o match/
+obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
apparmor-y := main.o list.o procattr.o lsm.o apparmorfs.o capabilities.o \
- module_interface.o
+ module_interface.o match.o
Index: linux-2.6/security/apparmor/apparmor.h
===================================================================
--- linux-2.6.orig/security/apparmor/apparmor.h
+++ linux-2.6/security/apparmor/apparmor.h
@@ -17,6 +17,7 @@
#include <linux/rcupdate.h>
#include "shared.h"
+#include "match.h"
/* Control parameters (0 or 1), settable thru module/boot flags or
* via /sys/kernel/security/apparmor/control */
@@ -61,56 +62,21 @@ struct flagval {
int audit;
};
-enum entry_match_type {
- aa_entry_literal,
- aa_entry_tailglob,
- aa_entry_pattern,
- aa_entry_invalid
-};
-
-/* struct aa_entry - file ACL *
- * @filename: filename controlled by this ACL
- * @mode: permissions granted by ACL
- * @type: type of match to perform against @filename
- * @extradata: any extra data needed by an extended matching type
- * @list: list the ACL is on
- * @listp: permission partitioned lists this ACL is on.
- *
- * Each entry describes a file and an allowed access mode.
- */
-struct aa_entry {
- char *filename;
- int mode; /* mode is 'or' of READ, WRITE, EXECUTE,
- * INHERIT, UNCONSTRAINED, and LIBRARY
- * (meaning don't prefetch). */
-
- enum entry_match_type type;
- void *extradata;
-
- struct list_head list;
- struct list_head listp[POS_AA_FILE_MAX + 1];
-};
-
#define AA_MEDIATE_FS (void*)0x00000001
#define AA_SECURE_EXEC_NEEDED 0x00000001
#define AA_EXEC_MODIFIER_MASK(mask) ((mask) & AA_EXEC_MODIFIERS)
-#define AA_EXEC_MASK(mask) ((mask) & (AA_MAY_EXEC | AA_EXEC_MODIFIERS))
-#define AA_EXEC_UNSAFE_MASK(mask) ((mask) & (AA_MAY_EXEC | AA_EXEC_MODIFIERS |\
- AA_EXEC_UNSAFE))
+#define AA_EXEC_MASK(mask) ((mask) & (AA_EXEC_MODIFIERS | AA_EXEC_UNSAFE))
/* struct aaprofile - basic confinement data
* @parent: non refcounted pointer to parent profile
* @name: the profiles name
- * @file_entry: file ACL
- * @file_entryp: vector of file ACL by permission granted
+ * @file_rules: dfa containing the profiles file rules
* @list: list this profile is on
* @sub: profiles list of subprofiles (HATS)
* @flags: flags controlling profile behavior
* @null_profile: if needed per profile learning and null confinement profile
* @isstale: flag to indicate the profile is stale
- * @num_file_entries: number of file entries the profile contains
- * @num_file_pentries: number of file entries for each partitioned list
* @capabilities: capabilities granted by the process
* @rcu: rcu head used when freeing the profile
* @count: reference count of the profile
@@ -123,17 +89,14 @@ struct aaprofile {
struct aaprofile *parent;
char *name;
- struct list_head file_entry;
- struct list_head file_entryp[POS_AA_FILE_MAX + 1];
+ struct aa_dfa *file_rules;
+
struct list_head list;
struct list_head sub;
struct flagval flags;
struct aaprofile *null_profile;
int isstale;
- int num_file_entries;
- int num_file_pentries[POS_AA_FILE_MAX + 1];
-
kernel_cap_t capabilities;
struct rcu_head rcu;
@@ -298,4 +261,12 @@ extern void destroy_apparmorfs(void);
/* capabilities.c */
extern const char *capability_to_name(unsigned int cap);
+/* match.c */
+struct aa_dfa *aamatch_alloc(void);
+void aamatch_free(struct aa_dfa *dfa);
+int unpack_dfa(struct aa_dfa *dfa, void *blob, size_t size);
+int verify_dfa(struct aa_dfa *dfa);
+const char *aamatch_features(void);
+unsigned int aamatch(struct aa_dfa *dfa, const char *pathname);
+
#endif /* __APPARMOR_H */
Index: linux-2.6/security/apparmor/inline.h
===================================================================
--- linux-2.6.orig/security/apparmor/inline.h
+++ linux-2.6/security/apparmor/inline.h
@@ -199,14 +199,8 @@ static inline struct aaprofile *alloc_aa
GFP_KERNEL);
AA_DEBUG("%s(%p)\n", __FUNCTION__, profile);
if (profile) {
- int i;
-
INIT_LIST_HEAD(&profile->list);
INIT_LIST_HEAD(&profile->sub);
- INIT_LIST_HEAD(&profile->file_entry);
- for (i = 0; i <= POS_AA_FILE_MAX; i++) {
- INIT_LIST_HEAD(&profile->file_entryp[i]);
- }
INIT_RCU_HEAD(&profile->rcu);
kref_init(&profile->count);
}
Index: linux-2.6/security/apparmor/main.c
===================================================================
--- linux-2.6.orig/security/apparmor/main.c
+++ linux-2.6/security/apparmor/main.c
@@ -14,7 +14,6 @@
#include <linux/audit.h>
#include "apparmor.h"
-#include "match/match.h"
#include "inline.h"
@@ -60,7 +59,6 @@ static inline int aa_taskattr_access(con
*/
static inline int aa_file_mode(struct aaprofile *profile, const char *name)
{
- struct aa_entry *entry;
int perms = 0;
AA_DEBUG("%s: %s\n", __FUNCTION__, name);
@@ -73,119 +71,11 @@ static inline int aa_file_mode(struct aa
AA_DEBUG("%s: no profile\n", __FUNCTION__);
goto out;
}
- list_for_each_entry(entry, &profile->file_entry, list) {
- perms |= aamatch_match(entry, name);
- }
-out:
- return perms;
-}
-
-/**
- * aa_get_execmode - calculate what qualifier to apply to an exec
- * @active: profile to search
- * @name: name of file to exec
- * @xmod: pointer to a execution mode bit for the rule that was matched
- * if the rule has no execuition qualifier {pui} then
- * %AA_MAY_EXEC is returned indicating a naked x
- * if the has an exec qualifier then only the qualifier bit {pui}
- * is returned (%AA_MAY_EXEC) is not set.
- * @unsafe: true if secure_exec should be overriden
- * Returns %0 (false):
- * if unable to find profile or there are conflicting pattern matches.
- * *xmod - is not modified
- * *unsafe - is not modified
- *
- * Returns %1 (true):
- * if exec rule matched
- * if the rule has an execution mode qualifier {pui} then
- * *xmod = the execution qualifier of the rule {pui}
- * else
- * *xmod = %AA_MAY_EXEC
- * unsafe = presence of unsage flag
- */
-static inline int aa_get_execmode(struct aaprofile *active, const char *name,
- int *xmod, int *unsafe)
-{
- struct aa_entry *entry;
- int entry_perms = 0, match_perms = 0;
- int pattern_match_invalid = 0, rc = 0;
-
- /* search list of profiles with 'x' permission
- * this will also include entries with 'p', 'u' and 'i'
- * qualifiers.
- *
- * If we find a pattern match we will keep looking for an exact match
- * If we find conflicting pattern matches we will flag (while still
- * looking for an exact match). If all we have is a conflict, FALSE
- * is returned.
- */
-
- list_for_each_entry(entry, &active->file_entryp[POS_AA_MAY_EXEC],
- listp[POS_AA_MAY_EXEC]) {
- if (!pattern_match_invalid &&
- entry->type == aa_entry_pattern &&
- (entry_perms = aamatch_match(entry, name))) {
- if (match_perms &&
- AA_EXEC_UNSAFE_MASK(entry_perms) !=
- AA_EXEC_UNSAFE_MASK(match_perms))
- pattern_match_invalid = 1;
- else
- /* keep searching for an exact match */
- match_perms = entry_perms;
- } else if ((entry->type == aa_entry_literal ||
- (!pattern_match_invalid &&
- entry->type == aa_entry_tailglob)) &&
- (entry_perms = aamatch_match(entry, name))) {
- if (entry->type == aa_entry_literal) {
- /* got an exact match -- there can be only
- * one, asserted at profile load time
- */
- match_perms = entry_perms;
- pattern_match_invalid = 0;
- break;
- } else {
- if (match_perms &&
- AA_EXEC_UNSAFE_MASK(entry_perms) !=
- AA_EXEC_UNSAFE_MASK(match_perms))
- pattern_match_invalid = 1;
- else
- /* got a tailglob match, keep searching
- * for an exact match
- */
- match_perms = entry_perms;
- }
- }
-
- }
-
- rc = match_perms && !pattern_match_invalid;
- if (rc) {
- int mode = AA_EXEC_MASK(match_perms);
+ perms = aamatch(profile->file_rules, name);
- /* check for qualifiers, if present
- * we just return the qualifier
- */
- if (mode & ~AA_MAY_EXEC)
- mode = mode & ~AA_MAY_EXEC;
-
- *xmod = mode;
- *unsafe = (match_perms & AA_EXEC_UNSAFE);
- } else if (!match_perms) {
- AA_DEBUG("%s: Unable to find execute entry in profile "
- "for image '%s'\n",
- __FUNCTION__,
- name);
- } else if (pattern_match_invalid) {
- AA_WARN("%s: Inconsistency in profile %s. "
- "Two (or more) patterns specify conflicting exec "
- "qualifiers ('u', 'i' or 'p') for image %s\n",
- __FUNCTION__,
- active->name,
- name);
- }
-
- return rc;
+out:
+ return perms;
}
/**
@@ -242,10 +132,9 @@ static inline void aa_permerror2result(i
*
* Return %0 on success, else mask of non-allowed permissions
*/
-static unsigned int aa_file_perm(struct aaprofile *active, const char *name,
- int mask)
+static int aa_file_perm(struct aaprofile *active, const char *name, int mask)
{
- int i, error = 0;
+ int error = 0;
int perms;
#define PROCPFX "/proc/"
@@ -265,32 +154,7 @@ static unsigned int aa_file_perm(struct
aa_taskattr_access(name + PROCLEN))
goto done;
- perms = 0;
-
- /* iterate over partition, one permission bit at a time */
- for (i = 0; i <= POS_AA_FILE_MAX; i++) {
- struct aa_entry *entry;
-
- /* do we have to accumulate this bit?
- * or have we already accumulated it (shortcut below)? */
- if (!(mask & (1 << i)) || perms & (1 << i))
- continue;
-
- list_for_each_entry(entry, &active->file_entryp[i],
- listp[i]) {
- perms |= aamatch_match(entry, name);
-
- /* Mask bits are overloaded
- * MAY_{EXEC,WRITE,READ,APPEND} are used by
- * kernel, other values are used locally only.
- */
- if ((perms & mask) == mask) {
- AA_DEBUG("MATCH! %s=0x%x [total mode=0x%x]\n",
- name, mask, perms);
- goto done;
- }
- }
- }
+ perms = aamatch(active->file_rules, name);
/* return permissions not satisfied */
error = mask & ~perms;
@@ -964,8 +828,8 @@ int aa_register(struct linux_binprm *bpr
exec_mode = 0,
find_profile = 0,
find_profile_mandatory = 0,
- unsafe_exec = 0,
- complain = 0;
+ complain = 0,
+ unsafe_exec = 0;
AA_DEBUG("%s\n", __FUNCTION__);
@@ -990,8 +854,11 @@ int aa_register(struct linux_binprm *bpr
/* Confined task, determine what mode inherit, unconstrained or
* mandatory to load new profile
*/
- if (aa_get_execmode(active, filename, &exec_mode, &unsafe_exec)) {
- switch (exec_mode) {
+ exec_mode = AA_EXEC_MASK(aamatch(active->file_rules, filename));
+ unsafe_exec = exec_mode & AA_EXEC_UNSAFE;
+
+ if (exec_mode) {
+ switch (AA_EXEC_MODIFIER_MASK(exec_mode)) {
case AA_EXEC_INHERIT:
/* do nothing - setting of profile
* already handed in aa_fork
Index: linux-2.6/security/apparmor/match/Kbuild
===================================================================
--- linux-2.6.orig/security/apparmor/match/Kbuild
+++ /dev/null
@@ -1,6 +0,0 @@
-# Makefile for AppArmor aamatch submodule
-#
-
-obj-$(CONFIG_SECURITY_APPARMOR) += aamatch_dfa.o
-
-aamatch_dfa-y := match_dfa.o
Index: linux-2.6/security/apparmor/match/Makefile
===================================================================
--- linux-2.6.orig/security/apparmor/match/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-# Makefile for AppArmor aamatch submodule
-#
-obj-$(CONFIG_SECURITY_APPARMOR) += aamatch_pcre.o
-
-aamatch_pcre-y := match_pcre.o pcre_exec.o
Index: linux-2.6/security/apparmor/match/match.h
===================================================================
--- linux-2.6.orig/security/apparmor/match/match.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2002-2005 Novell/SUSE
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, version 2 of the
- * License.
- *
- * AppArmor submodule (match) prototypes
- */
-
-#ifndef __MATCH_H
-#define __MATCH_H
-
-#include "../module_interface.h"
-#include "../apparmor.h"
-
-/* The following functions implement an interface used by the primary
- * AppArmor module to perform name matching (n.b. "AppArmor" was previously
- * called "SubDomain").
-
- * aamatch_alloc
- * aamatch_free
- * aamatch_features
- * aamatch_serialize
- * aamatch_match
- *
- * The intent is for the primary module to export (via virtual fs entries)
- * the features provided by the submodule (aamatch_features) so that the
- * parser may only load policy that can be supported.
- *
- * The primary module will call aamatch_serialize to allow the submodule
- * to consume submodule specific data from parser data stream and will call
- * aamatch_match to determine if a pathname matches an aa_entry.
- */
-
-typedef int (*aamatch_serializecb)
- (struct aa_ext *, enum aa_code, void *, const char *);
-
-/**
- * aamatch_alloc: allocate extradata (if necessary)
- * @type: type of entry being allocated
- * Return value: NULL indicates no data was allocated (ERR_PTR(x) on error)
- */
-extern void* aamatch_alloc(enum entry_match_type type);
-
-/**
- * aamatch_free: release data allocated by aamatch_alloc
- * @entry_extradata: data previously allocated by aamatch_alloc
- */
-extern void aamatch_free(void *entry_extradata);
-
-/**
- * aamatch_features: return match types supported
- * Return value: space seperated string (of types supported - use type=value
- * to indicate variants of a type)
- */
-extern const char* aamatch_features(void);
-
-/**
- * aamatch_serialize: serialize extradata
- * @entry_extradata: data previously allocated by aamatch_alloc
- * @e: input stream
- * @cb: callback fn (consume incoming data stream)
- * Return value: 0 success, -ve error
- */
-extern int aamatch_serialize(void *entry_extradata, struct aa_ext *e,
- aamatch_serializecb cb);
-
-/**
- * aamatch_match: determine if pathname matches entry
- * @entry: rule entry to match against
- * @pathname: pathname to verify
- * Return value: permission match, 0 othersise
- */
-extern int aamatch_match(struct aa_entry *entry, const char *pathname);
-
-/**
- * sd_getmatch_type - return string representation of entry_match_type
- * @type: entry match type
- */
-static inline const char *sd_getmatch_type(enum entry_match_type type)
-{
- const char *names[] = {
- "aa_entry_literal",
- "aa_entry_tailglob",
- "aa_entry_pattern",
- "aa_entry_invalid"
- };
-
- if (type >= aa_entry_invalid) {
- type = aa_entry_invalid;
- }
-
- return names[type];
-}
-
-/**
- * aamatch_match_common - helper function to check if a pathname matches
- * a literal/tailglob
- * @path: path requested to search for
- * @entry_name: name from aa_entry
- * @type: type of entry
- */
-static inline int aamatch_match_common(struct aa_entry *entry,
- const char *path)
-{
- int retval;
-
- /* literal, no pattern matching characters */
- if (entry->type == aa_entry_literal) {
- retval = (strcmp(entry->filename, path) == 0);
- /* trailing ** glob pattern */
- } else if (entry->type == aa_entry_tailglob) {
- retval = (strncmp(entry->filename, path,
- strlen(entry->filename) - 2) == 0);
- } else {
- AA_WARN("%s: Invalid entry_match_type %d\n",
- __FUNCTION__, entry->type);
- retval = 0;
- }
-
- return retval ? entry->mode : 0;
-}
-
-#endif /* __MATCH_H */
Index: linux-2.6/security/apparmor/match/match_default.c
===================================================================
--- linux-2.6.orig/security/apparmor/match/match_default.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2002-2005 Novell/SUSE
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, version 2 of the
- * License.
- *
- * http://forge.novell.com/modules/xfmod/project/?apparmor
- *
- * AppArmor default match submodule (literal and tailglob)
- */
-
-#include <linux/module.h>
-#include "match.h"
-
-static const char *features="literal tailglob";
-
-void* aamatch_alloc(enum entry_match_type type)
-{
- return NULL;
-}
-
-void aamatch_free(void *ptr)
-{
-}
-
-const char *aamatch_features(void)
-{
- return features;
-}
-
-int aamatch_serialize(void *entry_extradata, struct aa_ext *e,
- aamatch_serializecb cb)
-{
- return 0;
-}
-
-int aamatch_match(struct aa_entry *entry, const char *pathname)
-{
- int ret;
-
- ret = aamatch_match_common(entry, pathname);
-
- return ret;
-}
-
-EXPORT_SYMBOL_GPL(aamatch_alloc);
-EXPORT_SYMBOL_GPL(aamatch_free);
-EXPORT_SYMBOL_GPL(aamatch_features);
-EXPORT_SYMBOL_GPL(aamatch_serialize);
-EXPORT_SYMBOL_GPL(aamatch_match);
-
-MODULE_DESCRIPTION("AppArmor match module (aamatch) [default]");
-MODULE_AUTHOR("Tony Jones <tonyj@suse.de>");
-MODULE_LICENSE("GPL");
Index: linux-2.6/security/apparmor/match/match_dfa.c
===================================================================
--- linux-2.6.orig/security/apparmor/match/match_dfa.c
+++ /dev/null
@@ -1,398 +0,0 @@
-/*
- * Copyright (C) 2002-2005 Novell/SUSE
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, version 2 of the
- * License.
- *
- * http://forge.novell.com/modules/xfmod/project/?apparmor
- *
- * AppArmor aamatch submodule (w/ pattern expansion).
- *
- */
-
-#include <asm/unaligned.h>
-#include <linux/module.h>
-#include "match.h"
-
-static const char *features="literal tailglob pattern=aadfa";
-
-#define YYTH_MAGIC 0x1B5E783D
-
-struct table_set_header {
- u32 th_magic; /* TH_MAGIC */
- u32 th_hsize;
- u32 th_ssize;
- u16 th_flags;
- char th_version[];
-};
-
-#define YYTD_ID_ACCEPT 1 /* 1 */
-#define YYTD_ID_BASE 2 /* 2 */
-#define YYTD_ID_CHK 3 /* 3 */
-#define YYTD_ID_DEF 4 /* 4 */
-#define YYTD_ID_EC 5 /* 5 */
-#define YYTD_ID_NXT 6 /* 8 */
-#define YYTD_ID_META 7 /* 6 */
-
-#define YYTD_DATA8 1
-#define YYTD_DATA16 2
-#define YYTD_DATA32 4
-
-struct table_header {
- u16 td_id;
- u16 td_flags;
- u32 td_hilen;
- u32 td_lolen;
- char td_data[];
-};
-
-#define DEFAULT_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_DEF - 1]->td_data))
-#define BASE_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_BASE - 1]->td_data))
-#define NEXT_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_NXT - 1]->td_data))
-#define CHECK_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_CHK - 1]->td_data))
-#define EQUIV_TABLE(DFA) ((u8 *)((DFA)->tables[YYTD_ID_EC - 1]->td_data))
-#define ACCEPT_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT - 1]->td_data))
-
-struct aa_dfa {
- struct table_header *tables[YYTD_ID_NXT];
-
- struct table_set_header th;
-};
-
-#define ntohb(X) (X)
-
-#define UNPACK_ARRAY(TABLE, BLOB, LEN, TYPE, NTOHX) \
- do { \
- typeof(LEN) __i; \
- TYPE *__t = (TYPE *) TABLE; \
- TYPE *__b = (TYPE *) BLOB; \
- for (__i = 0; __i < LEN; __i++) { \
- __t[__i] = NTOHX(__b[__i]); \
- } \
- } while (0)
-
-static inline size_t pad64(size_t i)
-{
- return (i + (size_t)7) & ~(size_t)7;
-}
-
-static inline size_t table_size(size_t len, size_t el_size)
-{
- return pad64(sizeof(struct table_header) + len * el_size);
-}
-
-static struct table_header *unpack_table(void *blob, size_t bsize)
-{
- struct table_header *table = NULL;
- struct table_header th;
- size_t tsize;
-
- if (bsize < sizeof(struct table_header))
- goto out;
-
- th.td_id = ntohs(get_unaligned((u16 *) (blob)));
- th.td_flags = ntohs(get_unaligned((u16 *) (blob + 2)));
- th.td_lolen = ntohl(get_unaligned((u32 *) (blob + 8)));
- blob += sizeof(struct table_header);
-
- if (!(th.td_flags == YYTD_DATA16 || th.td_flags == YYTD_DATA32 ||
- th.td_flags == YYTD_DATA8))
- goto out;
-
- tsize = table_size(th.td_lolen, th.td_flags);
- if (bsize < tsize)
- goto out;
-
- table = kmalloc(tsize, GFP_KERNEL);
- if (table) {
- *table = th;
- if (th.td_flags == YYTD_DATA8)
- UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
- u8, ntohb);
- else if (th.td_flags == YYTD_DATA16)
- UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
- u16, ntohs);
- else
- UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
- u32, ntohl);
- }
-
-out:
- return table;
-}
-
-static int unpack_dfa(struct aa_dfa *dfa, void *blob, size_t size)
-{
- int i;
- int error = -ENOMEM;
-
- /* get dfa table set header */
- if (size < sizeof(struct table_set_header))
- goto fail;
-
- dfa->th.th_magic = ntohl(get_unaligned((u32 *) (blob + 0)));
- dfa->th.th_hsize = ntohl(get_unaligned((u32 *) (blob + 4)));
- dfa->th.th_ssize = ntohl(get_unaligned((u32 *) (blob + 8)));
- dfa->th.th_flags = ntohs(get_unaligned((u16 *) (blob + 12)));
-
- if (dfa->th.th_magic != YYTH_MAGIC)
- goto fail;
-
- if (size < dfa->th.th_hsize)
- goto fail;
-
- blob += dfa->th.th_hsize;
- size -= dfa->th.th_hsize;
-
- while (size > 0) {
- struct table_header *table;
- table = unpack_table(blob, size);
- if (!table)
- goto fail;
-
- switch(table->td_id) {
- case YYTD_ID_ACCEPT:
- case YYTD_ID_BASE:
- dfa->tables[table->td_id - 1] = table;
- if (table->td_flags != YYTD_DATA32)
- goto fail_proto;
- break;
- case YYTD_ID_DEF:
- case YYTD_ID_NXT:
- case YYTD_ID_CHK:
- dfa->tables[table->td_id - 1] = table;
- if (table->td_flags != YYTD_DATA16)
- goto fail_proto;
- break;
- case YYTD_ID_EC:
- dfa->tables[table->td_id - 1] = table;
- if (table->td_flags != YYTD_DATA8)
- goto fail_proto;
- break;
- default:
- kfree(table);
- goto fail_proto;
- }
-
- blob += table_size(table->td_lolen, table->td_flags);
- size -= table_size(table->td_lolen, table->td_flags);
- }
-
- error = 0;
-
- return error;
-
-fail_proto:
- error = -EPROTO;
-fail:
- for (i = 0; i < YYTD_ID_NXT; i++) {
- if (dfa->tables[i]) {
- kfree(dfa->tables[i]);
- dfa->tables[i] = NULL;
- }
- }
- return error;
-}
-
-/**
- * verify_dfa - verify that all the transitions and states in the dfa tables
- * are in bounds.
- * @dfa: dfa to test
- *
- * assumes dfa has gone through the verification done by unpacking
- */
-static int verify_dfa(struct aa_dfa *dfa)
-{
- size_t i, state_count, trans_count;
- int error = -EPROTO;
-
- /* check that required tables exist */
- if (!(dfa->tables[YYTD_ID_ACCEPT -1 ] &&
- dfa->tables[YYTD_ID_DEF - 1] &&
- dfa->tables[YYTD_ID_BASE - 1] &&
- dfa->tables[YYTD_ID_NXT - 1] &&
- dfa->tables[YYTD_ID_CHK - 1]))
- goto out;
-
- /* accept.size == default.size == base.size */
- state_count = dfa->tables[YYTD_ID_BASE - 1]->td_lolen;
- if (!(state_count == dfa->tables[YYTD_ID_DEF - 1]->td_lolen &&
- state_count == dfa->tables[YYTD_ID_ACCEPT - 1]->td_lolen))
- goto out;
-
- /* next.size == chk.size */
- trans_count = dfa->tables[YYTD_ID_NXT - 1]->td_lolen;
- if (trans_count != dfa->tables[YYTD_ID_CHK - 1]->td_lolen)
- goto out;
-
- /* if equivalence classes then its table must be 256 */
- if (dfa->tables[YYTD_ID_EC - 1] &&
- dfa->tables[YYTD_ID_EC - 1]->td_lolen != 256)
- goto out;
-
- for (i = 0; i < state_count; i++) {
- if (DEFAULT_TABLE(dfa)[i] >= state_count)
- goto out;
- if (BASE_TABLE(dfa)[i] >= trans_count + 256)
- goto out;
- }
-
- for (i = 0; i < trans_count ; i++) {
- if (NEXT_TABLE(dfa)[i] >= state_count)
- goto out;
- if (CHECK_TABLE(dfa)[i] >= state_count)
- goto out;
- }
-
- error = 0;
-out:
- return error;
-}
-
-/**
- * aadfa_label - return the permissions associated with @state
- * @dfa: dfa to get state permission from
- * @state: state in the dfa for which to get a label
- *
- * Assumes that state is a valid state of the dfa
- *
- * Returns the label associated with @state. 0 indicates the state
- * is no-accepting/provides no permissions.
- */
-inline unsigned int aadfa_label(struct aa_dfa *dfa, int state)
-{
- return ACCEPT_TABLE(dfa)[state] & AA_VALID_PERM_MASK;
-}
-
-/**
- * aadfa_match - match @path against @dfa starting in @state
- * @dfa: the dfa to match @path against
- * @state: the state to start matching in
- * @path: the path to match against the dfa
- *
- * aadfa_match will match the full path length and return the state it
- * finished matching in. The final state returned can be used to
- * lookup the accepting label or as a starting point to continue matching
- * with a new string if the path has been broken into multiple components.
- */
-static unsigned int aadfa_match(struct aa_dfa *dfa, unsigned int state,
- const char *path)
-{
- u8 *s = (u8 *) path;
- 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 *s */
- if (dfa->tables[YYTD_ID_EC - 1]) {
- u8 *equiv = EQUIV_TABLE(dfa);
- for ( ; *s; ++s) {
- pos = base[state] + equiv[*s];
- if (check[pos] == state)
- state = next[pos];
- else
- state = def[state];
- }
- } else {
- for ( ; *s; ++s) {
- pos = base[state] + *s;
- if (check[pos] == state)
- state = next[pos];
- else
- state = def[state];
- }
- }
- return state;
-}
-
-void* aamatch_alloc(enum entry_match_type entry_type)
-{
- void *ptr=NULL;
-
- if (entry_type == aa_entry_pattern) {
- ptr = kmalloc(sizeof(struct aa_dfa), GFP_KERNEL);
- if (ptr)
- memset(ptr, 0, sizeof(struct aa_dfa));
- else
- ptr=ERR_PTR(-ENOMEM);
- } else if (entry_type != aa_entry_literal &&
- entry_type != aa_entry_tailglob) {
- ptr = ERR_PTR(-EINVAL);
- }
-
- return ptr;
-}
-
-void aamatch_free(void *ptr)
-{
- if (ptr) {
- int i;
- struct aa_dfa *dfa = (struct aa_dfa *) ptr;
- for (i = 0; i < YYTD_ID_NXT; i++) {
- if (dfa->tables[i])
- kfree(dfa->tables[i]);
- }
- }
- kfree(ptr);
-}
-
-const char *aamatch_features(void)
-{
- return features;
-}
-
-int aamatch_serialize(void *entry_extradata, struct aa_ext *e,
- aamatch_serializecb cb)
-{
- int error = 0;
- char *blob = NULL;
- size_t size;
-
- struct aa_dfa *dfa = (struct aa_dfa *) entry_extradata;
- if (dfa == NULL)
- goto done;
-
- error = -EPROTO;
- size = cb(e, AA_BLOB_LOC, &blob, "aadfa");
-
- if (size)
- error = unpack_dfa(dfa, blob, size);
-
- if (!error)
- error = verify_dfa(dfa);
-done:
- return error;
-}
-
-int aamatch_match(struct aa_entry *entry, const char *pathname)
-{
- int ret;
-
- if (entry->type == aa_entry_pattern) {
- unsigned int state;
- struct aa_dfa *dfa = (struct aa_dfa *) entry->extradata;
-
- state = aadfa_match(dfa, 1, pathname);
-
- /* label returned is the permissions of the matched state */
- ret = aadfa_label(dfa, state);
- } else {
- ret = aamatch_match_common(entry, pathname);
- }
-
- return ret;
-}
-
-EXPORT_SYMBOL_GPL(aamatch_alloc);
-EXPORT_SYMBOL_GPL(aamatch_free);
-EXPORT_SYMBOL_GPL(aamatch_features);
-EXPORT_SYMBOL_GPL(aamatch_serialize);
-EXPORT_SYMBOL_GPL(aamatch_match);
-
-MODULE_DESCRIPTION("AppArmor aa_match module [dfa]");
-MODULE_AUTHOR("John Johansen <jjohansen@suse.de>");
-MODULE_LICENSE("GPL");
Index: linux-2.6/security/apparmor/match/match_pcre.c
===================================================================
--- linux-2.6.orig/security/apparmor/match/match_pcre.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (C) 2002-2005 Novell/SUSE
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, version 2 of the
- * License.
- *
- * http://forge.novell.com/modules/xfmod/project/?apparmor
- *
- * AppArmor aamatch submodule (w/ pattern expansion).
- *
- * This module makes use of a slightly modified version of the PCRE
- * library developed by Philip Hazel <ph10@cam.ac.uk>. See the files
- * pcre_* in this directory.
- */
-
-#include <linux/module.h>
-#include "match.h"
-#include "pcre_exec.h"
-#include "pcre_tables.h"
-
-static const char *features="literal tailglob pattern=pcre";
-
-struct aamatch_entry
-{
- char *pattern;
- pcre *compiled;
-};
-
-void* aamatch_alloc(enum entry_match_type entry_type)
-{
-void *ptr=NULL;
-
- if (entry_type == aa_entry_pattern) {
- ptr = kmalloc(sizeof(struct aamatch_entry), GFP_KERNEL);
- if (ptr)
- memset(ptr, 0, sizeof(struct aamatch_entry));
- else
- ptr=ERR_PTR(-ENOMEM);
- } else if (entry_type != aa_entry_literal &&
- entry_type != aa_entry_tailglob) {
- ptr = ERR_PTR(-EINVAL);
- }
-
- return ptr;
-}
-
-void aamatch_free(void *ptr)
-{
- if (ptr) {
- struct aamatch_entry *ed = (struct aamatch_entry *) ptr;
- kfree(ed->pattern);
- kfree(ed->compiled); /* allocated by AA_READ_X */
- }
- kfree(ptr);
-}
-
-const char *aamatch_features(void)
-{
- return features;
-}
-
-int aamatch_serialize(void *entry_extradata, struct aa_ext *e,
- aamatch_serializecb cb)
-{
-#define AA_READ_X(E, C, D, N) \
- do { \
- if (!cb((E), (C), (D), (N))) { \
- error = -EINVAL; \
- goto done; \
- }\
- } while (0)
-
- int error = 0;
- u32 size, magic, opts;
- u8 t_char;
- struct aamatch_entry *ed = (struct aamatch_entry *) entry_extradata;
-
- if (ed == NULL)
- goto done;
-
- AA_READ_X(e, AA_DYN_STRING, &ed->pattern, NULL);
-
- /* size determines the real size of the pcre struct,
- it is size_t - sizeof(pcre) on user side.
- uschar must be the same in user and kernel space */
- /* check that we are processing the correct structure */
- AA_READ_X(e, AA_STRUCT, NULL, "pcre");
- AA_READ_X(e, AA_U32, &size, NULL);
- AA_READ_X(e, AA_U32, &magic, NULL);
-
- /* the allocation of pcre is delayed because it depends on the size
- * of the pattern */
- ed->compiled = (pcre *) kmalloc(size + sizeof(pcre), GFP_KERNEL);
- if (!ed->compiled) {
- error = -ENOMEM;
- goto done;
- }
-
- memset(ed->compiled, 0, size + sizeof(pcre));
- ed->compiled->magic_number = magic;
- ed->compiled->size = size + sizeof(pcre);
-
- AA_READ_X(e, AA_U32, &opts, NULL);
- ed->compiled->options = opts;
- AA_READ_X(e, AA_U16, &ed->compiled->top_bracket, NULL);
- AA_READ_X(e, AA_U16, &ed->compiled->top_backref, NULL);
- AA_READ_X(e, AA_U8, &t_char, NULL);
- ed->compiled->first_char = t_char;
- AA_READ_X(e, AA_U8, &t_char, NULL);
- ed->compiled->req_char = t_char;
- AA_READ_X(e, AA_U8, &t_char, NULL);
- ed->compiled->code[0] = t_char;
-
- AA_READ_X(e, AA_STATIC_BLOB, &ed->compiled->code[1], NULL);
-
- AA_READ_X(e, AA_STRUCTEND, NULL, NULL);
-
- /* stitch in pcre patterns, it was NULLed out by parser
- * pcre_default_tables defined in pcre_tables.h */
- ed->compiled->tables = pcre_default_tables;
-
-done:
- if (error != 0 && ed) {
- kfree(ed->pattern); /* allocated by AA_READ_X */
- kfree(ed->compiled);
- ed->pattern = NULL;
- ed->compiled = NULL;
- }
-
- return error;
-}
-
-int aamatch_match(struct aa_entry *entry, const char *pathname)
-{
- int ret;
-
- if (entry->type == aa_entry_pattern) {
- int pcreret;
- struct aamatch_entry *ed =
- (struct aamatch_entry *) entry->extradata;
-
- pcreret = pcre_exec(ed->compiled, NULL,
- pathname, strlen(pathname),
- 0, 0, NULL, 0);
-
- ret = (pcreret >= 0) ? entry->mode : 0;
-
- // XXX - this needs access to subdomain_debug, hmmm
- //AA_DEBUG("%s(%d): %s %s %d\n", __FUNCTION__,
- // ret, pathname, ed->pattern, pcreret);
- } else {
- ret = aamatch_match_common(entry, pathname);
- }
-
- return ret;
-}
-
-EXPORT_SYMBOL_GPL(aamatch_alloc);
-EXPORT_SYMBOL_GPL(aamatch_free);
-EXPORT_SYMBOL_GPL(aamatch_features);
-EXPORT_SYMBOL_GPL(aamatch_serialize);
-EXPORT_SYMBOL_GPL(aamatch_match);
-
-MODULE_DESCRIPTION("AppArmor aa_match module [pcre]");
-MODULE_AUTHOR("Tony Jones <tonyj@suse.de>");
-MODULE_LICENSE("GPL");
Index: linux-2.6/security/apparmor/match/pcre_exec.c
===================================================================
--- linux-2.6.orig/security/apparmor/match/pcre_exec.c
+++ /dev/null
@@ -1,1945 +0,0 @@
-/*
- * This is a modified version of pcre.c containing only the code/data
- * required to support pcre_exec()
- */
-
-
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/*
-This is a library of functions to support regular expressions whose syntax
-and semantics are as close as possible to those of the Perl 5 language. See
-the file Tech.Notes for some information on the internals.
-
-Written by: Philip Hazel <ph10@cam.ac.uk>
-
- Copyright (c) 1997-2001 University of Cambridge
-
------------------------------------------------------------------------------
-Permission is granted to anyone to use this software for any purpose on any
-computer system, and to redistribute it freely, subject to the following
-restrictions:
-
-1. This software is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-2. The origin of this software must not be misrepresented, either by
- explicit claim or by omission.
-
-3. Altered versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
-
-4. If PCRE is embedded in any software that is released under the GNU
- General Purpose Licence (GPL), then the terms of that licence shall
- supersede any condition above with which it is incompatible.
------------------------------------------------------------------------------
-*/
-
-
-/* Define DEBUG to get debugging output on stdout. */
-
-/* #define DEBUG */
-
-/* Use a macro for debugging printing, 'cause that eliminates the use of #ifdef
-inline, and there are *still* stupid compilers about that don't like indented
-pre-processor statements. I suppose it's only been 10 years... */
-
-#ifdef DEBUG
-#define DPRINTF(p) PCRE_PRINTF p
-#else
-#define DPRINTF(p) /*nothing*/
-#endif
-
-/* Include the internals header, which itself includes Standard C headers plus
-the external pcre header. */
-
-#include "pcre_exec.h"
-
-
-/* ---- CODE DELETED ---- */
-
-
-/* Min and max values for the common repeats; for the maxima, 0 => infinity */
-
-static const char rep_min[] = { 0, 0, 1, 1, 0, 0 };
-static const char rep_max[] = { 0, 0, 0, 0, 1, 1 };
-
-
-/* ---- CODE DELETED ---- */
-
-
-/* Structure for building a chain of data that actually lives on the
- * stack, for holding the values of the subject pointer at the start of each
- * subpattern, so as to detect when an empty string has been matched by a
- * subpattern - to break infinite loops. */
-
-typedef struct eptrblock {
- struct eptrblock *prev;
- const uschar *saved_eptr;
-} eptrblock;
-
-/* Flag bits for the match() function */
-
-#define match_condassert 0x01 /* Called to check a condition assertion */
-#define match_isgroup 0x02 /* Set if start of bracketed group */
-
-
-/* ---- CODE DELETED ---- */
-
-
-/*************************************************
- * * Global variables *
- * *************************************************/
-
-/* PCRE is thread-clean and doesn't use any global variables in the normal
- * sense. However, it calls memory allocation and free functions via the two
- * indirections below, which are can be changed by the caller, but are shared
- * between all threads. */
-
-#ifdef __KERNEL__
-static void *kern_malloc(size_t sz)
-{
- return kmalloc(sz, GFP_KERNEL);
-}
-void *(*pcre_malloc)(size_t) = kern_malloc;
-void (*pcre_free)(const void *) = kfree;
-#else
-void *(*pcre_malloc)(size_t) = malloc;
-void (*pcre_free)(const void *) = free;
-#endif
-
-
-/*************************************************
- * * Macros and tables for character handling *
- * *************************************************/
-
-/* When UTF-8 encoding is being used, a character is no longer just a single
- * byte. The macros for character handling generate simple sequences when used in
- * byte-mode, and more complicated ones for UTF-8 characters. */
-
-#ifndef SUPPORT_UTF8
-#define GETCHARINC(c, eptr) c = *eptr++;
-#define GETCHARLEN(c, eptr, len) c = *eptr;
-#define BACKCHAR(eptr)
-#endif
-
-/* ---- CODE DELETED ---- */
-
-#ifdef DEBUG
-/*************************************************
-* Debugging function to print chars *
-*************************************************/
-
-/* Print a sequence of chars in printable format, stopping at the end of the
-subject if the requested.
-
-Arguments:
- p points to characters
- length number to print
- is_subject TRUE if printing from within md->start_subject
- md pointer to matching data block, if is_subject is TRUE
-
-Returns: nothing
-*/
-
-static void
-pchars(const uschar *p, int length, BOOL is_subject, match_data *md)
-{
-int c;
-if (is_subject && length > md->end_subject - p) length = md->end_subject - p;
-while (length-- > 0)
- if (isprint(c = *(p++))) PCRE_PRINTF("%c", c); else PCRE_PRINTF("\\x%02x", c);
-}
-#endif /* DEBUG */
-
-/* ---- CODE DELETED ---- */
-
-
-/*************************************************
-* Match a back-reference *
-*************************************************/
-
-/* If a back reference hasn't been set, the length that is passed is greater
-than the number of characters left in the string, so the match fails.
-
-Arguments:
- offset index into the offset vector
- eptr points into the subject
- length length to be matched
- md points to match data block
- ims the ims flags
-
-Returns: TRUE if matched
-*/
-
-static BOOL
-match_ref(int offset, register const uschar *eptr, int length, match_data *md,
- unsigned long int ims)
-{
-const uschar *p = md->start_subject + md->offset_vector[offset];
-
-#ifdef DEBUG
-if (eptr >= md->end_subject)
- PCRE_PRINTF("matching subject <null>");
-else
- {
- PCRE_PRINTF("matching subject ");
- pchars(eptr, length, TRUE, md);
- }
-PCRE_PRINTF(" against backref ");
-pchars(p, length, FALSE, md);
-PCRE_PRINTF("\n");
-#endif
-
-/* Always fail if not enough characters left */
-
-if (length > md->end_subject - eptr) return FALSE;
-
-/* Separate the caselesss case for speed */
-
-if ((ims & PCRE_CASELESS) != 0)
- {
- while (length-- > 0)
- if (md->lcc[*p++] != md->lcc[*eptr++]) return FALSE;
- }
-else
- { while (length-- > 0) if (*p++ != *eptr++) return FALSE; }
-
-return TRUE;
-}
-
-
-/*************************************************
-* Match from current position *
-*************************************************/
-
-/* On entry ecode points to the first opcode, and eptr to the first character
-in the subject string, while eptrb holds the value of eptr at the start of the
-last bracketed group - used for breaking infinite loops matching zero-length
-strings.
-
-Arguments:
- eptr pointer in subject
- ecode position in code
- offset_top current top pointer
- md pointer to "static" info for the match
- ims current /i, /m, and /s options
- eptrb pointer to chain of blocks containing eptr at start of
- brackets - for testing for empty matches
- flags can contain
- match_condassert - this is an assertion condition
- match_isgroup - this is the start of a bracketed group
-
-Returns: TRUE if matched
-*/
-
-static BOOL
-match(register const uschar *eptr, register const uschar *ecode,
- int offset_top, match_data *md, unsigned long int ims, eptrblock *eptrb,
- int flags)
-{
-unsigned long int original_ims = ims; /* Save for resetting on ')' */
-eptrblock newptrb;
-
-/* At the start of a bracketed group, add the current subject pointer to the
-stack of such pointers, to be re-instated at the end of the group when we hit
-the closing ket. When match() is called in other circumstances, we don't add to
-the stack. */
-
-if ((flags & match_isgroup) != 0)
- {
- newptrb.prev = eptrb;
- newptrb.saved_eptr = eptr;
- eptrb = &newptrb;
- }
-
-/* Now start processing the operations. */
-
-for (;;)
- {
- int op = (int)*ecode;
- int min, max, ctype;
- register int i;
- register int c;
- BOOL minimize = FALSE;
-
- /* Opening capturing bracket. If there is space in the offset vector, save
- the current subject position in the working slot at the top of the vector. We
- mustn't change the current values of the data slot, because they may be set
- from a previous iteration of this group, and be referred to by a reference
- inside the group.
-
- If the bracket fails to match, we need to restore this value and also the
- values of the final offsets, in case they were set by a previous iteration of
- the same bracket.
-
- If there isn't enough space in the offset vector, treat this as if it were a
- non-capturing bracket. Don't worry about setting the flag for the error case
- here; that is handled in the code for KET. */
-
- if (op > OP_BRA)
- {
- int offset;
- int number = op - OP_BRA;
-
- /* For extended extraction brackets (large number), we have to fish out the
- number from a dummy opcode at the start. */
-
- if (number > EXTRACT_BASIC_MAX) number = (ecode[4] << 8) | ecode[5];
- offset = number << 1;
-
-#ifdef DEBUG
- PCRE_PRINTF("start bracket %d subject=", number);
- pchars(eptr, 16, TRUE, md);
- PCRE_PRINTF("\n");
-#endif
-
- if (offset < md->offset_max)
- {
- int save_offset1 = md->offset_vector[offset];
- int save_offset2 = md->offset_vector[offset+1];
- int save_offset3 = md->offset_vector[md->offset_end - number];
-
- DPRINTF(("saving %d %d %d\n", save_offset1, save_offset2, save_offset3));
- md->offset_vector[md->offset_end - number] = eptr - md->start_subject;
-
- do
- {
- if (match(eptr, ecode+3, offset_top, md, ims, eptrb, match_isgroup))
- return TRUE;
- ecode += (ecode[1] << 8) + ecode[2];
- }
- while (*ecode == OP_ALT);
-
- DPRINTF(("bracket %d failed\n", number));
-
- md->offset_vector[offset] = save_offset1;
- md->offset_vector[offset+1] = save_offset2;
- md->offset_vector[md->offset_end - number] = save_offset3;
-
- return FALSE;
- }
-
- /* Insufficient room for saving captured contents */
-
- else op = OP_BRA;
- }
-
- /* Other types of node can be handled by a switch */
-
- switch(op)
- {
- case OP_BRA: /* Non-capturing bracket: optimized */
- DPRINTF(("start bracket 0\n"));
- do
- {
- if (match(eptr, ecode+3, offset_top, md, ims, eptrb, match_isgroup))
- return TRUE;
- ecode += (ecode[1] << 8) + ecode[2];
- }
- while (*ecode == OP_ALT);
- DPRINTF(("bracket 0 failed\n"));
- return FALSE;
-
- /* Conditional group: compilation checked that there are no more than
- two branches. If the condition is false, skipping the first branch takes us
- past the end if there is only one branch, but that's OK because that is
- exactly what going to the ket would do. */
-
- case OP_COND:
- if (ecode[3] == OP_CREF) /* Condition is extraction test */
- {
- int offset = (ecode[4] << 9) | (ecode[5] << 1); /* Doubled ref number */
- return match(eptr,
- ecode + ((offset < offset_top && md->offset_vector[offset] >= 0)?
- 6 : 3 + (ecode[1] << 8) + ecode[2]),
- offset_top, md, ims, eptrb, match_isgroup);
- }
-
- /* The condition is an assertion. Call match() to evaluate it - setting
- the final argument TRUE causes it to stop at the end of an assertion. */
-
- else
- {
- if (match(eptr, ecode+3, offset_top, md, ims, NULL,
- match_condassert | match_isgroup))
- {
- ecode += 3 + (ecode[4] << 8) + ecode[5];
- while (*ecode == OP_ALT) ecode += (ecode[1] << 8) + ecode[2];
- }
- else ecode += (ecode[1] << 8) + ecode[2];
- return match(eptr, ecode+3, offset_top, md, ims, eptrb, match_isgroup);
- }
- /* Control never reaches here */
-
- /* Skip over conditional reference or large extraction number data if
- encountered. */
-
- case OP_CREF:
- case OP_BRANUMBER:
- ecode += 3;
- break;
-
- /* End of the pattern. If PCRE_NOTEMPTY is set, fail if we have matched
- an empty string - recursion will then try other alternatives, if any. */
-
- case OP_END:
- if (md->notempty && eptr == md->start_match) return FALSE;
- md->end_match_ptr = eptr; /* Record where we ended */
- md->end_offset_top = offset_top; /* and how many extracts were taken */
- return TRUE;
-
- /* Change option settings */
-
- case OP_OPT:
- ims = ecode[1];
- ecode += 2;
- DPRINTF(("ims set to %02lx\n", ims));
- break;
-
- /* Assertion brackets. Check the alternative branches in turn - the
- matching won't pass the KET for an assertion. If any one branch matches,
- the assertion is true. Lookbehind assertions have an OP_REVERSE item at the
- start of each branch to move the current point backwards, so the code at
- this level is identical to the lookahead case. */
-
- case OP_ASSERT:
- case OP_ASSERTBACK:
- do
- {
- if (match(eptr, ecode+3, offset_top, md, ims, NULL, match_isgroup)) break;
- ecode += (ecode[1] << 8) + ecode[2];
- }
- while (*ecode == OP_ALT);
- if (*ecode == OP_KET) return FALSE;
-
- /* If checking an assertion for a condition, return TRUE. */
-
- if ((flags & match_condassert) != 0) return TRUE;
-
- /* Continue from after the assertion, updating the offsets high water
- mark, since extracts may have been taken during the assertion. */
-
- do ecode += (ecode[1] << 8) + ecode[2]; while (*ecode == OP_ALT);
- ecode += 3;
- offset_top = md->end_offset_top;
- continue;
-
- /* Negative assertion: all branches must fail to match */
-
- case OP_ASSERT_NOT:
- case OP_ASSERTBACK_NOT:
- do
- {
- if (match(eptr, ecode+3, offset_top, md, ims, NULL, match_isgroup))
- return FALSE;
- ecode += (ecode[1] << 8) + ecode[2];
- }
- while (*ecode == OP_ALT);
-
- if ((flags & match_condassert) != 0) return TRUE;
-
- ecode += 3;
- continue;
-
- /* Move the subject pointer back. This occurs only at the start of
- each branch of a lookbehind assertion. If we are too close to the start to
- move back, this match function fails. When working with UTF-8 we move
- back a number of characters, not bytes. */
-
- case OP_REVERSE:
-#ifdef SUPPORT_UTF8
- c = (ecode[1] << 8) + ecode[2];
- for (i = 0; i < c; i++)
- {
- eptr--;
- BACKCHAR(eptr)
- }
-#else
- eptr -= (ecode[1] << 8) + ecode[2];
-#endif
-
- if (eptr < md->start_subject) return FALSE;
- ecode += 3;
- break;
-
- /* Recursion matches the current regex, nested. If there are any capturing
- brackets started but not finished, we have to save their starting points
- and reinstate them after the recursion. However, we don't know how many
- such there are (offset_top records the completed total) so we just have
- to save all the potential data. There may be up to 99 such values, which
- is a bit large to put on the stack, but using malloc for small numbers
- seems expensive. As a compromise, the stack is used when there are fewer
- than 16 values to store; otherwise malloc is used. A problem is what to do
- if the malloc fails ... there is no way of returning to the top level with
- an error. Save the top 15 values on the stack, and accept that the rest
- may be wrong. */
-
- case OP_RECURSE:
- {
- BOOL rc;
- int *save;
- int stacksave[15];
-
- c = md->offset_max;
-
- if (c < 16) save = stacksave; else
- {
- save = (int *)(pcre_malloc)((c+1) * sizeof(int));
- if (save == NULL)
- {
- save = stacksave;
- c = 15;
- }
- }
-
- for (i = 1; i <= c; i++)
- save[i] = md->offset_vector[md->offset_end - i];
- rc = match(eptr, md->start_pattern, offset_top, md, ims, eptrb,
- match_isgroup);
- for (i = 1; i <= c; i++)
- md->offset_vector[md->offset_end - i] = save[i];
- if (save != stacksave) (pcre_free)(save);
- if (!rc) return FALSE;
-
- /* In case the recursion has set more capturing values, save the final
- number, then move along the subject till after the recursive match,
- and advance one byte in the pattern code. */
-
- offset_top = md->end_offset_top;
- eptr = md->end_match_ptr;
- ecode++;
- }
- break;
-
- /* "Once" brackets are like assertion brackets except that after a match,
- the point in the subject string is not moved back. Thus there can never be
- a move back into the brackets. Check the alternative branches in turn - the
- matching won't pass the KET for this kind of subpattern. If any one branch
- matches, we carry on as at the end of a normal bracket, leaving the subject
- pointer. */
-
- case OP_ONCE:
- {
- const uschar *prev = ecode;
- const uschar *saved_eptr = eptr;
-
- do
- {
- if (match(eptr, ecode+3, offset_top, md, ims, eptrb, match_isgroup))
- break;
- ecode += (ecode[1] << 8) + ecode[2];
- }
- while (*ecode == OP_ALT);
-
- /* If hit the end of the group (which could be repeated), fail */
-
- if (*ecode != OP_ONCE && *ecode != OP_ALT) return FALSE;
-
- /* Continue as from after the assertion, updating the offsets high water
- mark, since extracts may have been taken. */
-
- do ecode += (ecode[1] << 8) + ecode[2]; while (*ecode == OP_ALT);
-
- offset_top = md->end_offset_top;
- eptr = md->end_match_ptr;
-
- /* For a non-repeating ket, just continue at this level. This also
- happens for a repeating ket if no characters were matched in the group.
- This is the forcible breaking of infinite loops as implemented in Perl
- 5.005. If there is an options reset, it will get obeyed in the normal
- course of events. */
-
- if (*ecode == OP_KET || eptr == saved_eptr)
- {
- ecode += 3;
- break;
- }
-
- /* The repeating kets try the rest of the pattern or restart from the
- preceding bracket, in the appropriate order. We need to reset any options
- that changed within the bracket before re-running it, so check the next
- opcode. */
-
- if (ecode[3] == OP_OPT)
- {
- ims = (ims & ~PCRE_IMS) | ecode[4];
- DPRINTF(("ims set to %02lx at group repeat\n", ims));
- }
-
- if (*ecode == OP_KETRMIN)
- {
- if (match(eptr, ecode+3, offset_top, md, ims, eptrb, 0) ||
- match(eptr, prev, offset_top, md, ims, eptrb, match_isgroup))
- return TRUE;
- }
- else /* OP_KETRMAX */
- {
- if (match(eptr, prev, offset_top, md, ims, eptrb, match_isgroup) ||
- match(eptr, ecode+3, offset_top, md, ims, eptrb, 0)) return TRUE;
- }
- }
- return FALSE;
-
- /* An alternation is the end of a branch; scan along to find the end of the
- bracketed group and go to there. */
-
- case OP_ALT:
- do ecode += (ecode[1] << 8) + ecode[2]; while (*ecode == OP_ALT);
- break;
-
- /* BRAZERO and BRAMINZERO occur just before a bracket group, indicating
- that it may occur zero times. It may repeat infinitely, or not at all -
- i.e. it could be ()* or ()? in the pattern. Brackets with fixed upper
- repeat limits are compiled as a number of copies, with the optional ones
- preceded by BRAZERO or BRAMINZERO. */
-
- case OP_BRAZERO:
- {
- const uschar *next = ecode+1;
- if (match(eptr, next, offset_top, md, ims, eptrb, match_isgroup))
- return TRUE;
- do next += (next[1] << 8) + next[2]; while (*next == OP_ALT);
- ecode = next + 3;
- }
- break;
-
- case OP_BRAMINZERO:
- {
- const uschar *next = ecode+1;
- do next += (next[1] << 8) + next[2]; while (*next == OP_ALT);
- if (match(eptr, next+3, offset_top, md, ims, eptrb, match_isgroup))
- return TRUE;
- ecode++;
- }
- break;
-
- /* End of a group, repeated or non-repeating. If we are at the end of
- an assertion "group", stop matching and return TRUE, but record the
- current high water mark for use by positive assertions. Do this also
- for the "once" (not-backup up) groups. */
-
- case OP_KET:
- case OP_KETRMIN:
- case OP_KETRMAX:
- {
- const uschar *prev = ecode - (ecode[1] << 8) - ecode[2];
- const uschar *saved_eptr = eptrb->saved_eptr;
-
- eptrb = eptrb->prev; /* Back up the stack of bracket start pointers */
-
- if (*prev == OP_ASSERT || *prev == OP_ASSERT_NOT ||
- *prev == OP_ASSERTBACK || *prev == OP_ASSERTBACK_NOT ||
- *prev == OP_ONCE)
- {
- md->end_match_ptr = eptr; /* For ONCE */
- md->end_offset_top = offset_top;
- return TRUE;
- }
-
- /* In all other cases except a conditional group we have to check the
- group number back at the start and if necessary complete handling an
- extraction by setting the offsets and bumping the high water mark. */
-
- if (*prev != OP_COND)
- {
- int offset;
- int number = *prev - OP_BRA;
-
- /* For extended extraction brackets (large number), we have to fish out
- the number from a dummy opcode at the start. */
-
- if (number > EXTRACT_BASIC_MAX) number = (prev[4] << 8) | prev[5];
- offset = number << 1;
-
-#ifdef DEBUG
- PCRE_PRINTF("end bracket %d", number);
- PCRE_PRINTF("\n");
-#endif
-
- if (number > 0)
- {
- if (offset >= md->offset_max) md->offset_overflow = TRUE; else
- {
- md->offset_vector[offset] =
- md->offset_vector[md->offset_end - number];
- md->offset_vector[offset+1] = eptr - md->start_subject;
- if (offset_top <= offset) offset_top = offset + 2;
- }
- }
- }
-
- /* Reset the value of the ims flags, in case they got changed during
- the group. */
-
- ims = original_ims;
- DPRINTF(("ims reset to %02lx\n", ims));
-
- /* For a non-repeating ket, just continue at this level. This also
- happens for a repeating ket if no characters were matched in the group.
- This is the forcible breaking of infinite loops as implemented in Perl
- 5.005. If there is an options reset, it will get obeyed in the normal
- course of events. */
-
- if (*ecode == OP_KET || eptr == saved_eptr)
- {
- ecode += 3;
- break;
- }
-
- /* The repeating kets try the rest of the pattern or restart from the
- preceding bracket, in the appropriate order. */
-
- if (*ecode == OP_KETRMIN)
- {
- if (match(eptr, ecode+3, offset_top, md, ims, eptrb, 0) ||
- match(eptr, prev, offset_top, md, ims, eptrb, match_isgroup))
- return TRUE;
- }
- else /* OP_KETRMAX */
- {
- if (match(eptr, prev, offset_top, md, ims, eptrb, match_isgroup) ||
- match(eptr, ecode+3, offset_top, md, ims, eptrb, 0)) return TRUE;
- }
- }
- return FALSE;
-
- /* Start of subject unless notbol, or after internal newline if multiline */
-
- case OP_CIRC:
- if (md->notbol && eptr == md->start_subject) return FALSE;
- if ((ims & PCRE_MULTILINE) != 0)
- {
- if (eptr != md->start_subject && eptr[-1] != NEWLINE) return FALSE;
- ecode++;
- break;
- }
- /* ... else fall through */
-
- /* Start of subject assertion */
-
- case OP_SOD:
- if (eptr != md->start_subject) return FALSE;
- ecode++;
- break;
-
- /* Assert before internal newline if multiline, or before a terminating
- newline unless endonly is set, else end of subject unless noteol is set. */
-
- case OP_DOLL:
- if ((ims & PCRE_MULTILINE) != 0)
- {
- if (eptr < md->end_subject) { if (*eptr != NEWLINE) return FALSE; }
- else { if (md->noteol) return FALSE; }
- ecode++;
- break;
- }
- else
- {
- if (md->noteol) return FALSE;
- if (!md->endonly)
- {
- if (eptr < md->end_subject - 1 ||
- (eptr == md->end_subject - 1 && *eptr != NEWLINE)) return FALSE;
-
- ecode++;
- break;
- }
- }
- /* ... else fall through */
-
- /* End of subject assertion (\z) */
-
- case OP_EOD:
- if (eptr < md->end_subject) return FALSE;
- ecode++;
- break;
-
- /* End of subject or ending \n assertion (\Z) */
-
- case OP_EODN:
- if (eptr < md->end_subject - 1 ||
- (eptr == md->end_subject - 1 && *eptr != NEWLINE)) return FALSE;
- ecode++;
- break;
-
- /* Word boundary assertions */
-
- case OP_NOT_WORD_BOUNDARY:
- case OP_WORD_BOUNDARY:
- {
- BOOL prev_is_word = (eptr != md->start_subject) &&
- ((md->ctypes[eptr[-1]] & ctype_word) != 0);
- BOOL cur_is_word = (eptr < md->end_subject) &&
- ((md->ctypes[*eptr] & ctype_word) != 0);
- if ((*ecode++ == OP_WORD_BOUNDARY)?
- cur_is_word == prev_is_word : cur_is_word != prev_is_word)
- return FALSE;
- }
- break;
-
- /* Match a single character type; inline for speed */
-
- case OP_ANY:
- if ((ims & PCRE_DOTALL) == 0 && eptr < md->end_subject && *eptr == NEWLINE)
- return FALSE;
- if (eptr++ >= md->end_subject) return FALSE;
-#ifdef SUPPORT_UTF8
- if (md->utf8)
- while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
-#endif
- ecode++;
- break;
-
- case OP_NOT_DIGIT:
- if (eptr >= md->end_subject ||
- (md->ctypes[*eptr++] & ctype_digit) != 0)
- return FALSE;
- ecode++;
- break;
-
- case OP_DIGIT:
- if (eptr >= md->end_subject ||
- (md->ctypes[*eptr++] & ctype_digit) == 0)
- return FALSE;
- ecode++;
- break;
-
- case OP_NOT_WHITESPACE:
- if (eptr >= md->end_subject ||
- (md->ctypes[*eptr++] & ctype_space) != 0)
- return FALSE;
- ecode++;
- break;
-
- case OP_WHITESPACE:
- if (eptr >= md->end_subject ||
- (md->ctypes[*eptr++] & ctype_space) == 0)
- return FALSE;
- ecode++;
- break;
-
- case OP_NOT_WORDCHAR:
- if (eptr >= md->end_subject ||
- (md->ctypes[*eptr++] & ctype_word) != 0)
- return FALSE;
- ecode++;
- break;
-
- case OP_WORDCHAR:
- if (eptr >= md->end_subject ||
- (md->ctypes[*eptr++] & ctype_word) == 0)
- return FALSE;
- ecode++;
- break;
-
- /* Match a back reference, possibly repeatedly. Look past the end of the
- item to see if there is repeat information following. The code is similar
- to that for character classes, but repeated for efficiency. Then obey
- similar code to character type repeats - written out again for speed.
- However, if the referenced string is the empty string, always treat
- it as matched, any number of times (otherwise there could be infinite
- loops). */
-
- case OP_REF:
- {
- int length;
- int offset = (ecode[1] << 9) | (ecode[2] << 1); /* Doubled ref number */
- ecode += 3; /* Advance past item */
-
- /* If the reference is unset, set the length to be longer than the amount
- of subject left; this ensures that every attempt at a match fails. We
- can't just fail here, because of the possibility of quantifiers with zero
- minima. */
-
- length = (offset >= offset_top || md->offset_vector[offset] < 0)?
- md->end_subject - eptr + 1 :
- md->offset_vector[offset+1] - md->offset_vector[offset];
-
- /* Set up for repetition, or handle the non-repeated case */
-
- switch (*ecode)
- {
- case OP_CRSTAR:
- case OP_CRMINSTAR:
- case OP_CRPLUS:
- case OP_CRMINPLUS:
- case OP_CRQUERY:
- case OP_CRMINQUERY:
- c = *ecode++ - OP_CRSTAR;
- minimize = (c & 1) != 0;
- min = rep_min[c]; /* Pick up values from tables; */
- max = rep_max[c]; /* zero for max => infinity */
- if (max == 0) max = INT_MAX;
- break;
-
- case OP_CRRANGE:
- case OP_CRMINRANGE:
- minimize = (*ecode == OP_CRMINRANGE);
- min = (ecode[1] << 8) + ecode[2];
- max = (ecode[3] << 8) + ecode[4];
- if (max == 0) max = INT_MAX;
- ecode += 5;
- break;
-
- default: /* No repeat follows */
- if (!match_ref(offset, eptr, length, md, ims)) return FALSE;
- eptr += length;
- continue; /* With the main loop */
- }
-
- /* If the length of the reference is zero, just continue with the
- main loop. */
-
- if (length == 0) continue;
-
- /* First, ensure the minimum number of matches are present. We get back
- the length of the reference string explicitly rather than passing the
- address of eptr, so that eptr can be a register variable. */
-
- for (i = 1; i <= min; i++)
- {
- if (!match_ref(offset, eptr, length, md, ims)) return FALSE;
- eptr += length;
- }
-
- /* If min = max, continue at the same level without recursion.
- They are not both allowed to be zero. */
-
- if (min == max) continue;
-
- /* If minimizing, keep trying and advancing the pointer */
-
- if (minimize)
- {
- for (i = min;; i++)
- {
- if (match(eptr, ecode, offset_top, md, ims, eptrb, 0))
- return TRUE;
- if (i >= max || !match_ref(offset, eptr, length, md, ims))
- return FALSE;
- eptr += length;
- }
- /* Control never gets here */
- }
-
- /* If maximizing, find the longest string and work backwards */
-
- else
- {
- const uschar *pp = eptr;
- for (i = min; i < max; i++)
- {
- if (!match_ref(offset, eptr, length, md, ims)) break;
- eptr += length;
- }
- while (eptr >= pp)
- {
- if (match(eptr, ecode, offset_top, md, ims, eptrb, 0))
- return TRUE;
- eptr -= length;
- }
- return FALSE;
- }
- }
- /* Control never gets here */
-
-
-
- /* Match a character class, possibly repeatedly. Look past the end of the
- item to see if there is repeat information following. Then obey similar
- code to character type repeats - written out again for speed. */
-
- case OP_CLASS:
- {
- const uschar *data = ecode + 1; /* Save for matching */
- ecode += 33; /* Advance past the item */
-
- switch (*ecode)
- {
- case OP_CRSTAR:
- case OP_CRMINSTAR:
- case OP_CRPLUS:
- case OP_CRMINPLUS:
- case OP_CRQUERY:
- case OP_CRMINQUERY:
- c = *ecode++ - OP_CRSTAR;
- minimize = (c & 1) != 0;
- min = rep_min[c]; /* Pick up values from tables; */
- max = rep_max[c]; /* zero for max => infinity */
- if (max == 0) max = INT_MAX;
- break;
-
- case OP_CRRANGE:
- case OP_CRMINRANGE:
- minimize = (*ecode == OP_CRMINRANGE);
- min = (ecode[1] << 8) + ecode[2];
- max = (ecode[3] << 8) + ecode[4];
- if (max == 0) max = INT_MAX;
- ecode += 5;
- break;
-
- default: /* No repeat follows */
- min = max = 1;
- break;
- }
-
- /* First, ensure the minimum number of matches are present. */
-
- for (i = 1; i <= min; i++)
- {
- if (eptr >= md->end_subject) return FALSE;
- GETCHARINC(c, eptr) /* Get character; increment eptr */
-
-#ifdef SUPPORT_UTF8
- /* We do not yet support class members > 255 */
- if (c > 255) return FALSE;
-#endif
-
- if ((data[c/8] & (1 << (c&7))) != 0) continue;
- return FALSE;
- }
-
- /* If max == min we can continue with the main loop without the
- need to recurse. */
-
- if (min == max) continue;
-
- /* If minimizing, keep testing the rest of the expression and advancing
- the pointer while it matches the class. */
-
- if (minimize)
- {
- for (i = min;; i++)
- {
- if (match(eptr, ecode, offset_top, md, ims, eptrb, 0))
- return TRUE;
- if (i >= max || eptr >= md->end_subject) return FALSE;
- GETCHARINC(c, eptr) /* Get character; increment eptr */
-
-#ifdef SUPPORT_UTF8
- /* We do not yet support class members > 255 */
- if (c > 255) return FALSE;
-#endif
- if ((data[c/8] & (1 << (c&7))) != 0) continue;
- return FALSE;
- }
- /* Control never gets here */
- }
-
- /* If maximizing, find the longest possible run, then work backwards. */
-
- else
- {
- const uschar *pp = eptr;
- int len = 1;
- for (i = min; i < max; i++)
- {
- if (eptr >= md->end_subject) break;
- GETCHARLEN(c, eptr, len) /* Get character, set length if UTF-8 */
-
-#ifdef SUPPORT_UTF8
- /* We do not yet support class members > 255 */
- if (c > 255) break;
-#endif
- if ((data[c/8] & (1 << (c&7))) == 0) break;
- eptr += len;
- }
-
- while (eptr >= pp)
- {
- if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0))
- return TRUE;
-
-#ifdef SUPPORT_UTF8
- BACKCHAR(eptr)
-#endif
- }
- return FALSE;
- }
- }
- /* Control never gets here */
-
- /* Match a run of characters */
-
- case OP_CHARS:
- {
- register int length = ecode[1];
- ecode += 2;
-
-#ifdef DEBUG /* Sigh. Some compilers never learn. */
- if (eptr >= md->end_subject)
- PCRE_PRINTF("matching subject <null> against pattern ");
- else
- {
- PCRE_PRINTF("matching subject ");
- pchars(eptr, length, TRUE, md);
- PCRE_PRINTF(" against pattern ");
- }
- pchars(ecode, length, FALSE, md);
- PCRE_PRINTF("\n");
-#endif
-
- if (length > md->end_subject - eptr) return FALSE;
- if ((ims & PCRE_CASELESS) != 0)
- {
- while (length-- > 0)
- if (md->lcc[*ecode++] != md->lcc[*eptr++])
- return FALSE;
- }
- else
- {
- while (length-- > 0) if (*ecode++ != *eptr++) return FALSE;
- }
- }
- break;
-
- /* Match a single character repeatedly; different opcodes share code. */
-
- case OP_EXACT:
- min = max = (ecode[1] << 8) + ecode[2];
- ecode += 3;
- goto REPEATCHAR;
-
- case OP_UPTO:
- case OP_MINUPTO:
- min = 0;
- max = (ecode[1] << 8) + ecode[2];
- minimize = *ecode == OP_MINUPTO;
- ecode += 3;
- goto REPEATCHAR;
-
- case OP_STAR:
- case OP_MINSTAR:
- case OP_PLUS:
- case OP_MINPLUS:
- case OP_QUERY:
- case OP_MINQUERY:
- c = *ecode++ - OP_STAR;
- minimize = (c & 1) != 0;
- min = rep_min[c]; /* Pick up values from tables; */
- max = rep_max[c]; /* zero for max => infinity */
- if (max == 0) max = INT_MAX;
-
- /* Common code for all repeated single-character matches. We can give
- up quickly if there are fewer than the minimum number of characters left in
- the subject. */
-
- REPEATCHAR:
- if (min > md->end_subject - eptr) return FALSE;
- c = *ecode++;
-
- /* The code is duplicated for the caseless and caseful cases, for speed,
- since matching characters is likely to be quite common. First, ensure the
- minimum number of matches are present. If min = max, continue at the same
- level without recursing. Otherwise, if minimizing, keep trying the rest of
- the expression and advancing one matching character if failing, up to the
- maximum. Alternatively, if maximizing, find the maximum number of
- characters and work backwards. */
-
- DPRINTF(("matching %c{%d,%d} against subject %.*s\n", c, min, max,
- max, eptr));
-
- if ((ims & PCRE_CASELESS) != 0)
- {
- c = md->lcc[c];
- for (i = 1; i <= min; i++)
- if (c != md->lcc[*eptr++]) return FALSE;
- if (min == max) continue;
- if (minimize)
- {
- for (i = min;; i++)
- {
- if (match(eptr, ecode, offset_top, md, ims, eptrb, 0))
- return TRUE;
- if (i >= max || eptr >= md->end_subject ||
- c != md->lcc[*eptr++])
- return FALSE;
- }
- /* Control never gets here */
- }
- else
- {
- const uschar *pp = eptr;
- for (i = min; i < max; i++)
- {
- if (eptr >= md->end_subject || c != md->lcc[*eptr]) break;
- eptr++;
- }
- while (eptr >= pp)
- if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0))
- return TRUE;
- return FALSE;
- }
- /* Control never gets here */
- }
-
- /* Caseful comparisons */
-
- else
- {
- for (i = 1; i <= min; i++) if (c != *eptr++) return FALSE;
- if (min == max) continue;
- if (minimize)
- {
- for (i = min;; i++)
- {
- if (match(eptr, ecode, offset_top, md, ims, eptrb, 0))
- return TRUE;
- if (i >= max || eptr >= md->end_subject || c != *eptr++) return FALSE;
- }
- /* Control never gets here */
- }
- else
- {
- const uschar *pp = eptr;
- for (i = min; i < max; i++)
- {
- if (eptr >= md->end_subject || c != *eptr) break;
- eptr++;
- }
- while (eptr >= pp)
- if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0))
- return TRUE;
- return FALSE;
- }
- }
- /* Control never gets here */
-
- /* Match a negated single character */
-
- case OP_NOT:
- if (eptr >= md->end_subject) return FALSE;
- ecode++;
- if ((ims & PCRE_CASELESS) != 0)
- {
- if (md->lcc[*ecode++] == md->lcc[*eptr++]) return FALSE;
- }
- else
- {
- if (*ecode++ == *eptr++) return FALSE;
- }
- break;
-
- /* Match a negated single character repeatedly. This is almost a repeat of
- the code for a repeated single character, but I haven't found a nice way of
- commoning these up that doesn't require a test of the positive/negative
- option for each character match. Maybe that wouldn't add very much to the
- time taken, but character matching *is* what this is all about... */
-
- case OP_NOTEXACT:
- min = max = (ecode[1] << 8) + ecode[2];
- ecode += 3;
- goto REPEATNOTCHAR;
-
- case OP_NOTUPTO:
- case OP_NOTMINUPTO:
- min = 0;
- max = (ecode[1] << 8) + ecode[2];
- minimize = *ecode == OP_NOTMINUPTO;
- ecode += 3;
- goto REPEATNOTCHAR;
-
- case OP_NOTSTAR:
- case OP_NOTMINSTAR:
- case OP_NOTPLUS:
- case OP_NOTMINPLUS:
- case OP_NOTQUERY:
- case OP_NOTMINQUERY:
- c = *ecode++ - OP_NOTSTAR;
- minimize = (c & 1) != 0;
- min = rep_min[c]; /* Pick up values from tables; */
- max = rep_max[c]; /* zero for max => infinity */
- if (max == 0) max = INT_MAX;
-
- /* Common code for all repeated single-character matches. We can give
- up quickly if there are fewer than the minimum number of characters left in
- the subject. */
-
- REPEATNOTCHAR:
- if (min > md->end_subject - eptr) return FALSE;
- c = *ecode++;
-
- /* The code is duplicated for the caseless and caseful cases, for speed,
- since matching characters is likely to be quite common. First, ensure the
- minimum number of matches are present. If min = max, continue at the same
- level without recursing. Otherwise, if minimizing, keep trying the rest of
- the expression and advancing one matching character if failing, up to the
- maximum. Alternatively, if maximizing, find the maximum number of
- characters and work backwards. */
-
- DPRINTF(("negative matching %c{%d,%d} against subject %.*s\n", c, min, max,
- max, eptr));
-
- if ((ims & PCRE_CASELESS) != 0)
- {
- c = md->lcc[c];
- for (i = 1; i <= min; i++)
- if (c == md->lcc[*eptr++]) return FALSE;
- if (min == max) continue;
- if (minimize)
- {
- for (i = min;; i++)
- {
- if (match(eptr, ecode, offset_top, md, ims, eptrb, 0))
- return TRUE;
- if (i >= max || eptr >= md->end_subject ||
- c == md->lcc[*eptr++])
- return FALSE;
- }
- /* Control never gets here */
- }
- else
- {
- const uschar *pp = eptr;
- for (i = min; i < max; i++)
- {
- if (eptr >= md->end_subject || c == md->lcc[*eptr]) break;
- eptr++;
- }
- while (eptr >= pp)
- if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0))
- return TRUE;
- return FALSE;
- }
- /* Control never gets here */
- }
-
- /* Caseful comparisons */
-
- else
- {
- for (i = 1; i <= min; i++) if (c == *eptr++) return FALSE;
- if (min == max) continue;
- if (minimize)
- {
- for (i = min;; i++)
- {
- if (match(eptr, ecode, offset_top, md, ims, eptrb, 0))
- return TRUE;
- if (i >= max || eptr >= md->end_subject || c == *eptr++) return FALSE;
- }
- /* Control never gets here */
- }
- else
- {
- const uschar *pp = eptr;
- for (i = min; i < max; i++)
- {
- if (eptr >= md->end_subject || c == *eptr) break;
- eptr++;
- }
- while (eptr >= pp)
- if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0))
- return TRUE;
- return FALSE;
- }
- }
- /* Control never gets here */
-
- /* Match a single character type repeatedly; several different opcodes
- share code. This is very similar to the code for single characters, but we
- repeat it in the interests of efficiency. */
-
- case OP_TYPEEXACT:
- min = max = (ecode[1] << 8) + ecode[2];
- minimize = TRUE;
- ecode += 3;
- goto REPEATTYPE;
-
- case OP_TYPEUPTO:
- case OP_TYPEMINUPTO:
- min = 0;
- max = (ecode[1] << 8) + ecode[2];
- minimize = *ecode == OP_TYPEMINUPTO;
- ecode += 3;
- goto REPEATTYPE;
-
- case OP_TYPESTAR:
- case OP_TYPEMINSTAR:
- case OP_TYPEPLUS:
- case OP_TYPEMINPLUS:
- case OP_TYPEQUERY:
- case OP_TYPEMINQUERY:
- c = *ecode++ - OP_TYPESTAR;
- minimize = (c & 1) != 0;
- min = rep_min[c]; /* Pick up values from tables; */
- max = rep_max[c]; /* zero for max => infinity */
- if (max == 0) max = INT_MAX;
-
- /* Common code for all repeated single character type matches */
-
- REPEATTYPE:
- ctype = *ecode++; /* Code for the character type */
-
- /* First, ensure the minimum number of matches are present. Use inline
- code for maximizing the speed, and do the type test once at the start
- (i.e. keep it out of the loop). Also we can test that there are at least
- the minimum number of bytes before we start, except when doing '.' in
- UTF8 mode. Leave the test in in all cases; in the special case we have
- to test after each character. */
-
- if (min > md->end_subject - eptr) return FALSE;
- if (min > 0) switch(ctype)
- {
- case OP_ANY:
-#ifdef SUPPORT_UTF8
- if (md->utf8)
- {
- for (i = 1; i <= min; i++)
- {
- if (eptr >= md->end_subject ||
- (*eptr++ == NEWLINE && (ims & PCRE_DOTALL) == 0))
- return FALSE;
- while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
- }
- break;
- }
-#endif
- /* Non-UTF8 can be faster */
- if ((ims & PCRE_DOTALL) == 0)
- { for (i = 1; i <= min; i++) if (*eptr++ == NEWLINE) return FALSE; }
- else eptr += min;
- break;
-
- case OP_NOT_DIGIT:
- for (i = 1; i <= min; i++)
- if ((md->ctypes[*eptr++] & ctype_digit) != 0) return FALSE;
- break;
-
- case OP_DIGIT:
- for (i = 1; i <= min; i++)
- if ((md->ctypes[*eptr++] & ctype_digit) == 0) return FALSE;
- break;
-
- case OP_NOT_WHITESPACE:
- for (i = 1; i <= min; i++)
- if ((md->ctypes[*eptr++] & ctype_space) != 0) return FALSE;
- break;
-
- case OP_WHITESPACE:
- for (i = 1; i <= min; i++)
- if ((md->ctypes[*eptr++] & ctype_space) == 0) return FALSE;
- break;
-
- case OP_NOT_WORDCHAR:
- for (i = 1; i <= min; i++)
- if ((md->ctypes[*eptr++] & ctype_word) != 0)
- return FALSE;
- break;
-
- case OP_WORDCHAR:
- for (i = 1; i <= min; i++)
- if ((md->ctypes[*eptr++] & ctype_word) == 0)
- return FALSE;
- break;
- }
-
- /* If min = max, continue at the same level without recursing */
-
- if (min == max) continue;
-
- /* If minimizing, we have to test the rest of the pattern before each
- subsequent match. */
-
- if (minimize)
- {
- for (i = min;; i++)
- {
- if (match(eptr, ecode, offset_top, md, ims, eptrb, 0)) return TRUE;
- if (i >= max || eptr >= md->end_subject) return FALSE;
-
- c = *eptr++;
- switch(ctype)
- {
- case OP_ANY:
- if ((ims & PCRE_DOTALL) == 0 && c == NEWLINE) return FALSE;
-#ifdef SUPPORT_UTF8
- if (md->utf8)
- while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
-#endif
- break;
-
- case OP_NOT_DIGIT:
- if ((md->ctypes[c] & ctype_digit) != 0) return FALSE;
- break;
-
- case OP_DIGIT:
- if ((md->ctypes[c] & ctype_digit) == 0) return FALSE;
- break;
-
- case OP_NOT_WHITESPACE:
- if ((md->ctypes[c] & ctype_space) != 0) return FALSE;
- break;
-
- case OP_WHITESPACE:
- if ((md->ctypes[c] & ctype_space) == 0) return FALSE;
- break;
-
- case OP_NOT_WORDCHAR:
- if ((md->ctypes[c] & ctype_word) != 0) return FALSE;
- break;
-
- case OP_WORDCHAR:
- if ((md->ctypes[c] & ctype_word) == 0) return FALSE;
- break;
- }
- }
- /* Control never gets here */
- }
-
- /* If maximizing it is worth using inline code for speed, doing the type
- test once at the start (i.e. keep it out of the loop). */
-
- else
- {
- const uschar *pp = eptr;
- switch(ctype)
- {
- case OP_ANY:
-
- /* Special code is required for UTF8, but when the maximum is unlimited
- we don't need it. */
-
-#ifdef SUPPORT_UTF8
- if (md->utf8 && max < INT_MAX)
- {
- if ((ims & PCRE_DOTALL) == 0)
- {
- for (i = min; i < max; i++)
- {
- if (eptr >= md->end_subject || *eptr++ == NEWLINE) break;
- while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
- }
- }
- else
- {
- for (i = min; i < max; i++)
- {
- eptr++;
- while (eptr < md->end_subject && (*eptr & 0xc0) == 0x80) eptr++;
- }
- }
- break;
- }
-#endif
- /* Non-UTF8 can be faster */
- if ((ims & PCRE_DOTALL) == 0)
- {
- for (i = min; i < max; i++)
- {
- if (eptr >= md->end_subject || *eptr == NEWLINE) break;
- eptr++;
- }
- }
- else
- {
- c = max - min;
- if (c > md->end_subject - eptr) c = md->end_subject - eptr;
- eptr += c;
- }
- break;
-
- case OP_NOT_DIGIT:
- for (i = min; i < max; i++)
- {
- if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_digit) != 0)
- break;
- eptr++;
- }
- break;
-
- case OP_DIGIT:
- for (i = min; i < max; i++)
- {
- if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_digit) == 0)
- break;
- eptr++;
- }
- break;
-
- case OP_NOT_WHITESPACE:
- for (i = min; i < max; i++)
- {
- if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_space) != 0)
- break;
- eptr++;
- }
- break;
-
- case OP_WHITESPACE:
- for (i = min; i < max; i++)
- {
- if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_space) == 0)
- break;
- eptr++;
- }
- break;
-
- case OP_NOT_WORDCHAR:
- for (i = min; i < max; i++)
- {
- if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_word) != 0)
- break;
- eptr++;
- }
- break;
-
- case OP_WORDCHAR:
- for (i = min; i < max; i++)
- {
- if (eptr >= md->end_subject || (md->ctypes[*eptr] & ctype_word) == 0)
- break;
- eptr++;
- }
- break;
- }
-
- while (eptr >= pp)
- {
- if (match(eptr--, ecode, offset_top, md, ims, eptrb, 0))
- return TRUE;
-#ifdef SUPPORT_UTF8
- if (md->utf8)
- while (eptr > pp && (*eptr & 0xc0) == 0x80) eptr--;
-#endif
- }
- return FALSE;
- }
- /* Control never gets here */
-
- /* There's been some horrible disaster. */
-
- default:
- DPRINTF(("Unknown opcode %d\n", *ecode));
- md->errorcode = PCRE_ERROR_UNKNOWN_NODE;
- return FALSE;
- }
-
- /* Do not stick any code in here without much thought; it is assumed
- that "continue" in the code above comes out to here to repeat the main
- loop. */
-
- } /* End of main loop */
-/* Control never reaches here */
-}
-
-
-/*************************************************
-* Execute a Regular Expression *
-*************************************************/
-
-/* This function applies a compiled re to a subject string and picks out
-portions of the string if it matches. Two elements in the vector are set for
-each substring: the offsets to the start and end of the substring.
-
-Arguments:
- external_re points to the compiled expression
- external_extra points to "hints" from pcre_study() or is NULL
- subject points to the subject string
- length length of subject string (may contain binary zeros)
- start_offset where to start in the subject string
- options option bits
- offsets points to a vector of ints to be filled in with offsets
- offsetcount the number of elements in the vector
-
-Returns: > 0 => success; value is the number of elements filled in
- = 0 => success, but offsets is not big enough
- -1 => failed to match
- < -1 => some kind of unexpected problem
-*/
-
-int
-pcre_exec(const pcre *external_re, const pcre_extra *external_extra,
- const char *subject, int length, int start_offset, int options, int *offsets,
- int offsetcount)
-{
-int resetcount, ocount;
-int first_char = -1;
-int req_char = -1;
-int req_char2 = -1;
-unsigned long int ims = 0;
-match_data match_block;
-const uschar *start_bits = NULL;
-const uschar *start_match = (const uschar *)subject + start_offset;
-const uschar *end_subject;
-const uschar *req_char_ptr = start_match - 1;
-const real_pcre *re = (const real_pcre *)external_re;
-const real_pcre_extra *extra = (const real_pcre_extra *)external_extra;
-BOOL using_temporary_offsets = FALSE;
-BOOL anchored;
-BOOL startline;
-
-if ((options & ~PUBLIC_EXEC_OPTIONS) != 0) return PCRE_ERROR_BADOPTION;
-
-if (re == NULL || subject == NULL ||
- (offsets == NULL && offsetcount > 0)) return PCRE_ERROR_NULL;
-if (re->magic_number != MAGIC_NUMBER) return PCRE_ERROR_BADMAGIC;
-
-anchored = ((re->options | options) & PCRE_ANCHORED) != 0;
-startline = (re->options & PCRE_STARTLINE) != 0;
-
-match_block.start_pattern = re->code;
-match_block.start_subject = (const uschar *)subject;
-match_block.end_subject = match_block.start_subject + length;
-end_subject = match_block.end_subject;
-
-match_block.endonly = (re->options & PCRE_DOLLAR_ENDONLY) != 0;
-match_block.utf8 = (re->options & PCRE_UTF8) != 0;
-
-match_block.notbol = (options & PCRE_NOTBOL) != 0;
-match_block.noteol = (options & PCRE_NOTEOL) != 0;
-match_block.notempty = (options & PCRE_NOTEMPTY) != 0;
-
-match_block.errorcode = PCRE_ERROR_NOMATCH; /* Default error */
-
-match_block.lcc = re->tables + lcc_offset;
-match_block.ctypes = re->tables + ctypes_offset;
-
-/* The ims options can vary during the matching as a result of the presence
-of (?ims) items in the pattern. They are kept in a local variable so that
-restoring at the exit of a group is easy. */
-
-ims = re->options & (PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL);
-
-/* If the expression has got more back references than the offsets supplied can
-hold, we get a temporary bit of working store to use during the matching.
-Otherwise, we can use the vector supplied, rounding down its size to a multiple
-of 3. */
-
-ocount = offsetcount - (offsetcount % 3);
-
-if (re->top_backref > 0 && re->top_backref >= ocount/3)
- {
- ocount = re->top_backref * 3 + 3;
- match_block.offset_vector = (int *)(pcre_malloc)(ocount * sizeof(int));
- if (match_block.offset_vector == NULL) return PCRE_ERROR_NOMEMORY;
- using_temporary_offsets = TRUE;
- DPRINTF(("Got memory to hold back references\n"));
- }
-else match_block.offset_vector = offsets;
-
-match_block.offset_end = ocount;
-match_block.offset_max = (2*ocount)/3;
-match_block.offset_overflow = FALSE;
-
-/* Compute the minimum number of offsets that we need to reset each time. Doing
-this makes a huge difference to execution time when there aren't many brackets
-in the pattern. */
-
-resetcount = 2 + re->top_bracket * 2;
-if (resetcount > offsetcount) resetcount = ocount;
-
-/* Reset the working variable associated with each extraction. These should
-never be used unless previously set, but they get saved and restored, and so we
-initialize them to avoid reading uninitialized locations. */
-
-if (match_block.offset_vector != NULL)
- {
- register int *iptr = match_block.offset_vector + ocount;
- register int *iend = iptr - resetcount/2 + 1;
- while (--iptr >= iend) *iptr = -1;
- }
-
-/* Set up the first character to match, if available. The first_char value is
-never set for an anchored regular expression, but the anchoring may be forced
-at run time, so we have to test for anchoring. The first char may be unset for
-an unanchored pattern, of course. If there's no first char and the pattern was
-studied, there may be a bitmap of possible first characters. */
-
-if (!anchored)
- {
- if ((re->options & PCRE_FIRSTSET) != 0)
- {
- first_char = re->first_char;
- if ((ims & PCRE_CASELESS) != 0) first_char = match_block.lcc[first_char];
- }
- else
- if (!startline && extra != NULL &&
- (extra->options & PCRE_STUDY_MAPPED) != 0)
- start_bits = extra->start_bits;
- }
-
-/* For anchored or unanchored matches, there may be a "last known required
-character" set. If the PCRE_CASELESS is set, implying that the match starts
-caselessly, or if there are any changes of this flag within the regex, set up
-both cases of the character. Otherwise set the two values the same, which will
-avoid duplicate testing (which takes significant time). This covers the vast
-majority of cases. It will be suboptimal when the case flag changes in a regex
-and the required character in fact is caseful. */
-
-if ((re->options & PCRE_REQCHSET) != 0)
- {
- req_char = re->req_char;
- req_char2 = ((re->options & (PCRE_CASELESS | PCRE_ICHANGED)) != 0)?
- (re->tables + fcc_offset)[req_char] : req_char;
- }
-
-/* Loop for handling unanchored repeated matching attempts; for anchored regexs
-the loop runs just once. */
-
-do
- {
- int rc;
- register int *iptr = match_block.offset_vector;
- register int *iend = iptr + resetcount;
-
- /* Reset the maximum number of extractions we might see. */
-
- while (iptr < iend) *iptr++ = -1;
-
- /* Advance to a unique first char if possible */
-
- if (first_char >= 0)
- {
- if ((ims & PCRE_CASELESS) != 0)
- while (start_match < end_subject &&
- match_block.lcc[*start_match] != first_char)
- start_match++;
- else
- while (start_match < end_subject && *start_match != first_char)
- start_match++;
- }
-
- /* Or to just after \n for a multiline match if possible */
-
- else if (startline)
- {
- if (start_match > match_block.start_subject + start_offset)
- {
- while (start_match < end_subject && start_match[-1] != NEWLINE)
- start_match++;
- }
- }
-
- /* Or to a non-unique first char after study */
-
- else if (start_bits != NULL)
- {
- while (start_match < end_subject)
- {
- register int c = *start_match;
- if ((start_bits[c/8] & (1 << (c&7))) == 0) start_match++; else break;
- }
- }
-
-#ifdef DEBUG /* Sigh. Some compilers never learn. */
- PCRE_PRINTF(">>>> Match against: ");
- pchars(start_match, end_subject - start_match, TRUE, &match_block);
- PCRE_PRINTF("\n");
-#endif
-
- /* If req_char is set, we know that that character must appear in the subject
- for the match to succeed. If the first character is set, req_char must be
- later in the subject; otherwise the test starts at the match point. This
- optimization can save a huge amount of backtracking in patterns with nested
- unlimited repeats that aren't going to match. We don't know what the state of
- case matching may be when this character is hit, so test for it in both its
- cases if necessary. However, the different cased versions will not be set up
- unless PCRE_CASELESS was given or the casing state changes within the regex.
- Writing separate code makes it go faster, as does using an autoincrement and
- backing off on a match. */
-
- if (req_char >= 0)
- {
- register const uschar *p = start_match + ((first_char >= 0)? 1 : 0);
-
- /* We don't need to repeat the search if we haven't yet reached the
- place we found it at last time. */
-
- if (p > req_char_ptr)
- {
- /* Do a single test if no case difference is set up */
-
- if (req_char == req_char2)
- {
- while (p < end_subject)
- {
- if (*p++ == req_char) { p--; break; }
- }
- }
-
- /* Otherwise test for either case */
-
- else
- {
- while (p < end_subject)
- {
- register int pp = *p++;
- if (pp == req_char || pp == req_char2) { p--; break; }
- }
- }
-
- /* If we can't find the required character, break the matching loop */
-
- if (p >= end_subject) break;
-
- /* If we have found the required character, save the point where we
- found it, so that we don't search again next time round the loop if
- the start hasn't passed this character yet. */
-
- req_char_ptr = p;
- }
- }
-
- /* When a match occurs, substrings will be set for all internal extractions;
- we just need to set up the whole thing as substring 0 before returning. If
- there were too many extractions, set the return code to zero. In the case
- where we had to get some local store to hold offsets for backreferences, copy
- those back references that we can. In this case there need not be overflow
- if certain parts of the pattern were not used. */
-
- match_block.start_match = start_match;
- if (!match(start_match, re->code, 2, &match_block, ims, NULL, match_isgroup))
- continue;
-
- /* Copy the offset information from temporary store if necessary */
-
- if (using_temporary_offsets)
- {
- if (offsetcount >= 4)
- {
- memcpy(offsets + 2, match_block.offset_vector + 2,
- (offsetcount - 2) * sizeof(int));
- DPRINTF(("Copied offsets from temporary memory\n"));
- }
- if (match_block.end_offset_top > offsetcount)
- match_block.offset_overflow = TRUE;
-
- DPRINTF(("Freeing temporary memory\n"));
- (pcre_free)(match_block.offset_vector);
- }
-
- rc = match_block.offset_overflow? 0 : match_block.end_offset_top/2;
-
- if (offsetcount < 2) rc = 0; else
- {
- offsets[0] = start_match - match_block.start_subject;
- offsets[1] = match_block.end_match_ptr - match_block.start_subject;
- }
-
- DPRINTF((">>>> returning %d\n", rc));
- return rc;
- }
-
-/* This "while" is the end of the "do" above */
-
-while (!anchored &&
- match_block.errorcode == PCRE_ERROR_NOMATCH &&
- start_match++ < end_subject);
-
-if (using_temporary_offsets)
- {
- DPRINTF(("Freeing temporary memory\n"));
- (pcre_free)(match_block.offset_vector);
- }
-
-DPRINTF((">>>> returning %d\n", match_block.errorcode));
-
-return match_block.errorcode;
-}
-
-/* End of pcre.c */
Index: linux-2.6/security/apparmor/match/pcre_exec.h
===================================================================
--- linux-2.6.orig/security/apparmor/match/pcre_exec.h
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * This is a modified header file containing the definitions from
- * pcre.h and internal.h required to support pcre_exec()
- */
-
-
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* Copyright (c) 1997-2001 University of Cambridge */
-
-#ifndef _PCRE_H
-#define _PCRE_H
-
-/* ----- CODE ADDED ---- */
-
-#ifdef __KERNEL__
-#include <linux/slab.h> // for kmalloc/kfree
-#endif
-
-#ifdef __KERNEL__
-#define PCRE_PRINTF printk
-#define isprint(x) ((unsigned char)(x) >= 128 && (unsigned char)(x) <= 255)
-#else
-#define PCRE_PRINTF printf
-#endif
-
-/* The value of NEWLINE determines the newline character. The default is to
- * leave it up to the compiler, but some sites want to force a particular value.
- * On Unix systems, "configure" can be used to override this default. */
-
-#ifndef NEWLINE
-#define NEWLINE '\n'
-#endif
-
-/* ---- CODE DELETED ---- */
-
-/* Options */
-
-#define PCRE_CASELESS 0x0001
-#define PCRE_MULTILINE 0x0002
-#define PCRE_DOTALL 0x0004
-#define PCRE_EXTENDED 0x0008
-#define PCRE_ANCHORED 0x0010
-#define PCRE_DOLLAR_ENDONLY 0x0020
-#define PCRE_EXTRA 0x0040
-#define PCRE_NOTBOL 0x0080
-#define PCRE_NOTEOL 0x0100
-#define PCRE_UNGREEDY 0x0200
-#define PCRE_NOTEMPTY 0x0400
-#define PCRE_UTF8 0x0800
-
-/* Exec-time and get-time error codes */
-
-#define PCRE_ERROR_NOMATCH (-1)
-#define PCRE_ERROR_NULL (-2)
-#define PCRE_ERROR_BADOPTION (-3)
-#define PCRE_ERROR_BADMAGIC (-4)
-#define PCRE_ERROR_UNKNOWN_NODE (-5)
-#define PCRE_ERROR_NOMEMORY (-6)
-#define PCRE_ERROR_NOSUBSTRING (-7)
-
-/* ---- CODE DELETED ---- */
-
-/* Types */
-
-struct real_pcre; /* declaration; the definition is private */
-struct real_pcre_extra; /* declaration; the definition is private */
-
-typedef struct real_pcre pcre;
-typedef struct real_pcre_extra pcre_extra;
-
-/* ---- CODE DELETED ---- */
-
-extern int pcre_exec(const pcre *, const pcre_extra *,
- const char *, int, int, int, int *,
- int);
-
-/* ---- CODE ADDED (from internal.h) ---- */
-
-/* These are the public options that can change during matching. */
-
-#define PCRE_IMS (PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL)
-
-/* Private options flags start at the most significant end of the four bytes,
-but skip the top bit so we can use ints for convenience without getting tangled
-with negative values. The public options defined in pcre.h start at the least
-significant end. Make sure they don't overlap, though now that we have expanded
-to four bytes there is plenty of space. */
-
-#define PCRE_FIRSTSET 0x40000000 /* first_char is set */
-#define PCRE_REQCHSET 0x20000000 /* req_char is set */
-#define PCRE_STARTLINE 0x10000000 /* start after \n for multiline */
-#define PCRE_ICHANGED 0x04000000 /* i option changes within regex */
-
-/* Options for the "extra" block produced by pcre_study(). */
-
-#define PCRE_STUDY_MAPPED 0x01 /* a map of starting chars exists */
-
-/* Masks for identifying the public options which are permitted at compile
-time, run time or study time, respectively. */
-
-#define PUBLIC_EXEC_OPTIONS \
- (PCRE_ANCHORED|PCRE_NOTBOL|PCRE_NOTEOL|PCRE_NOTEMPTY)
-
-/* Magic number to provide a small check against being handed junk. */
-
-#define MAGIC_NUMBER 0x50435245UL /* 'PCRE' */
-
-typedef int BOOL;
-
-#define FALSE 0
-#define TRUE 1
-
-/* Opcode table: OP_BRA must be last, as all values >= it are used for brackets
-that extract substrings. Starting from 1 (i.e. after OP_END), the values up to
-OP_EOD must correspond in order to the list of escapes immediately above. */
-
-enum {
- OP_END, /* End of pattern */
-
- /* Values corresponding to backslashed metacharacters */
-
- OP_SOD, /* Start of data: \A */
- OP_NOT_WORD_BOUNDARY, /* \B */
- OP_WORD_BOUNDARY, /* \b */
- OP_NOT_DIGIT, /* \D */
- OP_DIGIT, /* \d */
- OP_NOT_WHITESPACE, /* \S */
- OP_WHITESPACE, /* \s */
- OP_NOT_WORDCHAR, /* \W */
- OP_WORDCHAR, /* \w */
- OP_EODN, /* End of data or \n at end of data: \Z. */
- OP_EOD, /* End of data: \z */
-
- OP_OPT, /* Set runtime options */
- OP_CIRC, /* Start of line - varies with multiline switch */
- OP_DOLL, /* End of line - varies with multiline switch */
- OP_ANY, /* Match any character */
- OP_CHARS, /* Match string of characters */
- OP_NOT, /* Match anything but the following char */
-
- OP_STAR, /* The maximizing and minimizing versions of */
- OP_MINSTAR, /* all these opcodes must come in pairs, with */
- OP_PLUS, /* the minimizing one second. */
- OP_MINPLUS, /* This first set applies to single characters */
- OP_QUERY,
- OP_MINQUERY,
- OP_UPTO, /* From 0 to n matches */
- OP_MINUPTO,
- OP_EXACT, /* Exactly n matches */
-
- OP_NOTSTAR, /* The maximizing and minimizing versions of */
- OP_NOTMINSTAR, /* all these opcodes must come in pairs, with */
- OP_NOTPLUS, /* the minimizing one second. */
- OP_NOTMINPLUS, /* This first set applies to "not" single characters */
- OP_NOTQUERY,
- OP_NOTMINQUERY,
- OP_NOTUPTO, /* From 0 to n matches */
- OP_NOTMINUPTO,
- OP_NOTEXACT, /* Exactly n matches */
-
- OP_TYPESTAR, /* The maximizing and minimizing versions of */
- OP_TYPEMINSTAR, /* all these opcodes must come in pairs, with */
- OP_TYPEPLUS, /* the minimizing one second. These codes must */
- OP_TYPEMINPLUS, /* be in exactly the same order as those above. */
- OP_TYPEQUERY, /* This set applies to character types such as \d */
- OP_TYPEMINQUERY,
- OP_TYPEUPTO, /* From 0 to n matches */
- OP_TYPEMINUPTO,
- OP_TYPEEXACT, /* Exactly n matches */
-
- OP_CRSTAR, /* The maximizing and minimizing versions of */
- OP_CRMINSTAR, /* all these opcodes must come in pairs, with */
- OP_CRPLUS, /* the minimizing one second. These codes must */
- OP_CRMINPLUS, /* be in exactly the same order as those above. */
- OP_CRQUERY, /* These are for character classes and back refs */
- OP_CRMINQUERY,
- OP_CRRANGE, /* These are different to the three seta above. */
- OP_CRMINRANGE,
-
- OP_CLASS, /* Match a character class */
- OP_REF, /* Match a back reference */
- OP_RECURSE, /* Match this pattern recursively */
-
- OP_ALT, /* Start of alternation */
- OP_KET, /* End of group that doesn't have an unbounded repeat */
- OP_KETRMAX, /* These two must remain together and in this */
- OP_KETRMIN, /* order. They are for groups the repeat for ever. */
-
- /* The assertions must come before ONCE and COND */
-
- OP_ASSERT, /* Positive lookahead */
- OP_ASSERT_NOT, /* Negative lookahead */
- OP_ASSERTBACK, /* Positive lookbehind */
- OP_ASSERTBACK_NOT, /* Negative lookbehind */
- OP_REVERSE, /* Move pointer back - used in lookbehind assertions */
-
- /* ONCE and COND must come after the assertions, with ONCE first, as there's
- a test for >= ONCE for a subpattern that isn't an assertion. */
-
- OP_ONCE, /* Once matched, don't back up into the subpattern */
- OP_COND, /* Conditional group */
- OP_CREF, /* Used to hold an extraction string number (cond ref) */
-
- OP_BRAZERO, /* These two must remain together and in this */
- OP_BRAMINZERO, /* order. */
-
- OP_BRANUMBER, /* Used for extracting brackets whose number is greater
- than can fit into an opcode. */
-
- OP_BRA /* This and greater values are used for brackets that
- extract substrings up to a basic limit. After that,
- use is made of OP_BRANUMBER. */
-};
-
-/* The highest extraction number before we have to start using additional
-bytes. (Originally PCRE didn't have support for extraction counts highter than
-this number.) The value is limited by the number of opcodes left after OP_BRA,
-i.e. 255 - OP_BRA. We actually set it a bit lower to leave room for additional
-opcodes. */
-
-#define EXTRACT_BASIC_MAX 150
-
-/* All character handling must be done as unsigned characters. Otherwise there
-are problems with top-bit-set characters and functions such as isspace().
-However, we leave the interface to the outside world as char *, because that
-should make things easier for callers. We define a short type for unsigned char
-to save lots of typing. I tried "uchar", but it causes problems on Digital
-Unix, where it is defined in sys/types, so use "uschar" instead. */
-
-typedef unsigned char uschar;
-
-/* The real format of the start of the pcre block; the actual code vector
-runs on as long as necessary after the end. */
-
-typedef struct real_pcre {
- unsigned long int magic_number;
- size_t size;
- const unsigned char *tables;
- unsigned long int options;
- unsigned short int top_bracket;
- unsigned short int top_backref;
- uschar first_char;
- uschar req_char;
- uschar code[1];
-} real_pcre;
-
-/* The real format of the extra block returned by pcre_study(). */
-
-typedef struct real_pcre_extra {
- uschar options;
- uschar start_bits[32];
-} real_pcre_extra;
-
-/* Structure for passing "static" information around between the functions
-doing the matching, so that they are thread-safe. */
-
-typedef struct match_data {
- int errorcode; /* As it says */
- int *offset_vector; /* Offset vector */
- int offset_end; /* One past the end */
- int offset_max; /* The maximum usable for return data */
- const uschar *lcc; /* Points to lower casing table */
- const uschar *ctypes; /* Points to table of type maps */
- BOOL offset_overflow; /* Set if too many extractions */
- BOOL notbol; /* NOTBOL flag */
- BOOL noteol; /* NOTEOL flag */
- BOOL utf8; /* UTF8 flag */
- BOOL endonly; /* Dollar not before final \n */
- BOOL notempty; /* Empty string match not wanted */
- const uschar *start_pattern; /* For use when recursing */
- const uschar *start_subject; /* Start of the subject string */
- const uschar *end_subject; /* End of the subject string */
- const uschar *start_match; /* Start of this match attempt */
- const uschar *end_match_ptr; /* Subject position at end match */
- int end_offset_top; /* Highwater mark at end of match */
-} match_data;
-
-/* Bit definitions for entries in the pcre_ctypes table. */
-
-#define ctype_space 0x01
-#define ctype_letter 0x02
-#define ctype_digit 0x04
-#define ctype_xdigit 0x08
-#define ctype_word 0x10 /* alphameric or '_' */
-#define ctype_meta 0x80 /* regexp meta char or zero (end pattern) */
-
-/* Offsets for the bitmap tables in pcre_cbits. Each table contains a set
-of bits for a class map. Some classes are built by combining these tables. */
-
-#define cbit_length 320 /* Length of the cbits table */
-
-/* Offsets of the various tables from the base tables pointer, and
-total length. */
-
-#define lcc_offset 0
-#define fcc_offset 256
-
-#define fcc_offset 256
-#define cbits_offset 512
-#define ctypes_offset (cbits_offset + cbit_length)
-
-/* ----- CODE ADDED ---- */
-
-#endif // _PCRE_H
- /* End of pcre.h */
Index: linux-2.6/security/apparmor/match/pcre_tables.h
===================================================================
--- linux-2.6.orig/security/apparmor/match/pcre_tables.h
+++ /dev/null
@@ -1,184 +0,0 @@
-
-/*************************************************
-* Perl-Compatible Regular Expressions *
-*************************************************/
-
-/* This file is automatically written by the dftables auxiliary
-program. If you edit it by hand, you might like to edit the Makefile to
-prevent its ever being regenerated.
-
-This file is #included in the compilation of pcre.c to build the default
-character tables which are used when no tables are passed to the compile
-function. */
-
-static unsigned char pcre_default_tables[] = {
-
-/* This table is a lower casing table. */
-
- 0, 1, 2, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39,
- 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55,
- 56, 57, 58, 59, 60, 61, 62, 63,
- 64, 97, 98, 99,100,101,102,103,
- 104,105,106,107,108,109,110,111,
- 112,113,114,115,116,117,118,119,
- 120,121,122, 91, 92, 93, 94, 95,
- 96, 97, 98, 99,100,101,102,103,
- 104,105,106,107,108,109,110,111,
- 112,113,114,115,116,117,118,119,
- 120,121,122,123,124,125,126,127,
- 128,129,130,131,132,133,134,135,
- 136,137,138,139,140,141,142,143,
- 144,145,146,147,148,149,150,151,
- 152,153,154,155,156,157,158,159,
- 160,161,162,163,164,165,166,167,
- 168,169,170,171,172,173,174,175,
- 176,177,178,179,180,181,182,183,
- 184,185,186,187,188,189,190,191,
- 192,193,194,195,196,197,198,199,
- 200,201,202,203,204,205,206,207,
- 208,209,210,211,212,213,214,215,
- 216,217,218,219,220,221,222,223,
- 224,225,226,227,228,229,230,231,
- 232,233,234,235,236,237,238,239,
- 240,241,242,243,244,245,246,247,
- 248,249,250,251,252,253,254,255,
-
-/* This table is a case flipping table. */
-
- 0, 1, 2, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39,
- 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55,
- 56, 57, 58, 59, 60, 61, 62, 63,
- 64, 97, 98, 99,100,101,102,103,
- 104,105,106,107,108,109,110,111,
- 112,113,114,115,116,117,118,119,
- 120,121,122, 91, 92, 93, 94, 95,
- 96, 65, 66, 67, 68, 69, 70, 71,
- 72, 73, 74, 75, 76, 77, 78, 79,
- 80, 81, 82, 83, 84, 85, 86, 87,
- 88, 89, 90,123,124,125,126,127,
- 128,129,130,131,132,133,134,135,
- 136,137,138,139,140,141,142,143,
- 144,145,146,147,148,149,150,151,
- 152,153,154,155,156,157,158,159,
- 160,161,162,163,164,165,166,167,
- 168,169,170,171,172,173,174,175,
- 176,177,178,179,180,181,182,183,
- 184,185,186,187,188,189,190,191,
- 192,193,194,195,196,197,198,199,
- 200,201,202,203,204,205,206,207,
- 208,209,210,211,212,213,214,215,
- 216,217,218,219,220,221,222,223,
- 224,225,226,227,228,229,230,231,
- 232,233,234,235,236,237,238,239,
- 240,241,242,243,244,245,246,247,
- 248,249,250,251,252,253,254,255,
-
-/* This table contains bit maps for various character classes.
-Each map is 32 bytes long and the bits run from the least
-significant end of each byte. The classes that have their own
-maps are: space, xdigit, digit, upper, lower, word, graph
-print, punct, and cntrl. Other classes are built from combinations. */
-
- 0x00,0x3e,0x00,0x00,0x01,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-
- 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,
- 0x7e,0x00,0x00,0x00,0x7e,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-
- 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0xfe,0xff,0xff,0x07,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0x07,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-
- 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,
- 0xfe,0xff,0xff,0x87,0xfe,0xff,0xff,0x07,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-
- 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,
- 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-
- 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,
- 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-
- 0x00,0x00,0x00,0x00,0xfe,0xff,0x00,0xfc,
- 0x01,0x00,0x00,0xf8,0x01,0x00,0x00,0x78,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-
- 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-
-/* This table identifies various classes of character by individual bits:
- 0x01 white space character
- 0x02 letter
- 0x04 decimal digit
- 0x08 hexadecimal digit
- 0x10 alphanumeric or '_'
- 0x80 regular expression metacharacter or binary zero
-*/
-
- 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 */
- 0x00,0x01,0x01,0x01,0x01,0x01,0x00,0x00, /* 8- 15 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16- 23 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */
- 0x01,0x00,0x00,0x00,0x80,0x00,0x00,0x00, /* - ' */
- 0x80,0x80,0x80,0x80,0x00,0x00,0x80,0x00, /* ( - / */
- 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, /* 0 - 7 */
- 0x1c,0x1c,0x00,0x00,0x00,0x00,0x00,0x80, /* 8 - ? */
- 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* @ - G */
- 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* H - O */
- 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* P - W */
- 0x12,0x12,0x12,0x80,0x00,0x00,0x80,0x10, /* X - _ */
- 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* ` - g */
- 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* h - o */
- 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* p - w */
- 0x12,0x12,0x12,0x80,0x80,0x00,0x00,0x00, /* x -127 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 128-135 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 136-143 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144-151 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 152-159 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160-167 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 168-175 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176-183 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 192-199 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 200-207 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 208-215 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 216-223 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 224-231 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 232-239 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 240-247 */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/* 248-255 */
-
-/* End of chartables.c */
Index: linux-2.6/security/apparmor/module_interface.c
===================================================================
--- linux-2.6.orig/security/apparmor/module_interface.c
+++ linux-2.6/security/apparmor/module_interface.c
@@ -14,7 +14,6 @@
#include "apparmor.h"
#include "inline.h"
#include "module_interface.h"
-#include "match/match.h"
/* aa_code defined in module_interface.h */
@@ -25,40 +24,6 @@ struct aa_taskreplace_data {
struct aaprofile *new_profile;
};
-/* inlines must be forward of there use in newer version of gcc,
- just forward declaring with a prototype won't work anymore */
-
-static inline void free_aa_entry(struct aa_entry *entry)
-{
- if (entry) {
- kfree(entry->filename);
- aamatch_free(entry->extradata);
- kfree(entry);
- }
-}
-
-/**
- * alloc_aa_entry - create new empty aa_entry
- * This routine allocates, initializes, and returns a new aa_entry
- * file entry structure. Structure is zeroed. Returns new structure on
- * success, %NULL on failure.
- */
-static inline struct aa_entry *alloc_aa_entry(void)
-{
- struct aa_entry *entry;
-
- AA_DEBUG("%s\n", __FUNCTION__);
- entry = kzalloc(sizeof(struct aa_entry), GFP_KERNEL);
- if (entry) {
- int i;
- INIT_LIST_HEAD(&entry->list);
- for (i = 0; i <= POS_AA_FILE_MAX; i++) {
- INIT_LIST_HEAD(&entry->listp[i]);
- }
- }
- return entry;
-}
-
/**
* free_aaprofile_rcu - rcu callback for free profiles
* @head: rcu_head struct of the profile whose reference is being put.
@@ -392,144 +357,38 @@ fail:
}
/**
- * aa_activate_file_entry - unpack serialized file entry
+ * aa_activate_dfa - unpack a file rule dfa
* @e: serialized data extent information
*
- * unpack the information used for a file ACL entry.
+ * returns dfa or ERR_PTR
*/
-static inline struct aa_entry *aa_activate_file_entry(struct aa_ext *e)
+struct aa_dfa *aa_activate_dfa(struct aa_ext *e)
{
- struct aa_entry *entry = NULL;
-
- if (!(entry = alloc_aa_entry()))
- goto fail;
-
- AA_READ_X(e, AA_STRUCT, NULL, "fe");
- AA_READ_X(e, AA_DYN_STRING, &entry->filename, NULL);
- AA_READ_X(e, AA_U32, &entry->mode, NULL);
- AA_READ_X(e, AA_U32, &entry->type, NULL);
-
- entry->extradata = aamatch_alloc(entry->type);
- if (IS_ERR(entry->extradata)) {
- entry->extradata = NULL;
- goto fail;
- }
-
- if (entry->extradata &&
- aamatch_serialize(entry->extradata, e, aa_is_nameX) != 0) {
- goto fail;
- }
- AA_READ_X(e, AA_STRUCTEND, NULL, NULL);
-
- switch (entry->type) {
- case aa_entry_literal:
- AA_DEBUG("%s: %s [no pattern] mode=0x%x\n",
- __FUNCTION__,
- entry->filename,
- entry->mode);
- break;
- case aa_entry_tailglob:
- AA_DEBUG("%s: %s [tailglob] mode=0x%x\n",
- __FUNCTION__,
- entry->filename,
- entry->mode);
- break;
- case aa_entry_pattern:
- AA_DEBUG("%s: %s mode=0x%x\n",
- __FUNCTION__,
- entry->filename,
- entry->mode);
- break;
- default:
- AA_WARN("%s: INVALID entry_match_type %d\n",
- __FUNCTION__,
- (int)entry->type);
- goto fail;
- }
-
- return entry;
-
-fail:
- free_aa_entry(entry);
- return NULL;
-}
-
-/**
- * check_rule_and_add - check a file rule is valid and add to a profile
- * @file_entry: file rule to add
- * @profile: profile to add the rule to
- * @message: error message returned if the addition failes.
- *
- * perform consistency check to ensure that a file rule entry is valid.
- * If the rule is valid it is added to the profile.
- */
-static inline int check_rule_and_add(struct aa_entry *file_entry,
- struct aaprofile *profile,
- const char **message)
-{
- /* verify consistency of x, px, ix, ux for entry against
- possible duplicates for this entry */
- int mode = AA_EXEC_MODIFIER_MASK(file_entry->mode);
- int i;
-
- if (mode && !(AA_MAY_EXEC & file_entry->mode)) {
- *message = "inconsistent rule, x modifiers without x";
- goto out;
- }
-
- /* check that only 1 of the modifiers is set */
- if (mode && (mode & (mode - 1))) {
- *message = "inconsistent rule, multiple x modifiers";
- goto out;
- }
+ char *blob = NULL;
+ size_t size, error = 0;
+ struct aa_dfa *dfa = NULL;
+
+ size = aa_is_nameX(e, AA_BLOB_LOC, &blob, "aadfa");
+ if (size) {
+ dfa = aamatch_alloc();
+ if (dfa) {
+ error = unpack_dfa(dfa, blob, size);
+
+ if (!error)
+ error = verify_dfa(dfa);
+ } else {
+ error = -ENOMEM;
+ }
- /* ix -> m (required so that target exec binary may map itself) */
- if (mode & AA_EXEC_INHERIT)
- file_entry->mode |= AA_EXEC_MMAP;
-
- list_add(&file_entry->list, &profile->file_entry);
- profile->num_file_entries++;
-
- mode = file_entry->mode;
-
- /* Handle partitioned lists
- * Chain entries onto sublists based on individual
- * permission bits. This allows more rapid searching.
- */
- for (i = 0; i <= POS_AA_FILE_MAX; i++) {
- if (mode & (1 << i))
- /* profile->file_entryp[i] initially set to
- * NULL in alloc_aaprofile() */
- list_add(&file_entry->listp[i],
- &profile->file_entryp[i]);
+ if (error) {
+ aamatch_free(dfa);
+ dfa = ERR_PTR(error);
+ }
}
- return 1;
-
-out:
- free_aa_entry(file_entry);
- return 0;
+ return dfa;
}
-#define AA_ENTRY_LIST(NAME) \
- do { \
- if (aa_is_nameX(e, AA_LIST, NULL, (NAME))) { \
- rulename = ""; \
- error_string = "Invalid file entry"; \
- while (!aa_is_nameX(e, AA_LISTEND, NULL, NULL)) { \
- struct aa_entry *file_entry; \
- file_entry = aa_activate_file_entry(e); \
- if (!file_entry) \
- goto fail; \
- if (!check_rule_and_add(file_entry, profile, \
- &error_string)) { \
- rulename = file_entry->filename; \
- goto fail; \
- } \
- } \
- } \
- } while (0)
-
/**
* aa_activate_profile - unpack a serialized profile
* @e: serialized data extent information
@@ -565,10 +424,14 @@ static struct aaprofile *aa_activate_pro
error_string = "Invalid capabilities";
AA_READ_X(e, AA_U32, &(profile->capabilities), NULL);
- /* get the file entries. */
- AA_ENTRY_LIST("pgent"); /* pcre rules */
- AA_ENTRY_LIST("sgent"); /* simple globs */
- AA_ENTRY_LIST("fent"); /* regular file entries */
+ /* get file rules */
+ profile->file_rules = aa_activate_dfa(e);
+ if (IS_ERR(profile->file_rules)) {
+ error_string = "Invalid file rule dfa\n";
+ *error = PTR_ERR(profile->file_rules);
+ profile->file_rules = NULL;
+ goto fail;
+ }
/* get the net entries */
if (aa_is_nameX(e, AA_LIST, NULL, "net")) {
@@ -631,7 +494,7 @@ static void *aa_activate_top_profile(str
}
/* check that the interface version is currently supported */
- if (e->version != 2) {
+ if (e->version != 3) {
AA_WARN("%s: unsupported interface version (%d)\n",
INTERFACE_ID, e->version);
*error = -EPROTONOSUPPORT;
@@ -816,7 +679,6 @@ void free_aaprofile_kref(struct kref *kr
*/
void free_aaprofile(struct aaprofile *profile)
{
- struct aa_entry *ent, *tmp;
struct aaprofile *p, *ptmp;
AA_DEBUG("%s(%p)\n", __FUNCTION__, profile);
@@ -833,13 +695,7 @@ void free_aaprofile(struct aaprofile *pr
BUG();
}
- list_for_each_entry_safe(ent, tmp, &profile->file_entry, list) {
- if (ent->filename)
- AA_DEBUG("freeing aa_entry: %p %s\n",
- ent->filename, ent->filename);
- list_del_init(&ent->list);
- free_aa_entry(ent);
- }
+ aamatch_free(profile->file_rules);
/* use free_aaprofile instead of put_aaprofile to destroy the
* null_profile, because the null_profile use the same reference
Index: linux-2.6/security/apparmor/apparmorfs.c
===================================================================
--- linux-2.6.orig/security/apparmor/apparmorfs.c
+++ linux-2.6/security/apparmor/apparmorfs.c
@@ -17,7 +17,6 @@
#include "apparmor.h"
#include "inline.h"
-#include "match/match.h"
#define SECFS_AA "apparmor"
static struct dentry *aafs_dentry = NULL;
Index: linux-2.6/security/apparmor/match.c
===================================================================
--- /dev/null
+++ linux-2.6/security/apparmor/match.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2002-2005 Novell/SUSE
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * http://forge.novell.com/modules/xfmod/project/?apparmor
+ *
+ * AppArmor aamatch submodule (w/ pattern expansion).
+ *
+ */
+
+#include <asm/unaligned.h>
+#include <linux/module.h>
+#include "match.h"
+
+static const char *features="pattern=aadfa";
+
+static struct table_header *unpack_table(void *blob, size_t bsize)
+{
+ struct table_header *table = NULL;
+ struct table_header th;
+ size_t tsize;
+
+ if (bsize < sizeof(struct table_header))
+ goto out;
+
+ th.td_id = ntohs(get_unaligned((u16 *) (blob)));
+ th.td_flags = ntohs(get_unaligned((u16 *) (blob + 2)));
+ th.td_lolen = ntohl(get_unaligned((u32 *) (blob + 8)));
+ blob += sizeof(struct table_header);
+
+ if (!(th.td_flags == YYTD_DATA16 || th.td_flags == YYTD_DATA32 ||
+ th.td_flags == YYTD_DATA8))
+ goto out;
+
+ tsize = table_size(th.td_lolen, th.td_flags);
+ if (bsize < tsize)
+ goto out;
+
+ table = kmalloc(tsize, GFP_KERNEL);
+ if (table) {
+ *table = th;
+ if (th.td_flags == YYTD_DATA8)
+ UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
+ u8, ntohb);
+ else if (th.td_flags == YYTD_DATA16)
+ UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
+ u16, ntohs);
+ else
+ UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
+ u32, ntohl);
+ }
+
+out:
+ return table;
+}
+
+int unpack_dfa(struct aa_dfa *dfa, void *blob, size_t size)
+{
+ int i;
+ int error = -ENOMEM;
+
+ /* get dfa table set header */
+ if (size < sizeof(struct table_set_header))
+ goto fail;
+
+ dfa->th.th_magic = ntohl(get_unaligned((u32 *) (blob + 0)));
+ dfa->th.th_hsize = ntohl(get_unaligned((u32 *) (blob + 4)));
+ dfa->th.th_ssize = ntohl(get_unaligned((u32 *) (blob + 8)));
+ dfa->th.th_flags = ntohs(get_unaligned((u16 *) (blob + 12)));
+
+ if (dfa->th.th_magic != YYTH_MAGIC)
+ goto fail;
+
+ if (size < dfa->th.th_hsize)
+ goto fail;
+
+ blob += dfa->th.th_hsize;
+ size -= dfa->th.th_hsize;
+
+ while (size > 0) {
+ struct table_header *table;
+ table = unpack_table(blob, size);
+ if (!table)
+ goto fail;
+
+ switch(table->td_id) {
+ case YYTD_ID_ACCEPT:
+ case YYTD_ID_BASE:
+ dfa->tables[table->td_id - 1] = table;
+ if (table->td_flags != YYTD_DATA32)
+ goto fail_proto;
+ break;
+ case YYTD_ID_DEF:
+ case YYTD_ID_NXT:
+ case YYTD_ID_CHK:
+ dfa->tables[table->td_id - 1] = table;
+ if (table->td_flags != YYTD_DATA16)
+ goto fail_proto;
+ break;
+ case YYTD_ID_EC:
+ dfa->tables[table->td_id - 1] = table;
+ if (table->td_flags != YYTD_DATA8)
+ goto fail_proto;
+ break;
+ default:
+ kfree(table);
+ goto fail_proto;
+ }
+
+ blob += table_size(table->td_lolen, table->td_flags);
+ size -= table_size(table->td_lolen, table->td_flags);
+ }
+
+ error = 0;
+
+ return error;
+
+fail_proto:
+ error = -EPROTO;
+fail:
+ for (i = 0; i < YYTD_ID_NXT; i++) {
+ if (dfa->tables[i]) {
+ kfree(dfa->tables[i]);
+ dfa->tables[i] = NULL;
+ }
+ }
+ return error;
+}
+
+/**
+ * verify_dfa - verify that all the transitions and states in the dfa tables
+ * are in bounds.
+ * @dfa: dfa to test
+ *
+ * assumes dfa has gone through the verification done by unpacking
+ */
+int verify_dfa(struct aa_dfa *dfa)
+{
+ size_t i, state_count, trans_count;
+ int error = -EPROTO;
+
+ /* check that required tables exist */
+ if (!(dfa->tables[YYTD_ID_ACCEPT -1 ] &&
+ dfa->tables[YYTD_ID_DEF - 1] &&
+ dfa->tables[YYTD_ID_BASE - 1] &&
+ dfa->tables[YYTD_ID_NXT - 1] &&
+ dfa->tables[YYTD_ID_CHK - 1]))
+ goto out;
+
+ /* accept.size == default.size == base.size */
+ state_count = dfa->tables[YYTD_ID_BASE - 1]->td_lolen;
+ if (!(state_count == dfa->tables[YYTD_ID_DEF - 1]->td_lolen &&
+ state_count == dfa->tables[YYTD_ID_ACCEPT - 1]->td_lolen))
+ goto out;
+
+ /* next.size == chk.size */
+ trans_count = dfa->tables[YYTD_ID_NXT - 1]->td_lolen;
+ if (trans_count != dfa->tables[YYTD_ID_CHK - 1]->td_lolen)
+ goto out;
+
+ /* if equivalence classes then its table must be 256 */
+ if (dfa->tables[YYTD_ID_EC - 1] &&
+ dfa->tables[YYTD_ID_EC - 1]->td_lolen != 256)
+ goto out;
+
+ for (i = 0; i < state_count; i++) {
+ if (DEFAULT_TABLE(dfa)[i] >= state_count)
+ goto out;
+ if (BASE_TABLE(dfa)[i] >= trans_count + 256)
+ goto out;
+ }
+
+ for (i = 0; i < trans_count ; i++) {
+ if (NEXT_TABLE(dfa)[i] >= state_count)
+ goto out;
+ if (CHECK_TABLE(dfa)[i] >= state_count)
+ goto out;
+ }
+
+ error = 0;
+out:
+ return error;
+}
+
+struct aa_dfa *aamatch_alloc(void)
+{
+ return kzalloc(sizeof(struct aa_dfa), GFP_KERNEL);
+}
+
+void aamatch_free(struct aa_dfa *dfa)
+{
+ if (dfa) {
+ int i;
+ for (i = 0; i < YYTD_ID_NXT; i++) {
+ kfree(dfa->tables[i]);
+ }
+ }
+ kfree(dfa);
+}
+
+const char *aamatch_features(void)
+{
+ return features;
+}
+
+/**
+ * aadfa_label - return the permissions associated with @state
+ * @dfa: dfa to get state permission from
+ * @state: state in the dfa for which to get a label
+ *
+ * Assumes that state is a valid state of the dfa
+ *
+ * Returns the label associated with @state. 0 indicates the state
+ * is no-accepting/provides no permissions.
+ */
+inline unsigned int aadfa_label(struct aa_dfa *dfa, int state)
+{
+ return ACCEPT_TABLE(dfa)[state];
+}
+
+/**
+ * aadfa_match - match @path against @dfa starting in @state
+ * @dfa: the dfa to match @path against
+ * @state: the state to start matching in
+ * @path: the path to match against the dfa
+ *
+ * aadfa_match will match the full path length and return the state it
+ * finished matching in. The final state returned can be used to
+ * lookup the accepting label or as a starting point to continue matching
+ * with a new string if the path has been broken into multiple components.
+ */
+inline unsigned int aadfa_match(struct aa_dfa *dfa, unsigned int state,
+ const char *path)
+{
+ u8 *s = (u8 *) path;
+ 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 *s */
+ if (dfa->tables[YYTD_ID_EC - 1]) {
+ u8 *equiv = EQUIV_TABLE(dfa);
+ for ( ; *s; ++s) {
+ pos = base[state] + equiv[*s];
+ if (check[pos] == state)
+ state = next[pos];
+ else
+ state = def[state];
+ }
+ } else {
+ for ( ; *s; ++s) {
+ pos = base[state] + *s;
+ if (check[pos] == state)
+ state = next[pos];
+ else
+ state = def[state];
+ }
+ }
+ return state;
+}
+
+unsigned int aamatch(struct aa_dfa *dfa, const char *pathname)
+{
+ if (dfa)
+ return aadfa_label(dfa, aadfa_match(dfa, 1, pathname));
+
+ return 0;
+}
Index: linux-2.6/security/apparmor/match.h
===================================================================
--- /dev/null
+++ linux-2.6/security/apparmor/match.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2002-2005 Novell/SUSE
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * AppArmor submodule (match) prototypes
+ */
+
+#ifndef __MATCH_H
+#define __MATCH_H
+
+#define YYTH_MAGIC 0x1B5E783D
+
+struct table_set_header {
+ u32 th_magic; /* TH_MAGIC */
+ u32 th_hsize;
+ u32 th_ssize;
+ u16 th_flags;
+ char th_version[];
+};
+
+#define YYTD_ID_ACCEPT 1 /* 1 */
+#define YYTD_ID_BASE 2 /* 2 */
+#define YYTD_ID_CHK 3 /* 3 */
+#define YYTD_ID_DEF 4 /* 4 */
+#define YYTD_ID_EC 5 /* 5 */
+#define YYTD_ID_NXT 6 /* 8 */
+#define YYTD_ID_META 7 /* 6 */
+
+#define YYTD_DATA8 1
+#define YYTD_DATA16 2
+#define YYTD_DATA32 4
+
+struct table_header {
+ u16 td_id;
+ u16 td_flags;
+ u32 td_hilen;
+ u32 td_lolen;
+ char td_data[];
+};
+
+#define DEFAULT_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_DEF - 1]->td_data))
+#define BASE_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_BASE - 1]->td_data))
+#define NEXT_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_NXT - 1]->td_data))
+#define CHECK_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_CHK - 1]->td_data))
+#define EQUIV_TABLE(DFA) ((u8 *)((DFA)->tables[YYTD_ID_EC - 1]->td_data))
+#define ACCEPT_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT - 1]->td_data))
+
+struct aa_dfa {
+ struct table_header *tables[YYTD_ID_NXT];
+
+ struct table_set_header th;
+};
+
+#define ntohb(X) (X)
+
+#define UNPACK_ARRAY(TABLE, BLOB, LEN, TYPE, NTOHX) \
+ do { \
+ typeof(LEN) __i; \
+ TYPE *__t = (TYPE *) TABLE; \
+ TYPE *__b = (TYPE *) BLOB; \
+ for (__i = 0; __i < LEN; __i++) { \
+ __t[__i] = NTOHX(__b[__i]); \
+ } \
+ } while (0)
+
+static inline size_t pad64(size_t i)
+{
+ return (i + (size_t)7) & ~(size_t)7;
+}
+
+static inline size_t table_size(size_t len, size_t el_size)
+{
+ return pad64(sizeof(struct table_header) + len * el_size);
+}
+
+#endif /* __MATCH_H */