Add dfa support to the parser

This commit is contained in:
John Johansen 2007-02-27 02:29:16 +00:00
parent 06a239c9c8
commit f3ba454d8c
15 changed files with 2123 additions and 259 deletions

View file

@ -77,6 +77,9 @@ OBJECTS = parser_lex.o parser_yacc.o parser_main.o parser_interface.o \
parser_include.o parser_merge.o parser_symtab.o parser_misc.o \
parser_regex.o parser_variable.o parser_policy.o
AAREDIR= libapparmor_re
AAREOBJECTS = ${AAREDIR}/libapparmor_re.a
PCREDIR= pcre
PCREOBJECTS = ${PCREDIR}/pcre.o
@ -110,8 +113,11 @@ all: $(LEX_C_FILES) $(YACC_C_FILES) $(TOOLS)
$(Q)make -C po all
$(Q)make -s tests
apparmor_parser: $(OBJECTS) $(PCREOBJECTS)
$(CC) $(EXTRA_CFLAGS) -o $@ $(OBJECTS) $(PCREOBJECTS) $(LIBS) ${LEXLIB}
apparmor_parser: $(OBJECTS) $(PCREOBJECTS) $(AAREOBJECTS)
rm -f ./libstdc++.a
ln -s `g++ -print-file-name=libstdc++.a`
g++ $(EXTRA_CFLAGS) -o $@ $(OBJECTS) $(PCREOBJECTS) $(LIBS) \
${LEXLIB} $(AAREOBJECTS) -static-libgcc -L.
parser_yacc.c parser_yacc.h: parser_yacc.y parser.h
$(YACC) $(YFLAGS) -o parser_yacc.c parser_yacc.y
@ -174,6 +180,10 @@ tests: ${TESTS}
$(Q)make -s -C tst tests
# always need to rebuild.
.SILENT: $(AAREOBJECTS)
$(AAREOBJECTS):
make -C $(AAREDIR)
.SILENT: $(PCREOBJECTS)
$(PCREOBJECTS):
make -C $(PCREDIR) "CFLAGS=$(CFLAGS)"
@ -196,7 +206,7 @@ install-suse:
ln -sf /etc/init.d/boot.apparmor $(DESTDIR)/sbin/rcapparmor
ln -sf rcapparmor $(DESTDIR)/sbin/rcsubdomain
ln -sf /etc/init.d/aaeventd $(DESTDIR)/sbin/rcaaeventd
.PHONY: install-slackware
install-slackware:
install -m 755 -d $(APPARMOR_BIN_PREFIX)/install
@ -229,7 +239,9 @@ clean:
rm -f $(YACC_C_FILES)
rm -f parser_version.h
rm -f $(NAME)*.tar.gz $(NAME)*.tgz
rm -rf libstdc++.a
make -s -C $(PCREDIR) clean
make -s -C $(AAREDIR) clean
make -s -C po clean
.SILENT: dist_clean

View file

@ -21,64 +21,70 @@
#define _IMMUNIX_H
/* start of system offsets */
#define POS_KERN_COD_FILE_MIN 0
#define POS_KERN_COD_MAY_EXEC POS_KERN_COD_FILE_MIN
#define POS_KERN_COD_MAY_WRITE (POS_KERN_COD_MAY_EXEC + 1)
#define POS_KERN_COD_MAY_READ (POS_KERN_COD_MAY_WRITE + 1)
#define POS_AA_FILE_MIN 0
#define POS_AA_MAY_EXEC POS_AA_FILE_MIN
#define POS_AA_MAY_WRITE (POS_AA_MAY_EXEC + 1)
#define POS_AA_MAY_READ (POS_AA_MAY_WRITE + 1)
/* not used by Subdomain */
#define POS_KERN_COD_MAY_APPEND (POS_KERN_COD_MAY_READ + 1)
#define POS_AA_MAY_APPEND (POS_AA_MAY_READ + 1)
/* end of system offsets */
#define POS_KERN_COD_MAY_LINK (POS_KERN_COD_MAY_APPEND + 1)
#define POS_KERN_COD_EXEC_INHERIT (POS_KERN_COD_MAY_LINK + 1)
#define POS_KERN_COD_EXEC_UNCONSTRAINED (POS_KERN_COD_EXEC_INHERIT + 1)
#define POS_KERN_COD_EXEC_PROFILE (POS_KERN_COD_EXEC_UNCONSTRAINED + 1)
#define POS_KERN_COD_EXEC_MMAP (POS_KERN_COD_EXEC_PROFILE + 1)
#define POS_KERN_COD_EXEC_UNSAFE (POS_KERN_COD_EXEC_MMAP + 1)
#define POS_KERN_COD_FILE_MAX POS_KERN_COD_EXEC_UNSAFE
#define POS_AA_MAY_LINK (POS_AA_MAY_APPEND + 1)
#define POS_AA_EXEC_INHERIT (POS_AA_MAY_LINK + 1)
#define POS_AA_EXEC_UNCONSTRAINED (POS_AA_EXEC_INHERIT + 1)
#define POS_AA_EXEC_PROFILE (POS_AA_EXEC_UNCONSTRAINED + 1)
#define POS_AA_EXEC_MMAP (POS_AA_EXEC_PROFILE + 1)
#define POS_AA_EXEC_UNSAFE (POS_AA_EXEC_MMAP + 1)
#define POS_AA_FILE_MAX POS_AA_EXEC_UNSAFE
#define POS_KERN_COD_NET_MIN (POS_KERN_COD_FILE_MAX + 1)
#define POS_KERN_COD_TCP_CONNECT POS_KERN_COD_NET_MIN
#define POS_KERN_COD_TCP_ACCEPT (POS_KERN_COD_TCP_CONNECT + 1)
#define POS_KERN_COD_TCP_CONNECTED (POS_KERN_COD_TCP_ACCEPT + 1)
#define POS_KERN_COD_TCP_ACCEPTED (POS_KERN_COD_TCP_CONNECTED + 1)
#define POS_KERN_COD_UDP_SEND (POS_KERN_COD_TCP_ACCEPTED + 1)
#define POS_KERN_COD_UDP_RECEIVE (POS_KERN_COD_UDP_SEND + 1)
#define POS_KERN_COD_NET_MAX POS_KERN_COD_UDP_RECEIVE
#define POS_AA_NET_MIN (POS_AA_FILE_MAX + 1)
#define POS_AA_TCP_CONNECT POS_AA_NET_MIN
#define POS_AA_TCP_ACCEPT (POS_AA_TCP_CONNECT + 1)
#define POS_AA_TCP_CONNECTED (POS_AA_TCP_ACCEPT + 1)
#define POS_AA_TCP_ACCEPTED (POS_AA_TCP_CONNECTED + 1)
#define POS_AA_UDP_SEND (POS_AA_TCP_ACCEPTED + 1)
#define POS_AA_UDP_RECEIVE (POS_AA_UDP_SEND + 1)
#define POS_AA_NET_MAX POS_AA_UDP_RECEIVE
/* logging only */
#define POS_KERN_COD_LOGTCP_SEND (POS_KERN_COD_NET_MAX + 1)
#define POS_KERN_COD_LOGTCP_RECEIVE (POS_KERN_COD_LOGTCP_SEND + 1)
#define POS_AA_LOGTCP_SEND (POS_AA_NET_MAX + 1)
#define POS_AA_LOGTCP_RECEIVE (POS_AA_LOGTCP_SEND + 1)
/* Absolute MAX/MIN */
#define POS_KERN_COD_MIN (POS_KERN_COD_FILE_MIN
#define POS_KERN_COD_MAX (POS_KERN_COD_NET_MAX
#define POS_AA_MIN (POS_AA_FILE_MIN
#define POS_AA_MAX (POS_AA_NET_MAX
/* Invalid perm permission */
#define POS_AA_INVALID_POS 31
/* Modeled after MAY_READ, MAY_WRITE, MAY_EXEC def'ns */
#define KERN_COD_MAY_EXEC (0x01 << POS_KERN_COD_MAY_EXEC)
#define KERN_COD_MAY_WRITE (0x01 << POS_KERN_COD_MAY_WRITE)
#define KERN_COD_MAY_READ (0x01 << POS_KERN_COD_MAY_READ)
#define KERN_COD_MAY_LINK (0x01 << POS_KERN_COD_MAY_LINK)
#define KERN_COD_EXEC_INHERIT (0x01 << POS_KERN_COD_EXEC_INHERIT)
#define KERN_COD_EXEC_UNCONSTRAINED (0x01 << POS_KERN_COD_EXEC_UNCONSTRAINED)
#define KERN_COD_EXEC_PROFILE (0x01 << POS_KERN_COD_EXEC_PROFILE)
#define KERN_COD_EXEC_MMAP (0x01 << POS_KERN_COD_EXEC_MMAP)
#define KERN_COD_EXEC_UNSAFE (0x01 << POS_KERN_COD_EXEC_UNSAFE)
#define KERN_EXEC_MODIFIERS(X) (X & (KERN_COD_EXEC_INHERIT | \
KERN_COD_EXEC_UNCONSTRAINED | \
KERN_COD_EXEC_PROFILE))
#define AA_MAY_EXEC (0x01 << POS_AA_MAY_EXEC)
#define AA_MAY_WRITE (0x01 << POS_AA_MAY_WRITE)
#define AA_MAY_READ (0x01 << POS_AA_MAY_READ)
#define AA_MAY_LINK (0x01 << POS_AA_MAY_LINK)
#define AA_EXEC_INHERIT (0x01 << POS_AA_EXEC_INHERIT)
#define AA_EXEC_UNCONSTRAINED (0x01 << POS_AA_EXEC_UNCONSTRAINED)
#define AA_EXEC_PROFILE (0x01 << POS_AA_EXEC_PROFILE)
#define AA_EXEC_MMAP (0x01 << POS_AA_EXEC_MMAP)
#define AA_EXEC_UNSAFE (0x01 << POS_AA_EXEC_UNSAFE)
#define AA_EXEC_MODIFIERS (AA_EXEC_INHERIT | \
AA_EXEC_UNCONSTRAINED | \
AA_EXEC_PROFILE)
#define KERN_EXEC_MODIFIERS(X) (X & AA_EXEC_MODIFIERS)
/* Network subdomain extensions. */
#define KERN_COD_TCP_CONNECT (0x01 << POS_KERN_COD_TCP_CONNECT)
#define KERN_COD_TCP_ACCEPT (0x01 << POS_KERN_COD_TCP_ACCEPT)
#define KERN_COD_TCP_CONNECTED (0x01 << POS_KERN_COD_TCP_CONNECTED)
#define KERN_COD_TCP_ACCEPTED (0x01 << POS_KERN_COD_TCP_ACCEPTED)
#define KERN_COD_UDP_SEND (0x01 << POS_KERN_COD_UDP_SEND)
#define KERN_COD_UDP_RECEIVE (0x01 << POS_KERN_COD_UDP_RECEIVE)
#define AA_TCP_CONNECT (0x01 << POS_AA_TCP_CONNECT)
#define AA_TCP_ACCEPT (0x01 << POS_AA_TCP_ACCEPT)
#define AA_TCP_CONNECTED (0x01 << POS_AA_TCP_CONNECTED)
#define AA_TCP_ACCEPTED (0x01 << POS_AA_TCP_ACCEPTED)
#define AA_UDP_SEND (0x01 << POS_AA_UDP_SEND)
#define AA_UDP_RECEIVE (0x01 << POS_AA_UDP_RECEIVE)
#define KERN_COD_LOGTCP_SEND (0x01 << POS_KERN_COD_LOGTCP_SEND)
#define KERN_COD_LOGTCP_RECEIVE (0x01 << POS_KERN_COD_LOGTCP_RECEIVE)
#define AA_LOGTCP_SEND (0x01 << POS_AA_LOGTCP_SEND)
#define AA_LOGTCP_RECEIVE (0x01 << POS_AA_LOGTCP_RECEIVE)
#define AA_INVALID_PERM (0x01 << POS_AA_INVALID_POS)
#define KERN_COD_HAT_SIZE 975 /* Maximum size of a subdomain
#define AA_HAT_SIZE 975 /* Maximum size of a subdomain
* ident (hat) */
enum pattern_t {
@ -88,14 +94,21 @@ enum pattern_t {
ePatternInvalid,
};
#define HAS_MAY_READ(mode) ((mode) & KERN_COD_MAY_READ)
#define HAS_MAY_WRITE(mode) ((mode) & KERN_COD_MAY_WRITE)
#define HAS_MAY_LINK(mode) ((mode) & KERN_COD_MAY_LINK)
#define HAS_MAY_EXEC(mode) ((mode) & KERN_COD_MAY_EXEC)
#define HAS_EXEC_INHERIT(mode) ((mode) & KERN_COD_EXEC_INHERIT)
#define HAS_EXEC_PROFILE(mode) ((mode) & KERN_COD_EXEC_PROFILE)
#define HAS_EXEC_UNCONSTRAINED(mode) ((mode) & KERN_COD_EXEC_UNCONSTRAINED)
#define HAS_EXEC_MMAP(mode) ((mode) & KERN_COD_EXEC_MMAP)
#define HAS_EXEC_UNSAFE(mode) ((mode) & KERN_COD_EXEC_UNSAFE)
#define HAS_MAY_READ(mode) ((mode) & AA_MAY_READ)
#define HAS_MAY_WRITE(mode) ((mode) & AA_MAY_WRITE)
#define HAS_MAY_LINK(mode) ((mode) & AA_MAY_LINK)
#define HAS_MAY_EXEC(mode) ((mode) & AA_MAY_EXEC)
#define HAS_EXEC_INHERIT(mode) ((mode) & AA_EXEC_INHERIT)
#define HAS_EXEC_PROFILE(mode) ((mode) & AA_EXEC_PROFILE)
#define HAS_EXEC_UNCONSTRAINED(mode) ((mode) & AA_EXEC_UNCONSTRAINED)
#define HAS_EXEC_MMAP(mode) ((mode) & AA_EXEC_MMAP)
#define HAS_EXEC_UNSAFE(mode) ((mode) & AA_EXEC_UNSAFE)
#define AA_NOXMODS_PERM_MASK (AA_MAY_EXEC | AA_MAY_WRITE | \
AA_MAY_READ | AA_MAY_LINK | \
AA_EXEC_MMAP)
#define AA_VALID_PERM_MASK ((1 << (POS_AA_MAX + 1)) - 1)
#define SINGLE_BIT_SET(X) (!((X) & ((X) - 1)))
#define AA_EXEC_SINGLE_MODIFIER_SET(X) SINGLE_BIT_SET(((X) & AA_EXEC_MODIFIERS))
#endif /* ! _IMMUNIX_H */

View file

@ -0,0 +1,25 @@
# Profiling:
#EXTRA_CFLAGS = -pg
TARGET=libapparmor_re.a
CFLAGS = -c -g -Wall -O2 ${EXTRA_CFLAGS}
CXXFLAGS := ${CFLAGS}
ARFLAGS=-rcs
BISON := bison
all : ${TARGET}
libapparmor_re.a: regexp.o
ar ${ARFLAGS} $@ $^
regexp.o : regexp.cc
$(LINK.cc) $^ -o $@
regexp.cc : regexp.y flex-tables.h
${BISON} -o $@ $<
clean:
rm -f regexp{,.o,.cc,.so,.a} ${TARGET}

View file

@ -0,0 +1,30 @@
/* $Id: apparmor.h 6203 2006-02-02 22:03:41Z steve $
Copyright (c) 2003, 2004, 2005, 2006 Novell, Inc. (All rights reserved)
The libapparmor library is licensed under the terms of the GNU
Lesser General Public License, version 2.1. Please see the file
COPYING.LGPL.
*/
#ifndef APPARMOR_RE_H
#define APPARMOR_RE_H
#ifdef __cplusplus
extern "C" {
#endif
struct aare_ruleset;
typedef struct aare_ruleset aare_ruleset_t;
aare_ruleset_t *aare_new_ruleset(int reverse);
void aare_delete_ruleset(aare_ruleset_t *rules);
int aare_add_rule(aare_ruleset_t *rules, char *rule, uint32_t perms);
void *aare_create_dfa(aare_ruleset_t *rules, int equiv_classes, size_t *size);
#ifdef __cplusplus
}
#endif
#endif /* APPARMOR_RE_H */

View file

@ -0,0 +1,40 @@
#ifndef __FLEX_TABLES_H
#define __FLEX_TABLES_H
#include <stdlib.h>
#include <stdint.h>
#define YYTH_MAGIC 0xF13C57B1
struct table_set_header {
uint32_t th_magic; /* TH_MAGIC */
uint32_t th_hsize;
uint32_t th_ssize;
uint16_t th_flags;
char th_version[];
/* char th_name[];
char th_pad64[];*/
} __attribute__ ((packed));
#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 {
uint16_t td_id;
uint16_t td_flags;
uint32_t td_hilen;
uint32_t td_lolen;
char td_data[];
/* char td_pad64[];*/
} __attribute__ ((packed));
#endif

View file

@ -0,0 +1,10 @@
#ifndef __REGEXP_H
#define __REGEXP_H
/**
* Flex file format, but without state compression and with negative
* match results in the YYTD_ID_DEF table instead.
*/
#define YYTH_REGEXP_MAGIC 0x1B5E783D
#endif /* __REGEXP_H */

File diff suppressed because it is too large Load diff

View file

@ -19,6 +19,7 @@
#include <netinet/in.h>
#include "pcre/internal.h"
#include "immunix.h"
#include "libapparmor_re/apparmor_re.h"
typedef enum pattern_t pattern_t;
@ -37,8 +38,8 @@ struct cod_entry {
char * name ;
struct codomain *codomain ; /* Special codomain defined
* just for this executable */
int mode ; /* mode is 'or' of KERN_COD_* bits */
int deny ; /* TRUE or FALSE */
int mode ; /* mode is 'or' of AA_* bits */
int deny ; /* TRUE or FALSE */
pattern_t pattern_type;
struct cod_pattern pat;
@ -68,6 +69,11 @@ struct codomain {
struct cod_net_entry * net_entries;
void *hat_table;
//struct codomain *next;
aare_ruleset_t *dfarules;
int dfarule_count;
void *dfa;
size_t dfa_size;
} ;
struct cod_global_entry {
@ -116,6 +122,10 @@ struct var_string {
#define OPTION_REPLACE 3
#define OPTION_STDOUT 4
#define AARE_NONE 0
#define AARE_PCRE 1
#define AARE_DFA 2
#ifdef DEBUG
#define PDEBUG(fmt, args...) printf("parser: " fmt, ## args)
#else
@ -139,6 +149,11 @@ struct var_string {
#define __unused __attribute__ ((unused))
#endif
#define list_for_each(LIST, ENTRY) \
for ((ENTRY) = (LIST); (ENTRY); (ENTRY) = (ENTRY)->next)
#define list_last_entry(LIST, ENTRY) \
for ((ENTRY) = (LIST); (ENTRY) && (ENTRY)->next; (ENTRY) = (ENTRY)->next)
/* Some external definitions to make b0rken programs happy */
extern char *progname;
extern char *subdomainbase;
@ -146,6 +161,7 @@ extern char *profilename;
/* from parser_main */
extern int force_complain;
extern int regex_type;
extern void pwarn(char *fmt, ...) __attribute__((__format__(__printf__, 1, 2)));
extern int yyparse(void);

View file

@ -26,6 +26,7 @@
#define _(s) gettext(s)
#include "parser.h"
#include "libapparmor_re/apparmor_re.h"
#include <unistd.h>
#include <linux/unistd.h>
@ -55,6 +56,7 @@
#define SD_STR_LEN (sizeof(u16))
#define SUBDOMAIN_INTERFACE_VERSION 2
#define SUBDOMAIN_INTERFACE_DFA_VERSION 3
int sd_serialize_codomain(int option, struct codomain *cod);
@ -334,6 +336,27 @@ inline int sd_write_blob(sd_serialize *p, void *b, int buf_size, char *name)
return 1;
}
#define align64(X) (((size_t) (X) + (size_t) 7) & ~((size_t) 7))
inline int sd_write_aligned_blob(sd_serialize *p, void *b, int buf_size,
char *name)
{
size_t pad;
u32 tmp;
if (!sd_write_name(p, name))
return 0;
pad = align64((p->pos + 5) - p->buffer) - ((p->pos + 5) - p->buffer);
if (!sd_prepare_write(p, SD_BLOB, 4 + buf_size + pad))
return 0;
tmp = cpu_to_le32(buf_size + pad);
memcpy(p->pos, &tmp, sizeof(tmp));
sd_inc(p, sizeof(tmp));
memset(p->pos, 0, pad);
sd_inc(p, pad);
memcpy(p->pos, b, buf_size);
sd_inc(p, buf_size);
return 1;
}
inline int sd_write_string(sd_serialize *p, char *b, char *name)
{
u16 tmp;
@ -470,12 +493,20 @@ int sd_serialize_file_entry(sd_serialize *p, struct cod_entry *file_entry)
return 1;
}
int sd_serialize_dfa(sd_serialize *p, void *dfa, size_t size)
{
if (dfa && !sd_write_aligned_blob(p, dfa, size, "aadfa"))
return 0;
return 1;
}
int count_file_ents(struct cod_entry *list)
{
struct cod_entry *file_entry;
struct cod_entry *entry;
int count = 0;
for (file_entry = list; file_entry; file_entry = file_entry->next) {
if (file_entry->pattern_type == ePatternBasic) {
list_for_each(list, entry) {
if (entry->pattern_type == ePatternBasic) {
count++;
}
}
@ -484,10 +515,10 @@ int count_file_ents(struct cod_entry *list)
int count_tailglob_ents(struct cod_entry *list)
{
struct cod_entry *file_entry;
struct cod_entry *entry;
int count = 0;
for (file_entry = list; file_entry; file_entry = file_entry->next) {
if (file_entry->pattern_type == ePatternTailGlob) {
list_for_each(list, entry) {
if (entry->pattern_type == ePatternTailGlob) {
count++;
}
}
@ -496,10 +527,10 @@ int count_tailglob_ents(struct cod_entry *list)
int count_pcre_ents(struct cod_entry *list)
{
struct cod_entry *file_entry;
struct cod_entry *entry;
int count = 0;
for (file_entry = list; file_entry; file_entry = file_entry->next) {
if (file_entry->pattern_type == ePatternRegex) {
list_for_each(list, entry) {
if (entry->pattern_type == ePatternRegex) {
count++;
}
}
@ -508,7 +539,7 @@ int count_pcre_ents(struct cod_entry *list)
int sd_serialize_profile(sd_serialize *p, struct codomain *profile)
{
struct cod_entry *file_entry;
struct cod_entry *entry;
struct cod_net_entry *net_entry;
if (!sd_write_struct(p, "profile"))
@ -529,55 +560,58 @@ int sd_serialize_profile(sd_serialize *p, struct codomain *profile)
if (!sd_write32(p, profile->capabilities))
return 0;
/* pcre globbing entries */
if (count_pcre_ents(profile->entries)) {
if (!sd_write_list(p, "pgent"))
/* either have a single dfa or lists of different entry types */
if (regex_type == AARE_DFA) {
if (!sd_serialize_dfa(p, profile->dfa, profile->dfa_size))
return 0;
for (file_entry = profile->entries; file_entry;
file_entry = file_entry->next) {
if (file_entry->pattern_type == ePatternRegex) {
if (!sd_serialize_file_entry(p, file_entry))
return 0;
} else {
/* pcre globbing entries */
if (count_pcre_ents(profile->entries)) {
if (!sd_write_list(p, "pgent"))
return 0;
list_for_each(profile->entries, entry) {
if (entry->pattern_type == ePatternRegex) {
if (!sd_serialize_file_entry(p, entry))
return 0;
}
}
if (!sd_write_listend(p))
return 0;
}
/* simple globbing entries */
if (count_tailglob_ents(profile->entries)) {
if (!sd_write_list(p, "sgent"))
return 0;
list_for_each(profile->entries, entry) {
if (entry->pattern_type == ePatternTailGlob) {
if (!sd_serialize_file_entry(p, entry))
return 0;
}
}
if (!sd_write_listend(p))
return 0;
}
/* basic file entries */
if (count_file_ents(profile->entries)) {
if (!sd_write_list(p, "fent"))
return 0;
list_for_each(profile->entries, entry) {
if (entry->pattern_type == ePatternBasic) {
if (!sd_serialize_file_entry(p, entry))
return 0;
}
}
if (!sd_write_listend(p))
return 0;
}
if (!sd_write_listend(p))
return 0;
}
/* simple globbing entries */
if (count_tailglob_ents(profile->entries)) {
if (!sd_write_list(p, "sgent"))
return 0;
for (file_entry = profile->entries; file_entry;
file_entry = file_entry->next) {
if (file_entry->pattern_type == ePatternTailGlob) {
if (!sd_serialize_file_entry(p, file_entry))
return 0;
}
}
if (!sd_write_listend(p))
return 0;
}
/* basic file entries */
if (count_file_ents(profile->entries)) {
if (!sd_write_list(p, "fent"))
return 0;
for (file_entry = profile->entries; file_entry;
file_entry = file_entry->next) {
if (file_entry->pattern_type == ePatternBasic) {
if (!sd_serialize_file_entry(p, file_entry))
return 0;
}
}
if (!sd_write_listend(p))
return 0;
}
if (profile->net_entries) {
if (profile->net_entries && (regex_type != AARE_DFA)) {
if (!sd_write_list(p, "net"))
return 0;
for (net_entry = profile->net_entries; net_entry; net_entry = net_entry->next) {
list_for_each(profile->net_entries, net_entry) {
if (!sd_serialize_net_entry(p, net_entry))
return 0;
}
@ -603,9 +637,18 @@ int sd_serialize_profile(sd_serialize *p, struct codomain *profile)
int sd_serialize_top_profile(sd_serialize *p, struct codomain *profile)
{
int version;
if (regex_type == AARE_DFA)
version = SUBDOMAIN_INTERFACE_DFA_VERSION;
else
version = SUBDOMAIN_INTERFACE_VERSION;
if (!sd_write_name(p, "version"))
return 0;
if (!sd_write32(p, SUBDOMAIN_INTERFACE_VERSION))
if (!sd_write32(p, version))
return 0;
return sd_serialize_profile(p, profile);
}

View file

@ -48,6 +48,7 @@
#define MATCH_STRING "/sys/kernel/security/" MODULE_NAME "/matching"
#define MOUNTED_FS "/proc/mounts"
#define PCRE "pattern=pcre"
#define AADFA "pattern=aadfa"
#define UNPRIVILEGED_OPS (debug || preprocess_only || option == OPTION_STDOUT || names_only || \
dump_vars || dump_expanded_vars)
@ -65,6 +66,8 @@ int conf_quiet = 0;
char *subdomainbase = NULL;
char *profilename;
char *match_string = NULL;
int regex_type = AARE_NONE;
extern int current_lineno;
struct option long_options[] = {
@ -264,99 +267,52 @@ static inline char *try_subdomainfs_mountpoint(const char *mntpnt,
return retval;
}
void find_subdomainfs_mountpoint(void)
int find_subdomainfs_mountpoint(void)
{
FILE *mntfile;
struct mntent *mntpt;
if (!(mntfile = setmntent(MOUNTED_FS, "r"))) {
/* Ugh, what's the right default if you can't open /proc/mounts? */
PERROR(_("Warning: unable to open %s, attempting to use %s\n"
"as the subdomainfs location. Use --subdomainfs to override.\n"),
MOUNTED_FS, DEFAULT_APPARMORFS);
subdomainbase = DEFAULT_APPARMORFS;
return;
}
while ((mntpt = getmntent(mntfile))) {
char *proposed = NULL;
if (strcmp(mntpt->mnt_type, "securityfs") == 0) {
proposed = try_subdomainfs_mountpoint(mntpt->mnt_dir, "/" MODULE_NAME);
if (proposed != NULL) {
subdomainbase = proposed;
break;
if ((mntfile = setmntent(MOUNTED_FS, "r"))) {
while ((mntpt = getmntent(mntfile))) {
char *proposed = NULL;
if (strcmp(mntpt->mnt_type, "securityfs") == 0) {
proposed = try_subdomainfs_mountpoint(mntpt->mnt_dir, "/" MODULE_NAME);
if (proposed != NULL) {
subdomainbase = proposed;
break;
}
proposed = try_subdomainfs_mountpoint(mntpt->mnt_dir, "/" OLD_MODULE_NAME);
if (proposed != NULL) {
subdomainbase = proposed;
break;
}
}
proposed = try_subdomainfs_mountpoint(mntpt->mnt_dir, "/" OLD_MODULE_NAME);
if (proposed != NULL) {
subdomainbase = proposed;
break;
}
}
if (strcmp(mntpt->mnt_type, "subdomainfs") == 0) {
proposed = try_subdomainfs_mountpoint(mntpt->mnt_dir, "");
if (proposed != NULL) {
subdomainbase = proposed;
break;
if (strcmp(mntpt->mnt_type, "subdomainfs") == 0) {
proposed = try_subdomainfs_mountpoint(mntpt->mnt_dir, "");
if (proposed != NULL) {
subdomainbase = proposed;
break;
}
}
}
endmntent(mntfile);
}
if (!subdomainbase) {
PERROR(_("Warning: unable to find a suitable fs in %s, is it mounted?\n"
"Attempting to use %s as the subdomainfs location.\n"
"Use --subdomainfs to override.\n"),
MOUNTED_FS, DEFAULT_APPARMORFS);
subdomainbase = DEFAULT_APPARMORFS;
}
endmntent(mntfile);
}
int is_module_loaded(void)
{
char *query_failed = NULL;
int module_loaded = 0;
int mlen = strlen(MODULE_NAME);
int oldmlen = strlen(OLD_MODULE_NAME);
FILE *fp;
fp = fopen(PROC_MODULES, "r");
if (fp) {
while (!feof(fp)) {
const int buflen = 256;
char buf[buflen];
if (fgets(buf, buflen, fp)) {
buf[buflen - 1] = 0;
if (strncmp(buf, MODULE_NAME, mlen) == 0 &&
buf[mlen] == ' ') {
module_loaded = 1;
}
if (strncmp(buf, OLD_MODULE_NAME, oldmlen) == 0 &&
buf[oldmlen] == ' ') {
module_loaded = 1;
}
}
struct stat buf;
if (stat(DEFAULT_APPARMORFS, &buf) == -1) {
PERROR(_("Warning: unable to find a suitable fs in %s, is it "
"mounted?\nUse --subdomainfs to override.\n"),
MOUNTED_FS);
} else {
subdomainbase = DEFAULT_APPARMORFS;
}
(void)fclose(fp);
} else {
query_failed = "unable to open " PROC_MODULES;
}
if (query_failed) {
PERROR(_("%s: Unable to query modules - '%s'\n"
"Either modules are disabled or your kernel is"
" too old.\n"), progname, query_failed);
return 1;
} else if (!module_loaded) {
PERROR(_("%s: Unable to find " MODULE_NAME "!\n"
"Ensure that it has been loaded.\n"), progname);
return 1;
}
return 0;
return (subdomainbase == NULL);
}
int have_enough_privilege(void)
{
uid_t uid, euid;
@ -387,7 +343,7 @@ static void get_match_string(void) {
/* has process_args() already assigned a match string? */
if (match_string)
return;
goto out;
FILE *ms = fopen(MATCH_STRING, "r");
if (!ms)
@ -404,22 +360,28 @@ static void get_match_string(void) {
}
out:
fclose(ms);
if (match_string) {
if (strstr(match_string, PCRE))
regex_type = AARE_PCRE;
if (strstr(match_string, AADFA))
regex_type = AARE_DFA;
}
if (ms)
fclose(ms);
return;
}
/* return 1 --> PCRE should work fine
return 0 --> no PCRE support */
static int pcre_support(void) {
get_match_string();
static int regex_support(void) {
/* no match string, predates (or postdates?) the split matching
module design */
if (!match_string)
return 1;
if (strstr(match_string, PCRE))
if (regex_type != AARE_NONE)
return 1;
return 0;
@ -437,6 +399,9 @@ int process_profile(int option, char *profilename)
if (retval != 0)
goto out;
/* Get the match string to determine type of regex support needed */
get_match_string();
retval = post_process_policy();
if (retval != 0) {
PERROR(_("%s: Errors found in file. Aborting.\n"), progname);
@ -467,10 +432,7 @@ int process_profile(int option, char *profilename)
goto out;
}
if (!subdomainbase && !preprocess_only && !(option == OPTION_STDOUT))
find_subdomainfs_mountpoint();
if (!pcre_support()) {
if (!regex_support()) {
die_if_any_regex();
}
@ -502,8 +464,9 @@ int main(int argc, char *argv[])
return retval;
}
/* Check to make sure modules are enabled */
if (!(UNPRIVILEGED_OPS) && ((retval = is_module_loaded()))) {
/* Check to make sure there is an interface to load policy */
if (!(UNPRIVILEGED_OPS) && (subdomainbase == NULL) &&
(retval = find_subdomainfs_mountpoint())) {
return retval;
}

View file

@ -296,17 +296,17 @@ reeval:
switch (this) {
case COD_READ_CHAR:
PDEBUG("Parsing mode: found READ\n");
mode |= KERN_COD_MAY_READ;
mode |= AA_MAY_READ;
break;
case COD_WRITE_CHAR:
PDEBUG("Parsing mode: found WRITE\n");
mode |= KERN_COD_MAY_WRITE;
mode |= AA_MAY_WRITE;
break;
case COD_LINK_CHAR:
PDEBUG("Parsing mode: found LINK\n");
mode |= KERN_COD_MAY_LINK;
mode |= AA_MAY_LINK;
break;
case COD_INHERIT_CHAR:
@ -319,13 +319,13 @@ reeval:
if (next != tolower(next))
warn_uppercase();
mode |=
(KERN_COD_EXEC_INHERIT | KERN_COD_MAY_EXEC);
(AA_EXEC_INHERIT | AA_MAY_EXEC);
p++; /* skip 'x' */
}
break;
case COD_UNSAFE_UNCONSTRAINED_CHAR:
mode |= KERN_COD_EXEC_UNSAFE;
mode |= AA_EXEC_UNSAFE;
pwarn(_("Unconstrained exec qualifier (%c%c) allows some dangerous environment variables "
"to be passed to the unconfined process; 'man 5 apparmor.d' for details.\n"),
COD_UNSAFE_UNCONSTRAINED_CHAR, COD_EXEC_CHAR);
@ -342,14 +342,14 @@ reeval:
if (next != tolower(next))
warn_uppercase();
mode |=
(KERN_COD_EXEC_UNCONSTRAINED |
KERN_COD_MAY_EXEC);
(AA_EXEC_UNCONSTRAINED |
AA_MAY_EXEC);
p++; /* skip 'x' */
}
break;
case COD_UNSAFE_PROFILE_CHAR:
mode |= KERN_COD_EXEC_UNSAFE;
mode |= AA_EXEC_UNSAFE;
/* fall through */
case COD_PROFILE_CHAR:
PDEBUG("Parsing mode: found PROFILE\n");
@ -363,14 +363,14 @@ reeval:
if (next != tolower(next))
warn_uppercase();
mode |=
(KERN_COD_EXEC_PROFILE | KERN_COD_MAY_EXEC);
(AA_EXEC_PROFILE | AA_MAY_EXEC);
p++; /* skip 'x' */
}
break;
case COD_MMAP_CHAR:
PDEBUG("Parsing mode: found MMAP\n");
mode |= KERN_COD_EXEC_MMAP;
mode |= AA_EXEC_MMAP;
break;
case COD_EXEC_CHAR:
@ -557,7 +557,7 @@ void debug_cod_entries(struct cod_entry *list)
printf("--- Entries ---\n");
for (item = list; item; item = item->next) {
list_for_each(list, item) {
if (!item)
printf("Item is NULL!\n");
@ -603,7 +603,7 @@ void debug_cod_net_entries(struct cod_net_entry *list)
printf("--- NetwerkEntries --- \n");
for (item = list; item; item = item->next) {
list_for_each(list, item) {
if (!item)
printf("Item is NULL");
@ -623,17 +623,17 @@ void debug_cod_net_entries(struct cod_net_entry *list)
printf("Destination netmask: %lx\n", dmask);
fflush(stdout);
printf("Mode:\t");
if (item->mode & KERN_COD_TCP_ACCEPT)
if (item->mode & AA_TCP_ACCEPT)
printf("TA");
if (item->mode & KERN_COD_TCP_CONNECT)
if (item->mode & AA_TCP_CONNECT)
printf("TC");
if (item->mode & KERN_COD_TCP_ACCEPTED)
if (item->mode & AA_TCP_ACCEPTED)
printf("Ta");
if (item->mode & KERN_COD_TCP_CONNECTED)
if (item->mode & AA_TCP_CONNECTED)
printf("Tc");
if (item->mode & KERN_COD_UDP_SEND)
if (item->mode & AA_UDP_SEND)
printf("US");
if (item->mode & KERN_COD_UDP_RECEIVE)
if (item->mode & AA_UDP_RECEIVE)
printf("UR");
if (item->iface != NULL)
printf("\nInterface: %s\n", item->iface);

View file

@ -159,7 +159,7 @@ static int any_regex_entries(struct cod_entry *entry_list)
{
struct cod_entry *entry;
for (entry = entry_list; entry; entry = entry->next) {
list_for_each(entry_list, entry) {
if (entry->pattern_type == ePatternRegex)
return TRUE;
}
@ -374,8 +374,7 @@ struct codomain *merge_policy(struct codomain *a, struct codomain *b)
}
if (a->entries) {
for (last = a->entries; last->next; last = last->next)
/* do nothing */ ;
list_last_entry(a->entries, last);
last->next = b->entries;
} else {
a->entries = b->entries;
@ -383,8 +382,7 @@ struct codomain *merge_policy(struct codomain *a, struct codomain *b)
b->entries = NULL;
if (a->net_entries) {
for (lastnet = a->net_entries; lastnet->next; lastnet = lastnet->next)
/* do nothing */ ;
list_last_entry(a->net_entries, lastnet);
lastnet->next = b->net_entries;
} else {
a->net_entries = b->net_entries;
@ -451,5 +449,9 @@ void free_policy(struct codomain *cod)
free_hat_table(cod->hat_table);
free_cod_entries(cod->entries);
free_net_entries(cod->net_entries);
if (cod->dfarules)
aare_delete_ruleset(cod->dfarules);
if (cod->dfa)
free(cod->dfa);
free(cod);
}

View file

@ -27,6 +27,7 @@
/* #define DEBUG */
#include "parser.h"
#include "libapparmor_re/apparmor_re.h"
enum error_type {
e_no_error,
@ -113,10 +114,11 @@ static void filter_slashes(char *path)
}
}
static int process_regex_entry(struct cod_entry *entry)
static pattern_t convert_aaregex_to_pcre(const char *aare, int anchor,
char *pcre, size_t pcre_size)
{
#define STORE(_src, _dest, _len) \
if ((const char*)_dest + _len > tbufend){ \
if ((const char*)_dest + _len > (pcre + pcre_size)){ \
error = e_buffer_overflow; \
} else { \
memcpy(_dest, _src, _len); \
@ -128,9 +130,6 @@ static int process_regex_entry(struct cod_entry *entry)
/* flag to indicate input error */
enum error_type error;
char tbuf[PATH_MAX + 3]; /* +3 for ^, $ and \0 */
const char *tbufend = &tbuf[PATH_MAX];
const char *sptr;
char *dptr;
pattern_t ptype;
@ -142,14 +141,12 @@ static int process_regex_entry(struct cod_entry *entry)
error = e_no_error;
ptype = ePatternBasic; /* assume no regex */
if (!entry) /* shouldn't happen */
return TRUE;
sptr = aare;
dptr = pcre;
sptr = entry->name;
dptr = tbuf;
/* anchor beginning of regular expression */
*dptr++ = '^';
if (anchor)
/* anchor beginning of regular expression */
*dptr++ = '^';
while (error == e_no_error && *sptr) {
switch (*sptr) {
@ -342,12 +339,12 @@ static int process_regex_entry(struct cod_entry *entry)
}
/* anchor end and terminate pattern string */
if (error == e_no_error) {
char buf[2] = { '$', 0 };
STORE(buf, dptr, 2);
if ((error == e_no_error) && anchor) {
STORE("$" , dptr, 1);
}
if (error == e_no_error) {
STORE("", dptr, 1);
}
/* check error again, as above STORE may have set it */
if (error != e_no_error) {
if (error == e_buffer_overflow) {
@ -356,12 +353,31 @@ static int process_regex_entry(struct cod_entry *entry)
}
PERROR(_("%s: Unable to parse input line '%s'\n"),
progname, entry->name);
progname, aare);
ret = FALSE;
goto out;
}
out:
if (ret == FALSE)
ptype = ePatternInvalid;
return ptype;
}
static int process_pcre_entry(struct cod_entry *entry)
{
char tbuf[PATH_MAX + 3]; /* +3 for ^, $ and \0 */
int ret = TRUE;
pattern_t ptype;
if (!entry) /* shouldn't happen */
return TRUE;
ptype = convert_aaregex_to_pcre(entry->name, 1, tbuf, PATH_MAX + 3);
if (ptype == ePatternInvalid)
return FALSE;
entry->pattern_type = ptype;
/*
@ -422,33 +438,83 @@ static int process_regex_entry(struct cod_entry *entry)
filter_escapes(entry->name);
} /* ptype == ePatternRegex */
out:
return ret;
}
int post_process_entries(struct cod_entry *entry_list)
static int process_dfa_entry(aare_ruleset_t *dfarules, struct cod_entry *entry)
{
char tbuf[PATH_MAX + 3]; /* +3 for ^, $ and \0 */
int ret = TRUE;
pattern_t ptype;
if (!entry) /* shouldn't happen */
return TRUE;
ptype = convert_aaregex_to_pcre(entry->name, 0, tbuf, PATH_MAX + 3);
if (ptype == ePatternInvalid)
return FALSE;
entry->pattern_type = ptype;
/* ix implies m but the apparmor module does not add m bit to
* dfa states like it does for pcre
*/
if (entry->mode & AA_EXEC_INHERIT)
entry->mode |= AA_EXEC_MMAP;
if (!aare_add_rule(dfarules, tbuf, entry->mode))
ret = FALSE;
return ret;
}
int post_process_entries(struct codomain *cod)
{
int ret = TRUE, rc;
struct cod_entry *entry;
int count = 0;
for (entry = entry_list; entry; entry = entry->next) {
list_for_each(cod->entries, entry) {
filter_slashes(entry->name);
rc = process_regex_entry(entry);
if (regex_type == AARE_DFA)
rc = process_dfa_entry(cod->dfarules, entry);
else
rc = process_pcre_entry(entry);
if (!rc)
ret = FALSE;
count++;
}
cod->dfarule_count = count;
return ret;
}
int process_regex(struct codomain *cod)
{
int error = 0;
int error = -1;
if (!post_process_entries(cod->entries)) {
error = -1;
if (regex_type == AARE_DFA) {
cod->dfarules = aare_new_ruleset(0);
if (!cod->dfarules)
goto out;
}
if (!post_process_entries(cod))
goto out;
if (regex_type == AARE_DFA && cod->dfarule_count > 0) {
cod->dfa = aare_create_dfa(cod->dfarules, 0, &cod->dfa_size);
if (!cod->dfa)
goto out;
/*
if (cod->dfa_size == 0) {
PERROR(_("profile %s: has merged rules (%s) with "
"multiple x modifiers\n"),
cod->name, (char *) cod->dfa);
free(cod->dfa);
cod->dfa = NULL;
goto out;
}
*/
}
/*
* Post process subdomain(s):
*
@ -464,8 +530,11 @@ int process_regex(struct codomain *cod)
* }
*/
if (process_hat_regex(cod) != 0)
error = -1;
goto out;
error = 0;
out:
return error;
}

View file

@ -184,7 +184,7 @@ static int process_variables_in_entries(struct cod_entry *entry_list)
int ret = TRUE, rc;
struct cod_entry *entry;
for (entry = entry_list; entry; entry = entry->next) {
list_for_each(entry_list, entry) {
rc = expand_entry_variables(entry);
if (!rc)
ret = FALSE;

View file

@ -599,12 +599,12 @@ netrule: action addresses interface TOK_END_OF_RULE
$$ = entry;
};
action: TOK_TCP_CONN { $$ = KERN_COD_TCP_CONNECT; }
| TOK_TCP_ACPT { $$ = KERN_COD_TCP_ACCEPT; }
| TOK_TCP_CONN_ESTB { $$ = KERN_COD_TCP_CONNECTED; }
| TOK_TCP_ACPT_ESTB { $$ = KERN_COD_TCP_ACCEPTED; }
| TOK_UDP_SEND { $$ = KERN_COD_UDP_SEND; }
| TOK_UDP_RECV { $$ = KERN_COD_UDP_RECEIVE; }
action: TOK_TCP_CONN { $$ = AA_TCP_CONNECT; }
| TOK_TCP_ACPT { $$ = AA_TCP_ACCEPT; }
| TOK_TCP_CONN_ESTB { $$ = AA_TCP_CONNECTED; }
| TOK_TCP_ACPT_ESTB { $$ = AA_TCP_ACCEPTED; }
| TOK_UDP_SEND { $$ = AA_UDP_SEND; }
| TOK_UDP_RECV { $$ = AA_UDP_RECEIVE; }
;