[apparmor] [PATCH] Add compressed dfa matching routines to library, and a base test program
John Johansen
john.johansen at canonical.com
Fri Jan 8 23:48:06 UTC 2016
Signed-off-by: John Johansen <john.johansen at canonical.com>
---
devtools/Makefile | 34 ++
devtools/README | 25 +
devtools/expr.txt | 772 ++++++++++++++++++++++++++
devtools/match.txt | 14 +
devtools/print_hfa.c | 192 +++++++
devtools/test_re.cc | 440 +++++++++++++++
libraries/libapparmor/src/Makefile.am | 11 +-
libraries/libapparmor/src/hfa.c | 304 ++++++++++
libraries/libapparmor/src/hfa.h | 83 +++
libraries/libapparmor/src/hfa_print.c | 209 +++++++
libraries/libapparmor/src/hfa_private.h | 101 ++++
libraries/libapparmor/src/hfa_unpack.c | 636 +++++++++++++++++++++
libraries/libapparmor/src/libapparmor.map | 7 +
libraries/libapparmor/swig/SWIG/libapparmor.i | 9 +
parser/libapparmor_re/Makefile | 4 +-
parser/libapparmor_re/aare_rules.h | 1 +
16 files changed, 2835 insertions(+), 7 deletions(-)
create mode 100644 devtools/Makefile
create mode 100644 devtools/README
create mode 100644 devtools/expr.txt
create mode 100644 devtools/match.txt
create mode 100644 devtools/print_hfa.c
create mode 100644 devtools/test_re.cc
create mode 100644 libraries/libapparmor/src/hfa.c
create mode 100644 libraries/libapparmor/src/hfa.h
create mode 100644 libraries/libapparmor/src/hfa_print.c
create mode 100644 libraries/libapparmor/src/hfa_private.h
create mode 100644 libraries/libapparmor/src/hfa_unpack.c
diff --git a/devtools/Makefile b/devtools/Makefile
new file mode 100644
index 0000000..b0cd26e
--- /dev/null
+++ b/devtools/Makefile
@@ -0,0 +1,34 @@
+# Profiling:
+#EXTRA_CFLAGS = -pg
+
+ifdef USE_SYSTEM
+ # Using the system libapparmor
+ INCLUDE_APPARMOR =
+else
+ INCLUDE_APPARMOR = -I../libraries/libapparmor/include
+endif
+
+CFLAGS ?= -g -Wall -O2 ${EXTRA_CFLAGS} ${INCLUDE_APPARMOR}
+CXXFLAGS := ${CFLAGS} -std=gnu++0x
+
+ARFLAGS=-rcs
+
+TARGETS=test_re print_hfa
+
+all : ${TARGETS}
+
+
+test_re: test_re.o ../parser/libapparmor_re/libapparmor_re.a ../parser/parser.h ../parser/common_optarg.h ../parser/common_optarg.o ../parser/lib.o
+ $(CXX) ${CXXFLAGS} -o $@ $^ -L ../libraries/libapparmor/src/.libs/ -static -lapparmor
+
+test_re.o: test_re.cc ../parser/libapparmor_re/aare_rules.h
+ $(CXX) ${CXXFLAGS} -c -o $@ $<
+
+print_hfa: print_hfa.o
+ $(CC) ${CFLAGS} -o $@ $^ -L ../libraries/libapparmor/src/.libs/ -static -lapparmor
+
+print_hfa.o: print_hfa.c
+ $(CC) ${CFLAGS} -c -o $@ $<
+
+clean:
+ rm -f *.o *.gcda *.gcno ${TARGETS}
diff --git a/devtools/README b/devtools/README
new file mode 100644
index 0000000..b16f6f0
--- /dev/null
+++ b/devtools/README
@@ -0,0 +1,25 @@
+Basic developer utilities not ready for or needed by regular users
+
+test_re:
+TODO: split into 2 utilities. gen_hfa, and test_hfa
+
+program to generate and test a dfa.
+Eg. compile hfa described by the exprs in expr.txt, and match the text in
+ match.txt against it. In this case every string in match.txt is run
+ against the hfa 10000000 times and the time to perform this match is
+ reported
+
+ ./test_re -t -c 10000000 -E expr.txt -M match.txt
+ elapsed time: 8.421s
+
+to generate an hfa
+ ./test_r -o hfa.file -E expr.txt
+
+
+
+
+print_hfa: simple hfa text dump utility
+Eg.
+ print_hfa hfa.file
+
+
diff --git a/devtools/expr.txt b/devtools/expr.txt
new file mode 100644
index 0000000..4b7d12b
--- /dev/null
+++ b/devtools/expr.txt
@@ -0,0 +1,772 @@
+1 /
+1 /([^\0000])*\.[Bb][Mm][Pp]
+1 /([^\0000])*\.[Bb][Zz]2
+1 /([^\0000])*\.[Cc][Bb][7RZrz]
+1 /([^\0000])*\.[Dd][Jj][Vv][Uu]
+1 /([^\0000])*\.[Dd][Vv][Ii]
+1 /([^\0000])*\.[Ee][Pp][Ss]
+1 /([^\0000])*\.[FPfp][Dd][Ff]
+1 /([^\0000])*\.[Gg][Ii][Ff]
+1 /([^\0000])*\.[Gg][Zz]
+1 /([^\0000])*\.[Jj][Pp][Ee][Gg]
+1 /([^\0000])*\.[Jj][Pp][Gg]
+1 /([^\0000])*\.[Oo][Dd][Pp]
+1 /([^\0000])*\.[Pp][Nn][Gg]
+1 /([^\0000])*\.[Pp][Nn][Mm]
+1 /([^\0000])*\.[Pp][Ss]
+1 /([^\0000])*\.[Tt][Ii][Ff]
+1 /([^\0000])*\.[Tt][Ii][Ff][Ff]
+1 /([^\0000])*\.[Xx][Pp][Mm]
+1 /[^\0000/]([^\0000])*/
+1 /[^\0000/]([^\0000])*/\.goutputstream-([^\0000/])*
+1 /bin/bzip2
+1 /bin/gzip
+1 /bin/ls
+1 /bin/tar
+1 /dev/\.udev/(data|db)/[^\0000/]([^\0000/])*
+1 /dev/admmidi([^\0000/])*
+1 /dev/adsp([^\0000/])*
+1 /dev/aload([^\0000/])*
+1 /dev/amidi([^\0000/])*
+1 /dev/audio([^\0000/])*
+1 /dev/dmfm([^\0000/])*
+1 /dev/dmmidi([^\0000/])*
+1 /dev/dri/[^\0000/]([^\0000])*
+1 /dev/dsp([^\0000/])*
+1 /dev/full
+1 /dev/log
+1 /dev/midi([^\0000/])*
+1 /dev/mixer([^\0000/])*
+1 /dev/mpu401data
+1 /dev/mpu401stat
+1 /dev/null
+1 /dev/patmgr([^\0000/])*
+1 /dev/phone([^\0000/])*
+1 /dev/radio([^\0000/])*
+1 /dev/random
+1 /dev/rmidi([^\0000/])*
+1 /dev/sequencer
+1 /dev/sequencer2
+1 /dev/smpte([^\0000/])*
+1 /dev/snd/[^\0000/]([^\0000/])*
+1 /dev/sound/[^\0000/]([^\0000/])*
+1 /dev/urandom
+1 /dev/zero
+1 /etc/
+1 /etc/DIR_COLORS
+1 /etc/X11/cursors/
+1 /etc/X11/cursors/[^\0000/]([^\0000])*
+1 /etc/bash\.bashrc
+1 /etc/bash\.bashrc\.local
+1 /etc/bash_completion
+1 /etc/bash_completion\.d/
+1 /etc/bash_completion\.d/[^\0000/]([^\0000/])*
+1 /etc/bashrc
+1 /etc/bindresvport\.blacklist
+1 /etc/cups/client\.conf
+1 /etc/cups/lpoptions
+1 /etc/default/apport
+1 /etc/default/nss
+1 /etc/drirc
+1 /etc/esound/esd\.conf
+1 /etc/fonts/[^\0000/]([^\0000/])*
+1 /etc/fonts/[^\0000/]([^\0000])*
+1 /etc/fstab
+1 /etc/gai\.conf
+1 /etc/gnashpluginrc
+1 /etc/gnashrc
+1 /etc/gnome-vfs-2\.0/modules/
+1 /etc/gnome-vfs-2\.0/modules/[^\0000/]([^\0000/])*
+1 /etc/gnome/defaults\.list
+1 /etc/gnome/gtkrc([^\0000/])*
+1 /etc/group
+1 /etc/gtk-([^\0000/])*/[^\0000/]([^\0000/])*
+1 /etc/gtk/[^\0000/]([^\0000/])*
+1 /etc/host\.conf
+1 /etc/hosts
+1 /etc/inputrc
+1 /etc/krb\.conf
+1 /etc/krb\.realms
+1 /etc/krb5\.conf
+1 /etc/krb5\.keytab
+1 /etc/ld\.so\.cache
+1 /etc/ldap\.conf
+1 /etc/ldap\.secret
+1 /etc/locale\.alias
+1 /etc/locale/[^\0000/]([^\0000])*
+1 /etc/localtime
+1 /etc/mplayerplug-in\.conf
+1 /etc/mtab
+1 /etc/nss_mdns\.conf
+1 /etc/nsswitch\.conf
+1 /etc/openal/alsoft\.conf
+1 /etc/openldap/[^\0000/]([^\0000/])*
+1 /etc/openldap/cacerts/[^\0000/]([^\0000/])*
+1 /etc/orbitrc
+1 /etc/pango/[^\0000/]([^\0000/])*
+1 /etc/papersize
+1 /etc/passwd
+1 /etc/pkcs11/
+1 /etc/pkcs11/modules/
+1 /etc/pkcs11/modules/[^\0000/]([^\0000/])*
+1 /etc/pkcs11/pkcs11\.conf
+1 /etc/profile
+1 /etc/profile\.d/
+1 /etc/profile\.d/[^\0000/]([^\0000/])*
+1 /etc/profile\.dos
+1 /etc/protocols
+1 /etc/pulse/
+1 /etc/pulse/[^\0000/]([^\0000/])*
+1 /etc/resolv\.conf
+1 /etc/resolvconf/run/resolv\.conf
+1 /etc/samba/lmhosts
+1 /etc/samba/smb\.conf
+1 /etc/sasl2/[^\0000/]([^\0000/])*
+1 /etc/services
+1 /etc/sound/
+1 /etc/sound/[^\0000/]([^\0000])*
+1 /etc/srvtab
+1 /etc/ssl/
+1 /etc/ssl/certs/
+1 /etc/ssl/certs/[^\0000/]([^\0000/])*
+1 /etc/texmf/
+1 /etc/texmf/[^\0000/]([^\0000])*
+1 /etc/udev/udev\.conf
+1 /etc/writable/localtime
+1 /etc/xdg/xdg-xubuntu/xfce4/helpers\.rc
+1 /etc/xdg/xfce4/helpers\.rc
+1 /etc/xpdf/[^\0000/]([^\0000/])*
+1 /home/
+1 /home/[^\0000/]([^\0000/])*/
+1 /home/[^\0000/]([^\0000/])*/[^\0000/]([^\0000])*
+1 /home/[^\0000/]([^\0000/])*/\.ICEauthority
+1 /home/[^\0000/]([^\0000/])*/\.Private/[^\0000/]([^\0000])*
+1 /home/[^\0000/]([^\0000/])*/\.Private/[^\0000/]([^\0000])*\0000/[^/](.)*
+1 /home/[^\0000/]([^\0000/])*/\.Xauthority
+1 /home/[^\0000/]([^\0000/])*/\.asoundrc
+1 /home/[^\0000/]([^\0000/])*/\.bash_history
+1 /home/[^\0000/]([^\0000/])*/\.bash_profile
+1 /home/[^\0000/]([^\0000/])*/\.bashrc
+1 /home/[^\0000/]([^\0000/])*/\.cache/
+1 /home/[^\0000/]([^\0000/])*/\.cache/event-sound-cache\.([^\0000/])*
+1 /home/[^\0000/]([^\0000/])*/\.config/
+1 /home/[^\0000/]([^\0000/])*/\.config/gtk-2\.0/[^\0000/]([^\0000])*
+1 /home/[^\0000/]([^\0000/])*/\.config/gtk-2\.0/gtkfilechooser\.ini([^\0000/])*
+1 /home/[^\0000/]([^\0000/])*/\.config/ibus/bus/
+1 /home/[^\0000/]([^\0000/])*/\.config/ibus/bus/[^\0000/]([^\0000/])*
+1 /home/[^\0000/]([^\0000/])*/\.config/pulse/cookie
+1 /home/[^\0000/]([^\0000/])*/\.esd_auth
+1 /home/[^\0000/]([^\0000/])*/\.fonts\.cache-([^\0000/])*
+1 /home/[^\0000/]([^\0000/])*/\.fonts\.cache-([^\0000/])*\0000/[^/](.)*
+1 /home/[^\0000/]([^\0000/])*/\.fonts\.cache-2
+1 /home/[^\0000/]([^\0000/])*/\.fonts\.conf
+1 /home/[^\0000/]([^\0000/])*/\.fonts\.conf\.d/
+1 /home/[^\0000/]([^\0000/])*/\.fonts\.conf\.d/[^\0000/]([^\0000])*
+1 /home/[^\0000/]([^\0000/])*/\.fonts/
+1 /home/[^\0000/]([^\0000/])*/\.fonts/[^\0000/]([^\0000])*
+1 /home/[^\0000/]([^\0000/])*/\.gconfd/lock/[^\0000/]([^\0000/])*
+1 /home/[^\0000/]([^\0000/])*/\.gnash/
+1 /home/[^\0000/]([^\0000/])*/\.gnash/[^\0000/]([^\0000])*
+1 /home/[^\0000/]([^\0000/])*/\.gnome/Gnome
+1 /home/[^\0000/]([^\0000/])*/\.gnome/application-info
+1 /home/[^\0000/]([^\0000/])*/\.gnome2/accels/
+1 /home/[^\0000/]([^\0000/])*/\.gnome2/accels/evince
+1 /home/[^\0000/]([^\0000/])*/\.gnome2/accelsevince
+1 /home/[^\0000/]([^\0000/])*/\.gnome2/evince/[^\0000/]([^\0000/])*
+1 /home/[^\0000/]([^\0000/])*/\.gnome2/evince/[^\0000/]([^\0000/])*\0000/[^/](.)*
+1 /home/[^\0000/]([^\0000/])*/\.gtk
+1 /home/[^\0000/]([^\0000/])*/\.gtk-bookmarks
+1 /home/[^\0000/]([^\0000/])*/\.gtkrc
+1 /home/[^\0000/]([^\0000/])*/\.gtkrc-2\.0
+1 /home/[^\0000/]([^\0000/])*/\.local/
+1 /home/[^\0000/]([^\0000/])*/\.local/share/
+1 /home/[^\0000/]([^\0000/])*/\.local/share/gvfs-metadata/[^\0000/]([^\0000])*
+1 /home/[^\0000/]([^\0000/])*/\.local/share/gvfs-metadata/[^\0000/]([^\0000])*\0000/[^/](.)*
+1 /home/[^\0000/]([^\0000/])*/\.local/share/recently-used\.xbel([^\0000/])*
+1 /home/[^\0000/]([^\0000/])*/\.profile
+1 /home/[^\0000/]([^\0000/])*/\.pulse-cookie
+1 /home/[^\0000/]([^\0000/])*/\.pulse/
+1 /home/[^\0000/]([^\0000/])*/\.pulse/[^\0000/]([^\0000/])*
+1 /home/[^\0000/]([^\0000/])*/\.recently-used\.xbel([^\0000/])*
+1 /home/[^\0000/]([^\0000/])*/\.themes/
+1 /home/[^\0000/]([^\0000/])*/\.themes/[^\0000/]([^\0000])*
+1 /home/[^\0000/]([^\0000/])*/\.(|cache/)fontconfig/
+1 /home/[^\0000/]([^\0000/])*/\.(|cache/)fontconfig/[^\0000/]([^\0000])*
+1 /home/[^\0000/]([^\0000/])*/\.(|cache/)fontconfig/[^\0000/]([^\0000])*\0000/[^/](.)*
+1 /home/[^\0000/]([^\0000/])*/tmp/
+1 /home/[^\0000/]([^\0000/])*/tmp/[^\0000/]([^\0000])*
+1 /home/[^\0000/]([^\0000/])*/tmp/[^\0000/]([^\0000])*\0000/[^/](.)*
+1 /home/\.ecryptfs/[^\0000/]([^\0000/])*/\.Private/[^\0000/]([^\0000])*
+1 /home/\.ecryptfs/[^\0000/]([^\0000/])*/\.Private/[^\0000/]([^\0000])*\0000/[^/](.)*
+1 /lib/([^\0000/])*-linux-gnu([^\0000/])*/[^\0000/]([^\0000])*
+1 /lib/([^\0000/])*-linux-gnu([^\0000/])*/[^\0000/]([^\0000])*/lib([^\0000/])*\.so([^\0000/])*
+1 /lib/([^\0000/])*-linux-gnu([^\0000/])*/ld((|32)|64)-([^\0000/])*\.so
+1 /lib/([^\0000/])*-linux-gnu([^\0000/])*/lib([^\0000/])*\.so([^\0000/])*
+1 /lib/([^\0000/])*-linux-gnu([^\0000/])*/libnss_([^\0000/])*\.so([^\0000/])*
+1 /lib/i386-linux-gnu/tls/i686/(cmov|nosegneg)/ld-([^\0000/])*\.so
+1 /lib/i386-linux-gnu/tls/i686/(cmov|nosegneg)/lib([^\0000/])*\.so([^\0000/])*
+1 /lib/tls/i686/(cmov|nosegneg)/ld-([^\0000/])*\.so
+1 /lib/tls/i686/(cmov|nosegneg)/lib([^\0000/])*\.so([^\0000/])*
+1 /lib((|32)|64)/[^\0000/]([^\0000])*
+1 /lib((|32)|64)/[^\0000/]([^\0000])*/ld((|32)|64)-([^\0000/])*\.so
+1 /lib((|32)|64)/[^\0000/]([^\0000])*/lib([^\0000/])*\.so([^\0000/])*
+1 /lib((|32)|64)/ld((|32)|64)-([^\0000/])*\.so
+1 /lib((|32)|64)/lib([^\0000/])*\.so([^\0000/])*
+1 /lib((|32)|64)/libnss_([^\0000/])*\.so([^\0000/])*
+1 /opt/([^\0000/])*-linux-uclibc/lib/ld-uClibc([^\0000/])*so([^\0000/])*
+1 /opt/google/chrome/google-chrome
+1 /opt/kde3/share/fonts/[^\0000/]([^\0000])*
+1 /proc/[^\0000/]([^\0000/])*/maps
+1 /proc/[^\0000/]([^\0000/])*/mounts
+1 /proc/[^\0000/]([^\0000/])*/net/route
+1 /proc/[0123456789]([^\0000/])*/fd/
+1 /proc/[0123456789]([^\0000/])*/mountinfo
+1 /proc/[0123456789]([^\0000/])*/mounts
+1 /proc/asound/[^\0000/]([^\0000])*
+1 /proc/cpuinfo
+1 /proc/filesystems
+1 /proc/meminfo
+1 /proc/stat
+1 /proc/sys/crypto/[^\0000/]([^\0000/])*
+1 /proc/sys/kernel/ngroups_max
+1 /proc/sys/kernel/version
+1 /proc/sys/vm/overcommit_memory
+1 /root/
+1 /root/[^\0000/]([^\0000])*
+1 /root/\.ICEauthority
+1 /root/\.Private/[^\0000/]([^\0000])*
+1 /root/\.Private/[^\0000/]([^\0000])*\0000/[^/](.)*
+1 /root/\.Xauthority
+1 /root/\.asoundrc
+1 /root/\.bash_history
+1 /root/\.bash_profile
+1 /root/\.bashrc
+1 /root/\.cache/
+1 /root/\.cache/event-sound-cache\.([^\0000/])*
+1 /root/\.config/
+1 /root/\.config/gtk-2\.0/[^\0000/]([^\0000])*
+1 /root/\.config/gtk-2\.0/gtkfilechooser\.ini([^\0000/])*
+1 /root/\.config/ibus/bus/
+1 /root/\.config/ibus/bus/[^\0000/]([^\0000/])*
+1 /root/\.config/pulse/cookie
+1 /root/\.esd_auth
+1 /root/\.fonts\.cache-([^\0000/])*
+1 /root/\.fonts\.cache-([^\0000/])*\0000/[^/](.)*
+1 /root/\.fonts\.cache-2
+1 /root/\.fonts\.conf
+1 /root/\.fonts\.conf\.d/
+1 /root/\.fonts\.conf\.d/[^\0000/]([^\0000])*
+1 /root/\.fonts/
+1 /root/\.fonts/[^\0000/]([^\0000])*
+1 /root/\.gconfd/lock/[^\0000/]([^\0000/])*
+1 /root/\.gnash/
+1 /root/\.gnash/[^\0000/]([^\0000])*
+1 /root/\.gnome/Gnome
+1 /root/\.gnome/application-info
+1 /root/\.gnome2/accels/
+1 /root/\.gnome2/accels/evince
+1 /root/\.gnome2/accelsevince
+1 /root/\.gnome2/evince/[^\0000/]([^\0000/])*
+1 /root/\.gnome2/evince/[^\0000/]([^\0000/])*\0000/[^/](.)*
+1 /root/\.gtk
+1 /root/\.gtk-bookmarks
+1 /root/\.gtkrc
+1 /root/\.gtkrc-2\.0
+1 /root/\.local/
+1 /root/\.local/share/
+1 /root/\.local/share/gvfs-metadata/[^\0000/]([^\0000])*
+1 /root/\.local/share/gvfs-metadata/[^\0000/]([^\0000])*\0000/[^/](.)*
+1 /root/\.local/share/recently-used\.xbel([^\0000/])*
+1 /root/\.profile
+1 /root/\.pulse-cookie
+1 /root/\.pulse/
+1 /root/\.pulse/[^\0000/]([^\0000/])*
+1 /root/\.recently-used\.xbel([^\0000/])*
+1 /root/\.themes/
+1 /root/\.themes/[^\0000/]([^\0000])*
+1 /root/\.(|cache/)fontconfig/
+1 /root/\.(|cache/)fontconfig/[^\0000/]([^\0000])*
+1 /root/\.(|cache/)fontconfig/[^\0000/]([^\0000])*\0000/[^/](.)*
+1 /root/tmp/
+1 /root/tmp/[^\0000/]([^\0000])*
+1 /root/tmp/[^\0000/]([^\0000])*\0000/[^/](.)*
+1 /sys/devices/[^\0000/]([^\0000])*/block/[^\0000/]([^\0000])*/uevent
+1 /sys/devices/system/cpu/online
+1 /tmp/
+1 /tmp/[^\0000/]([^\0000])*
+1 /tmp/[^\0000/]([^\0000])*\0000/[^/](.)*
+1 /tmp/\.X11-unix/[^\0000/]([^\0000/])*
+1 /tmp/\.lwidentity/pipe
+1 /tmp/\.winbindd/pipe
+1 /tmp/krb5cc([^\0000/])*
+1 /tmp/pulse-([^\0000/])*/
+1 /tmp/pulse-([^\0000/])*/[^\0000/]([^\0000/])*
+1 /usr/X11R6/[^\0000/]([^\0000])*
+1 /usr/X11R6/([^\0000])*\.so([^\0000/])*
+1 /usr/bin/7za
+1 /usr/bin/7zr
+1 /usr/bin/Dooble
+1 /usr/bin/alpine
+1 /usr/bin/amarok
+1 /usr/bin/anjal
+1 /usr/bin/arora
+1 /usr/bin/audacious2
+1 /usr/bin/audacity
+1 /usr/bin/balsa
+1 /usr/bin/bangarang
+1 /usr/bin/banshee
+1 /usr/bin/banshee-1
+1 /usr/bin/bug-buddy
+1 /usr/bin/chromium-browser
+1 /usr/bin/citadel
+1 /usr/bin/claws-mail
+1 /usr/bin/cone
+1 /usr/bin/conkeror
+1 /usr/bin/dbus-launch
+1 /usr/bin/decibel
+1 /usr/bin/dillo
+1 /usr/bin/dircolors
+1 /usr/bin/dragon
+1 /usr/bin/dvipdfm
+1 /usr/bin/dvipdfmx
+1 /usr/bin/elinks
+1 /usr/bin/elmo
+1 /usr/bin/epiphany
+1 /usr/bin/epiphany-browser
+1 /usr/bin/epiphany-webkit
+1 /usr/bin/esperanza
+1 /usr/bin/evince
+1 /usr/bin/evince-previewer
+1 /usr/bin/evolution
+1 /usr/bin/exaile
+1 /usr/bin/exo-open
+1 /usr/bin/firefox
+1 /usr/bin/freevo
+1 /usr/bin/galeon
+1 /usr/bin/gedit
+1 /usr/bin/gmerlin
+1 /usr/bin/gmplayer
+1 /usr/bin/gnome-mplayer
+1 /usr/bin/gnome-terminal
+1 /usr/bin/gs-esp
+1 /usr/bin/gtk-gnash
+1 /usr/bin/gxmms
+1 /usr/bin/gxmms2
+1 /usr/bin/hornsey
+1 /usr/bin/iceweasel
+1 /usr/bin/jlgui
+1 /usr/bin/juk
+1 /usr/bin/kaffeine
+1 /usr/bin/kazehakase
+1 /usr/bin/kmail
+1 /usr/bin/kmplayer
+1 /usr/bin/konqueror
+1 /usr/bin/links
+1 /usr/bin/listen
+1 /usr/bin/lynx\.cur
+1 /usr/bin/mailody
+1 /usr/bin/midori
+1 /usr/bin/mktexpk
+1 /usr/bin/mktextfm
+1 /usr/bin/modest
+1 /usr/bin/mplayer
+1 /usr/bin/muine
+1 /usr/bin/mutt
+1 /usr/bin/nautilus
+1 /usr/bin/nautilus-sendto
+1 /usr/bin/netrik
+1 /usr/bin/netsurf
+1 /usr/bin/opera
+1 /usr/bin/potamus
+1 /usr/bin/prism
+1 /usr/bin/promoe
+1 /usr/bin/qmmp
+1 /usr/bin/quodlibet
+1 /usr/bin/rekonq
+1 /usr/bin/rhythmbox
+1 /usr/bin/seamonkey
+1 /usr/bin/sensible-browser
+1 /usr/bin/smplayer
+1 /usr/bin/strange-quark
+1 /usr/bin/swfdec-player
+1 /usr/bin/sylpheed
+1 /usr/bin/timidity
+1 /usr/bin/tkrat
+1 /usr/bin/totem
+1 /usr/bin/totem-gstreamer
+1 /usr/bin/totem-xine
+1 /usr/bin/unrar([^\0000/])*
+1 /usr/bin/unzip
+1 /usr/bin/vlc
+1 /usr/bin/w3m
+1 /usr/bin/xfmedia
+1 /usr/bin/xmms
+1 /usr/bin/yelp
+1 /usr/bin/zipnote
+1 /usr/include/X11/
+1 /usr/include/X11/[^\0000/]([^\0000])*
+1 /usr/lib([^\0000/])*/samba/lowcase\.dat
+1 /usr/lib([^\0000/])*/samba/upcase\.dat
+1 /usr/lib([^\0000/])*/samba/valid\.dat
+1 /usr/lib/([^\0000/])*-linux-gnu([^\0000/])*/[^\0000/]([^\0000])*
+1 /usr/lib/([^\0000/])*-linux-gnu([^\0000/])*/[^\0000/]([^\0000])*/lib([^\0000/])*\.so([^\0000/])*
+1 /usr/lib/([^\0000/])*-linux-gnu([^\0000/])*/dri/[^\0000/]([^\0000])*
+1 /usr/lib/([^\0000/])*-linux-gnu([^\0000/])*/gconv/([^\0000/])*\.so
+1 /usr/lib/([^\0000/])*-linux-gnu([^\0000/])*/gconv/gconv-modules([^\0000/])*
+1 /usr/lib/([^\0000/])*-linux-gnu([^\0000/])*/gdk-pixbuf-([^\0000/])*/[^\0000/]([^\0000])*
+1 /usr/lib/([^\0000/])*-linux-gnu([^\0000/])*/gnome-vfs-2\.0/modules/([^\0000/])*\.so
+1 /usr/lib/([^\0000/])*-linux-gnu([^\0000/])*/gtk-([^\0000/])*/[^\0000/]([^\0000])*
+1 /usr/lib/([^\0000/])*-linux-gnu([^\0000/])*/gtk/[^\0000/]([^\0000])*
+1 /usr/lib/([^\0000/])*-linux-gnu([^\0000/])*/krb5/plugins/libkrb5/
+1 /usr/lib/([^\0000/])*-linux-gnu([^\0000/])*/krb5/plugins/libkrb5/[^\0000/]([^\0000/])*
+1 /usr/lib/([^\0000/])*-linux-gnu([^\0000/])*/krb5/plugins/preauth/
+1 /usr/lib/([^\0000/])*-linux-gnu([^\0000/])*/krb5/plugins/preauth/[^\0000/]([^\0000/])*
+1 /usr/lib/([^\0000/])*-linux-gnu([^\0000/])*/lib([^\0000/])*\.so([^\0000/])*
+1 /usr/lib/([^\0000/])*-linux-gnu([^\0000/])*/libnss_([^\0000/])*\.so([^\0000/])*
+1 /usr/lib/([^\0000/])*-linux-gnu([^\0000/])*/pango/[^\0000/]([^\0000])*
+1 /usr/lib/([^\0000/])*-linux-gnu([^\0000/])*/pkcs11/([^\0000/])*\.so
+1 /usr/lib/([^\0000/])*-linux-gnu([^\0000/])*/xfce4/exo-1/exo-helper-1
+1 /usr/lib/GNUstep/Applications/GNUMail\.app/GNUMail
+1 /usr/lib/chromium-browser/chromium-browser
+1 /usr/lib/fennec-([^\0000/])*/fennec
+1 /usr/lib/fglrx/dri/[^\0000/]([^\0000])*
+1 /usr/lib/firefox([^\0000/])*/firefox([^\0000/])*\.sh
+1 /usr/lib/ghostscript/[^\0000/]([^\0000])*
+1 /usr/lib/gnome-vfs-2\.0/modules/([^\0000/])*\.so
+1 /usr/lib/icecat-([^\0000/])*/icecat
+1 /usr/lib/iceweasel/iceweasel
+1 /usr/lib/p7zip/7za
+1 /usr/lib/p7zip/7zr
+1 /usr/lib/thunderbird([^\0000/])*/thunderbird(|\.sh)
+1 /usr/lib/totem/[^\0000/]([^\0000])*
+1 /usr/lib/xorg/modules/fonts/([^\0000])*\.so([^\0000/])*
+1 /usr/lib((|32)|64)/[^\0000/]([^\0000])*
+1 /usr/lib((|32)|64)/[^\0000/]([^\0000])*/lib([^\0000/])*\.so([^\0000/])*
+1 /usr/lib((|32)|64)/([^\0000/])*\.so([^\0000/])*
+1 /usr/lib((|32)|64)/dri/[^\0000/]([^\0000])*
+1 /usr/lib((|32)|64)/gconv/([^\0000/])*\.so
+1 /usr/lib((|32)|64)/gconv/gconv-modules([^\0000/])*
+1 /usr/lib((|32)|64)/gdk-pixbuf-([^\0000/])*/[^\0000/]([^\0000])*
+1 /usr/lib((|32)|64)/gtk-([^\0000/])*/[^\0000/]([^\0000])*
+1 /usr/lib((|32)|64)/gtk/[^\0000/]([^\0000])*
+1 /usr/lib((|32)|64)/krb5/plugins/libkrb5/
+1 /usr/lib((|32)|64)/krb5/plugins/libkrb5/[^\0000/]([^\0000/])*
+1 /usr/lib((|32)|64)/krb5/plugins/preauth/
+1 /usr/lib((|32)|64)/krb5/plugins/preauth/[^\0000/]([^\0000/])*
+1 /usr/lib((|32)|64)/libnss_([^\0000/])*\.so([^\0000/])*
+1 /usr/lib((|32)|64)/locale/[^\0000/]([^\0000])*
+1 /usr/lib((|32)|64)/openoffice/share/fonts/[^\0000/]([^\0000])*
+1 /usr/lib((|32)|64)/pango/[^\0000/]([^\0000])*
+1 /usr/lib((|32)|64)/pkcs11/([^\0000/])*\.so
+1 /usr/lib((|32)|64)/sasl2/[^\0000/]([^\0000/])*
+1 /usr/local/share/
+1 /usr/local/share/[^\0000/]([^\0000])*
+1 /usr/local/share/ca-certificates/
+1 /usr/local/share/ca-certificates/[^\0000/]([^\0000])*
+1 /usr/local/share/fonts/
+1 /usr/local/share/fonts/[^\0000/]([^\0000])*
+1 /usr/local/share/icons/
+1 /usr/local/share/icons/[^\0000/]([^\0000])*
+1 /usr/local/share/pixmaps/
+1 /usr/local/share/pixmaps/[^\0000/]([^\0000])*
+1 /usr/share/
+1 /usr/share/[^\0000/]([^\0000])*
+1 /usr/share/[^\0000/]([^\0000])*/icon-theme\.cache
+1 /usr/share/[^\0000/]([^\0000])*/locale/[^\0000/]([^\0000])*
+1 /usr/share/AbiSuite/fonts/[^\0000/]([^\0000])*
+1 /usr/share/X11/
+1 /usr/share/X11/[^\0000/]([^\0000])*
+1 /usr/share/X11/locale/[^\0000/]([^\0000])*
+1 /usr/share/a2ps/fonts/[^\0000/]([^\0000])*
+1 /usr/share/alsa/[^\0000/]([^\0000])*
+1 /usr/share/applications/
+1 /usr/share/applications/([^\0000/])*\.desktop
+1 /usr/share/applications/mimeinfo\.cache
+1 /usr/share/ca-certificates/
+1 /usr/share/ca-certificates/[^\0000/]([^\0000])*
+1 /usr/share/common-licenses/[^\0000/]([^\0000])*
+1 /usr/share/cups/charmaps/[^\0000/]([^\0000])*
+1 /usr/share/fonts/
+1 /usr/share/fonts/[^\0000/]([^\0000])*
+1 /usr/share/ghostscript/fonts/[^\0000/]([^\0000])*
+1 /usr/share/gnome/applications/mimeinfo\.cache
+1 /usr/share/gvfs/remote-volume-monitors/
+1 /usr/share/gvfs/remote-volume-monitors/[^\0000/]([^\0000/])*
+1 /usr/share/icons/
+1 /usr/share/icons/[^\0000/]([^\0000])*
+1 /usr/share/locale-langpack/[^\0000/]([^\0000])*
+1 /usr/share/locale/[^\0000/]([^\0000])*
+1 /usr/share/mime/[^\0000/]([^\0000])*
+1 /usr/share/minirok/minirok\.py
+1 /usr/share/p11-kit/modules/
+1 /usr/share/p11-kit/modules/[^\0000/]([^\0000/])*
+1 /usr/share/pixmaps/
+1 /usr/share/pixmaps/[^\0000/]([^\0000])*
+1 /usr/share/poppler/cMap/[^\0000/]([^\0000])*
+1 /usr/share/sounds/[^\0000/]([^\0000])*
+1 /usr/share/ssl/certs/ca-bundle\.crt
+1 /usr/share/terminfo/[^\0000/]([^\0000])*
+1 /usr/share/texmf/(|([^\0000/])*/)fonts/[^\0000/]([^\0000])*
+1 /usr/share/themes/[^\0000/]([^\0000])*
+1 /usr/share/xfce/fonts/[^\0000/]([^\0000])*
+1 /usr/share/zoneinfo/
+1 /usr/share/zoneinfo/[^\0000/]([^\0000])*
+1 /var/cache/[^\0000/]([^\0000])*/icon-theme\.cache
+1 /var/cache/fontconfig/[^\0000/]([^\0000])*
+1 /var/cache/fonts/[^\0000/]([^\0000])*
+1 /var/lib/dbus/machine-id
+1 /var/lib/defoma/[^\0000/]([^\0000])*
+1 /var/lib/ghostscript/[^\0000/]([^\0000])*
+1 /var/lib/likewise-open/lwidentity_privileged/pipe
+1 /var/lib/misc/([^\0000/])*\.db
+1 /var/lib/sss/mc/group
+1 /var/lib/sss/mc/passwd
+1 /var/lib/texmf/[^\0000/]([^\0000])*
+1 /var/tmp/
+1 /var/tmp/[^\0000/]([^\0000])*
+1 /var/tmp/[^\0000/]([^\0000])*\0000/[^/](.)*
+1 /var/yp/binding/[^\0000/]([^\0000/])*
+1 /var/((db|cache)|run)/nscd/(((passwd|group)|services)|host)
+1 /var/(lib|run)/samba/winbindd_privileged/pipe
+1 /(|var/)run/\.nscd_socket
+1 /(|var/)run/avahi-daemon/socket
+1 /(|var/)run/cups/cups\.sock
+1 /(|var/)run/dbus/system_bus_socket
+1 /(|var/)run/mdnsd
+1 /(|var/)run/nscd/db([^\0000/])*
+1 /(|var/)run/nscd/socket
+1 /(|var/)run/resolvconf/resolv\.conf
+1 /(|var/)run/user/[^\0000/]([^\0000/])*/dconf/
+1 /(|var/)run/user/[^\0000/]([^\0000/])*/dconf/user
+1 /(|var/)run/user/[^\0000/]([^\0000/])*/pulse/
+1 /(|var/)run/user/[^\0000/]([^\0000/])*/pulse/(native|pid)
+1 /(|var/)run/user/[0123456789]([^\0000/])*/keyring([^\0000/])*/pkcs11
+1 /(run|dev)/shm/
+1 /(run|dev)/shm/pulse-shm([^\0000/])*
+1 /home/[^\0000/]([^\0000/])*/\.([^\0000/])*\.bak deny
+1 /home/[^\0000/]([^\0000/])*/\.([^\0000/])*\.bak\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.([^\0000/])*\.swp deny
+1 /home/[^\0000/]([^\0000/])*/\.([^\0000/])*\.swp\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.([^\0000/])*history deny
+1 /home/[^\0000/]([^\0000/])*/\.([^\0000/])*history\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.([^\0000/])*rc deny
+1 /home/[^\0000/]([^\0000/])*/\.([^\0000/])*rc\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.([^\0000/])*~ deny
+1 /home/[^\0000/]([^\0000/])*/\.([^\0000/])*~\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.([^\0000/])*~1~ deny
+1 /home/[^\0000/]([^\0000/])*/\.([^\0000/])*~1~\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.bash([^\0000/])* deny
+1 /home/[^\0000/]([^\0000/])*/\.bash([^\0000/])*\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.config/autostart/[^\0000/]([^\0000])* deny
+1 /home/[^\0000/]([^\0000/])*/\.config/autostart/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.config/chromium/[^\0000/]([^\0000])* deny
+1 /home/[^\0000/]([^\0000/])*/\.config/chromium/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.config/evolution/[^\0000/]([^\0000])* deny
+1 /home/[^\0000/]([^\0000/])*/\.config/evolution/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.config/upstart/[^\0000/]([^\0000])* deny
+1 /home/[^\0000/]([^\0000/])*/\.config/upstart/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.evolution/[^\0000/]([^\0000])* deny
+1 /home/[^\0000/]([^\0000/])*/\.evolution/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.fetchmail([^\0000/])* deny
+1 /home/[^\0000/]([^\0000/])*/\.fetchmail([^\0000/])*\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.gnome2/keyrings/[^\0000/]([^\0000])* deny
+1 /home/[^\0000/]([^\0000/])*/\.gnome2/keyrings/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.gnome2_private/[^\0000/]([^\0000])* deny
+1 /home/[^\0000/]([^\0000/])*/\.gnome2_private/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.gnupg/[^\0000/]([^\0000])* deny
+1 /home/[^\0000/]([^\0000/])*/\.gnupg/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.init/[^\0000/]([^\0000])* deny
+1 /home/[^\0000/]([^\0000/])*/\.init/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.inputrc deny
+1 /home/[^\0000/]([^\0000/])*/\.inputrc\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.kde/share/apps/kmail/[^\0000/]([^\0000])* deny
+1 /home/[^\0000/]([^\0000/])*/\.kde/share/apps/kmail/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.kde/share/apps/kwallet/[^\0000/]([^\0000])* deny
+1 /home/[^\0000/]([^\0000/])*/\.kde/share/apps/kwallet/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.kde/share/config/[^\0000/]([^\0000])* deny
+1 /home/[^\0000/]([^\0000/])*/\.kde/share/config/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.kde(|4)/Autostart/[^\0000/]([^\0000])* deny
+1 /home/[^\0000/]([^\0000/])*/\.kde(|4)/Autostart/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.kde(|4)/env/[^\0000/]([^\0000])* deny
+1 /home/[^\0000/]([^\0000/])*/\.kde(|4)/env/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.mozilla/[^\0000/]([^\0000])*/bookmarkbackups/[^\0000/]([^\0000])* deny
+1 /home/[^\0000/]([^\0000/])*/\.mozilla/[^\0000/]([^\0000])*/bookmarkbackups/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.mozilla/[^\0000/]([^\0000])*/chrome/[^\0000/]([^\0000])* deny
+1 /home/[^\0000/]([^\0000/])*/\.mozilla/[^\0000/]([^\0000])*/chrome/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.mozilla/[^\0000/]([^\0000])*/extensions/[^\0000/]([^\0000])* deny
+1 /home/[^\0000/]([^\0000/])*/\.mozilla/[^\0000/]([^\0000])*/extensions/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.mozilla/[^\0000/]([^\0000])*/gm_scripts/[^\0000/]([^\0000])* deny
+1 /home/[^\0000/]([^\0000/])*/\.mozilla/[^\0000/]([^\0000])*/gm_scripts/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.mozilla/[^\0000/]([^\0000/])*/[^\0000/]([^\0000/])*/[^\0000/]([^\0000/])* deny
+1 /home/[^\0000/]([^\0000/])*/\.mozilla/[^\0000/]([^\0000/])*/[^\0000/]([^\0000/])*/[^\0000/]([^\0000/])*\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.pki/nssdb/[^\0000/]([^\0000])* deny
+1 /home/[^\0000/]([^\0000/])*/\.pki/nssdb/([^\0000/])*\.so(|\.[0123456789]([^\0000/])*) deny
+1 /home/[^\0000/]([^\0000/])*/\.pki/nssdb/([^\0000/])*\.so(|\.[0123456789]([^\0000/])*)\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.ssh/[^\0000/]([^\0000])* deny
+1 /home/[^\0000/]([^\0000/])*/\.ssh/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.viminfo([^\0000/])* deny
+1 /home/[^\0000/]([^\0000/])*/\.viminfo([^\0000/])*\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.zshenv deny
+1 /home/[^\0000/]([^\0000/])*/\.zshenv\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.(|mozilla-)thunderbird/[^\0000/]([^\0000/])*/[^\0000/]([^\0000/])* deny
+1 /home/[^\0000/]([^\0000/])*/\.(|mozilla-)thunderbird/[^\0000/]([^\0000/])*/[^\0000/]([^\0000/])*\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.(|mozilla-)thunderbird/[^\0000/]([^\0000/])*/[^C][^a][^c][^h][^e]([^\0000/])*/[^\0000/]([^\0000])* deny
+1 /home/[^\0000/]([^\0000/])*/\.(|mozilla-)thunderbird/[^\0000/]([^\0000/])*/[^C][^a][^c][^h][^e]([^\0000/])*/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.(|z)log(in|out) deny
+1 /home/[^\0000/]([^\0000/])*/\.(|z)log(in|out)\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/\.(|z)profile([^\0000/])* deny
+1 /home/[^\0000/]([^\0000/])*/\.(|z)profile([^\0000/])*\0000/[^/](.)* deny
+1 /home/[^\0000/]([^\0000/])*/bin/[^\0000/]([^\0000])* deny
+1 /home/[^\0000/]([^\0000/])*/bin/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /root/\.([^\0000/])*\.bak deny
+1 /root/\.([^\0000/])*\.bak\0000/[^/](.)* deny
+1 /root/\.([^\0000/])*\.swp deny
+1 /root/\.([^\0000/])*\.swp\0000/[^/](.)* deny
+1 /root/\.([^\0000/])*history deny
+1 /root/\.([^\0000/])*history\0000/[^/](.)* deny
+1 /root/\.([^\0000/])*rc deny
+1 /root/\.([^\0000/])*rc\0000/[^/](.)* deny
+1 /root/\.([^\0000/])*~ deny
+1 /root/\.([^\0000/])*~\0000/[^/](.)* deny
+1 /root/\.([^\0000/])*~1~ deny
+1 /root/\.([^\0000/])*~1~\0000/[^/](.)* deny
+1 /root/\.bash([^\0000/])* deny
+1 /root/\.bash([^\0000/])*\0000/[^/](.)* deny
+1 /root/\.config/autostart/[^\0000/]([^\0000])* deny
+1 /root/\.config/autostart/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /root/\.config/chromium/[^\0000/]([^\0000])* deny
+1 /root/\.config/chromium/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /root/\.config/evolution/[^\0000/]([^\0000])* deny
+1 /root/\.config/evolution/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /root/\.config/upstart/[^\0000/]([^\0000])* deny
+1 /root/\.config/upstart/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /root/\.evolution/[^\0000/]([^\0000])* deny
+1 /root/\.evolution/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /root/\.fetchmail([^\0000/])* deny
+1 /root/\.fetchmail([^\0000/])*\0000/[^/](.)* deny
+1 /root/\.gnome2/keyrings/[^\0000/]([^\0000])* deny
+1 /root/\.gnome2/keyrings/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /root/\.gnome2_private/[^\0000/]([^\0000])* deny
+1 /root/\.gnome2_private/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /root/\.gnupg/[^\0000/]([^\0000])* deny
+1 /root/\.gnupg/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /root/\.init/[^\0000/]([^\0000])* deny
+1 /root/\.init/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /root/\.inputrc deny
+1 /root/\.inputrc\0000/[^/](.)* deny
+1 /root/\.kde/share/apps/kmail/[^\0000/]([^\0000])* deny
+1 /root/\.kde/share/apps/kmail/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /root/\.kde/share/apps/kwallet/[^\0000/]([^\0000])* deny
+1 /root/\.kde/share/apps/kwallet/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /root/\.kde/share/config/[^\0000/]([^\0000])* deny
+1 /root/\.kde/share/config/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /root/\.kde(|4)/Autostart/[^\0000/]([^\0000])* deny
+1 /root/\.kde(|4)/Autostart/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /root/\.kde(|4)/env/[^\0000/]([^\0000])* deny
+1 /root/\.kde(|4)/env/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /root/\.mozilla/[^\0000/]([^\0000])*/bookmarkbackups/[^\0000/]([^\0000])* deny
+1 /root/\.mozilla/[^\0000/]([^\0000])*/bookmarkbackups/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /root/\.mozilla/[^\0000/]([^\0000])*/chrome/[^\0000/]([^\0000])* deny
+1 /root/\.mozilla/[^\0000/]([^\0000])*/chrome/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /root/\.mozilla/[^\0000/]([^\0000])*/extensions/[^\0000/]([^\0000])* deny
+1 /root/\.mozilla/[^\0000/]([^\0000])*/extensions/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /root/\.mozilla/[^\0000/]([^\0000])*/gm_scripts/[^\0000/]([^\0000])* deny
+1 /root/\.mozilla/[^\0000/]([^\0000])*/gm_scripts/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /root/\.mozilla/[^\0000/]([^\0000/])*/[^\0000/]([^\0000/])*/[^\0000/]([^\0000/])* deny
+1 /root/\.mozilla/[^\0000/]([^\0000/])*/[^\0000/]([^\0000/])*/[^\0000/]([^\0000/])*\0000/[^/](.)* deny
+1 /root/\.pki/nssdb/[^\0000/]([^\0000])* deny
+1 /root/\.pki/nssdb/([^\0000/])*\.so(|\.[0123456789]([^\0000/])*) deny
+1 /root/\.pki/nssdb/([^\0000/])*\.so(|\.[0123456789]([^\0000/])*)\0000/[^/](.)* deny
+1 /root/\.ssh/[^\0000/]([^\0000])* deny
+1 /root/\.ssh/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /root/\.viminfo([^\0000/])* deny
+1 /root/\.viminfo([^\0000/])*\0000/[^/](.)* deny
+1 /root/\.zshenv deny
+1 /root/\.zshenv\0000/[^/](.)* deny
+1 /root/\.(|mozilla-)thunderbird/[^\0000/]([^\0000/])*/[^\0000/]([^\0000/])* deny
+1 /root/\.(|mozilla-)thunderbird/[^\0000/]([^\0000/])*/[^\0000/]([^\0000/])*\0000/[^/](.)* deny
+1 /root/\.(|mozilla-)thunderbird/[^\0000/]([^\0000/])*/[^C][^a][^c][^h][^e]([^\0000/])*/[^\0000/]([^\0000])* deny
+1 /root/\.(|mozilla-)thunderbird/[^\0000/]([^\0000/])*/[^C][^a][^c][^h][^e]([^\0000/])*/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /root/\.(|z)log(in|out) deny
+1 /root/\.(|z)log(in|out)\0000/[^/](.)* deny
+1 /root/\.(|z)profile([^\0000/])* deny
+1 /root/\.(|z)profile([^\0000/])*\0000/[^/](.)* deny
+1 /root/bin/[^\0000/]([^\0000])* deny
+1 /root/bin/[^\0000/]([^\0000])*\0000/[^/](.)* deny
+1 /run/udev/data/[^\0000/]([^\0000])* deny
+1 /
+1 /[^\0000/]([^\0000])*
+1 /[^\0000/]([^\0000])*\0000/[^/](.)*
+1 /bin/[^\0000/]([^\0000/])*
+1 /dev/full
+1 /dev/log
+1 /dev/null
+1 /dev/random
+1 /dev/urandom
+1 /dev/zero
+1 /etc/bindresvport\.blacklist
+1 /etc/ld\.so\.cache
+1 /etc/locale\.alias
+1 /etc/locale/[^\0000/]([^\0000])*
+1 /etc/localtime
+1 /etc/writable/localtime
+1 /home/[^\0000/]([^\0000/])*/\.Private/[^\0000/]([^\0000])*
+1 /home/[^\0000/]([^\0000/])*/\.Private/[^\0000/]([^\0000])*\0000/[^/](.)*
+1 /home/\.ecryptfs/[^\0000/]([^\0000/])*/\.Private/[^\0000/]([^\0000])*
+1 /home/\.ecryptfs/[^\0000/]([^\0000/])*/\.Private/[^\0000/]([^\0000])*\0000/[^/](.)*
+1 /lib/([^\0000/])*-linux-gnu([^\0000/])*/[^\0000/]([^\0000])*
+1 /lib/([^\0000/])*-linux-gnu([^\0000/])*/[^\0000/]([^\0000])*/lib([^\0000/])*\.so([^\0000/])*
+1 /lib/([^\0000/])*-linux-gnu([^\0000/])*/ld((|32)|64)-([^\0000/])*\.so
+1 /lib/([^\0000/])*-linux-gnu([^\0000/])*/lib([^\0000/])*\.so([^\0000/])*
+1 /lib/i386-linux-gnu/tls/i686/(cmov|nosegneg)/ld-([^\0000/])*\.so
+1 /lib/i386-linux-gnu/tls/i686/(cmov|nosegneg)/lib([^\0000/])*\.so([^\0000/])*
+1 /lib/tls/i686/(cmov|nosegneg)/ld-([^\0000/])*\.so
+1 /lib/tls/i686/(cmov|nosegneg)/lib([^\0000/])*\.so([^\0000/])*
+1 /lib((|32)|64)/[^\0000/]([^\0000])*
+1 /lib((|32)|64)/[^\0000/]([^\0000])*/ld((|32)|64)-([^\0000/])*\.so
+1 /lib((|32)|64)/[^\0000/]([^\0000])*/lib([^\0000/])*\.so([^\0000/])*
+1 /lib((|32)|64)/ld((|32)|64)-([^\0000/])*\.so
+1 /lib((|32)|64)/lib([^\0000/])*\.so([^\0000/])*
+1 /opt/([^\0000/])*-linux-uclibc/lib/ld-uClibc([^\0000/])*so([^\0000/])*
+1 /opt/google/chrome/chrome
+1 /opt/google/chrome/chrome-sandbox
+1 /opt/google/chrome/google-chrome
+1 /opt/google/chrome/lib([^\0000/])*\.so(|\.([^\0000/])*)
+1 /proc/[^\0000/]([^\0000/])*/maps
+1 /proc/cpuinfo
+1 /proc/filesystems
+1 /proc/meminfo
+1 /proc/stat
+1 /proc/sys/crypto/[^\0000/]([^\0000/])*
+1 /proc/sys/kernel/ngroups_max
+1 /proc/sys/kernel/version
+1 /proc/sys/vm/overcommit_memory
+1 /root/\.Private/[^\0000/]([^\0000])*
+1 /root/\.Private/[^\0000/]([^\0000])*\0000/[^/](.)*
+1 /sbin/[^\0000/]([^\0000/])*
+1 /sys/devices/system/cpu/online
+1 /usr/bin/[^\0000/]([^\0000/])*
+1 /usr/lib/([^\0000/])*-linux-gnu([^\0000/])*/[^\0000/]([^\0000])*
+1 /usr/lib/([^\0000/])*-linux-gnu([^\0000/])*/[^\0000/]([^\0000])*/lib([^\0000/])*\.so([^\0000/])*
+1 /usr/lib/([^\0000/])*-linux-gnu([^\0000/])*/gconv/([^\0000/])*\.so
+1 /usr/lib/([^\0000/])*-linux-gnu([^\0000/])*/gconv/gconv-modules([^\0000/])*
+1 /usr/lib/([^\0000/])*-linux-gnu([^\0000/])*/lib([^\0000/])*\.so([^\0000/])*
+1 /usr/lib/chromium-browser/chromium-browser-sandbox
+1 /usr/lib((|32)|64)/[^\0000/]([^\0000])*
+1 /usr/lib((|32)|64)/[^\0000/]([^\0000])*/lib([^\0000/])*\.so([^\0000/])*
+1 /usr/lib((|32)|64)/([^\0000/])*\.so([^\0000/])*
+1 /usr/lib((|32)|64)/gconv/([^\0000/])*\.so
+1 /usr/lib((|32)|64)/gconv/gconv-modules([^\0000/])*
+1 /usr/lib((|32)|64)/locale/[^\0000/]([^\0000])*
+1 /usr/local/bin/[^\0000/]([^\0000/])*
+1 /usr/sbin/[^\0000/]([^\0000/])*
+1 /usr/share/[^\0000/]([^\0000])*/locale/[^\0000/]([^\0000])*
+1 /usr/share/X11/locale/[^\0000/]([^\0000])*
+1 /usr/share/common-licenses/[^\0000/]([^\0000])*
+1 /usr/share/locale-langpack/[^\0000/]([^\0000])*
+1 /usr/share/locale/[^\0000/]([^\0000])*
+1 /usr/share/software-center/[^\0000/]([^\0000/])*
+1 /usr/share/zoneinfo/
+1 /usr/share/zoneinfo/[^\0000/]([^\0000])*
+1 /usr/(|local/)lib([^\0000/])*/(|([^\0000])*/)([^\0000/])*
+1 /((|usr/)|usr/local/)lib((|32)|64)/(|([^\0000])*/)([^\0000/])*\.so(|\.([^\0000/])*)
diff --git a/devtools/match.txt b/devtools/match.txt
new file mode 100644
index 0000000..549f43d
--- /dev/null
+++ b/devtools/match.txt
@@ -0,0 +1,14 @@
+1 /abdcd
+1 /defg
+1 /home/
+0 abc
+1 /asdfjhlnlwknrlwknklwenflwknfsam.,smdfakdflkafa;ldfkwekjlmnsmnvaslkdfjwfnkaef
+1 /alkoijnlkn lkasdfasfwedvasvsdvasv
+1 /lkasjdflkasjdflaskflj;kjwef;kjav;klansvlkjaoifjaskl;vnda;lsdvna
+1 /home/alskdf;jasldka;lsvnkasvlajk hnqlkjwnlkjavn;asldkjvkalsjf;lasjkdf;lsdf
+1 /home/a;dsjfk;lasjkfslafkj;aslfkjasljfk;alsfkj;slafkj;las
+0 laksjdf;lasjkdf;aslkdfj;alsjkdf;alsf
+0 ;lasjkdf;lasjkdf;lajh;oiwfwiovnsadjkvbaskdvblavjbklwjvbaskdjvb;wiefuhsa;jdkvb
+0 jjjjjjasldfasldflll
+0 asdf
+0 a
diff --git a/devtools/print_hfa.c b/devtools/print_hfa.c
new file mode 100644
index 0000000..c5a5b65
--- /dev/null
+++ b/devtools/print_hfa.c
@@ -0,0 +1,192 @@
+/*
+ * AppArmor security module
+ *
+ * Copyright 2016 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "../libraries/libapparmor/src/hfa.h"
+
+typedef struct {
+ unsigned int perm;
+ char *str;
+} entry;
+
+const char *progname;
+
+void display_version(void)
+{
+ printf("%s version 0.1\n", progname);
+}
+
+static void usage(void)
+{
+ fprintf(stderr,
+ "Usage: %s [options] <file>\n"
+ "Options:\n"
+ "--------\n"
+ , progname);
+}
+
+const char *short_options = "";
+struct option long_options[] = {
+ {NULL, 0, 0, 0},
+};
+
+static int process_args(int argc, char *argv[])
+{
+ int c, o;
+
+ while ((c = getopt_long(argc, argv, short_options, long_options, &o)) != -1) {
+ //long tmp;
+ switch (c) {
+ case 0:
+ fprintf(stderr, "Error in getopt_long handling\n");
+ exit(1);
+ break;
+ }
+
+ }
+
+ return optind;
+}
+
+char *load_file(const char *path, ssize_t *fsize)
+{
+ struct stat stat;
+ char *buffer;
+ ssize_t remaining;
+ int fd, res;
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1) {
+ fprintf(stderr, " Error '%s', failed to open '%s'\n", strerror(errno), path);
+ goto out;
+ }
+
+ res = fstat(fd, &stat);
+ if (res != 0) {
+ fprintf(stderr, "Error '%s', could not get size of file '%s'\n", strerror(errno), path);
+ close(fd);
+ goto out_fd;
+ }
+
+ buffer = (char *) malloc(stat.st_size + 1);
+ if (!buffer) {
+ fprintf(stderr, "Error could not allocate buffer '%s'\n", path);
+ close(fd);
+ goto out_fd;
+ }
+
+ remaining = stat.st_size;
+ do {
+ ssize_t size;
+ size = read(fd, buffer, remaining);
+ if (size == -1) {
+ if (errno != EAGAIN) {
+ fprintf(stderr, "Error reading file '%s'\n", path);
+ goto out_buffer;
+ }
+ } else
+ remaining -= size;
+ } while (remaining);
+
+ close(fd);
+ buffer[stat.st_size] = 0;
+
+ *fsize = stat.st_size;
+ return buffer;
+
+out_buffer:
+ free(buffer);
+out_fd:
+ close(fd);
+out:
+ return NULL;
+}
+
+int main(int argc, char **argv)
+{
+ const char *err;
+ char *chfa;
+ ssize_t size;
+ int i;
+
+ progname = argv[0];
+
+ if (argc < 2) {
+ usage();
+ return 1;
+ }
+
+ for (i = optind; i <= argc && argv[i]; i++) {
+ struct direct_mapped_accept accept;
+ struct aa_hfa *hfa = NULL;
+ if (!(chfa = load_file(argv[i], &size))) {
+ fprintf(stderr, "Error failed to process match arg '%s'\n", argv[i]);
+ continue;
+ }
+
+ fprintf(stderr, "Unpacking HFA\n");
+ err = NULL;
+ hfa = aa_hfa_unpack(chfa, size, &err, &accept);
+ if (!hfa) {
+ fprintf(stderr, "Error failed to unpack compressed hfa: %s\n", err);
+ exit(1);
+ }
+ free(chfa);
+
+ if (accept.size) {
+ u32 j;
+
+ fprintf(stdout, " accept table\n");
+ fprintf(stdout, "----------------------------\n");
+ fprintf(stdout, "index accept1 accept2\n");
+ for (j = 0; j < accept.size; j++)
+ fprintf(stdout, "%5d 0x%08x 0x%08x\n", j,
+ accept.table[j].accept1,
+ accept.table[j].accept2);
+
+ fprintf(stdout, "\n");
+ }
+ fprint_hfa(stdout, hfa);
+
+ aa_hfa_free(hfa);
+ }
+ return 0;
+}
+
+/* To write hfa to a memory buffer do
+void print_hfa_to_memory_stream(struct aa_hfa *hfa)
+{
+ char *bp;
+ size_t *size;
+
+ f = open_memstream(&bp, size);
+ fprint_hfa(f, hfa);
+ fflush (f); // update bp and size
+ printf ("buf = `%s', size = %d\n", bp, size);
+ fprintf (f, ", world");
+ fclose (f); // update bp and size
+ printf ("buf = `%s', size = %d\n", bp, size);
+ free(bp); // free stream buffer
+}
+*/
diff --git a/devtools/test_re.cc b/devtools/test_re.cc
new file mode 100644
index 0000000..57ce55e
--- /dev/null
+++ b/devtools/test_re.cc
@@ -0,0 +1,440 @@
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <list>
+
+#include "../parser/common_optarg.h"
+#include "../parser/libapparmor_re/aare_rules.h"
+
+#include "../libraries/libapparmor/include/sys/apparmor.h"
+#include "../libraries/libapparmor/src/hfa.h"
+#include "../libraries/libapparmor/src/hfa_private.h"
+
+typedef struct {
+ unsigned int perm;
+ char *str;
+} entry;
+
+const char *progname;
+int g_dump_info = 0;
+int g_print_time = 0;
+long g_repeat_count = 1;
+const char *g_sep = "\n";
+const char *g_out_file = NULL;
+
+dfaflags_t hfaflags = (dfaflags_t)(DFA_CONTROL_TREE_NORMAL | DFA_CONTROL_TREE_SIMPLE | DFA_CONTROL_MINIMIZE );
+
+aare_rules *g_rules;
+std::list<entry> g_matches;
+
+
+int process_expr_line(const char *line);
+int process_expr_file(const char *path);
+int process_match_line(const char *line);
+int process_match_file(const char *path);
+
+void display_version(void)
+{
+ printf("%s version 0.1\n", progname);
+}
+
+static void usage(void)
+{
+ fprintf(stderr,
+ "Usage: %s [options] [match entries]*\n"
+ "Options:\n"
+ "--------\n"
+ "-h, --help [n] display usage, or help for cmd [n]\n"
+ "-t, --time show time spent doing match\n"
+ "-c, --count n repeat the match set n times\n"
+ "-s, --separator n using n as line separator in file\n"
+ "-e, --expr n add expr to the hfa\n"
+ "-E, --expr-file n add exprs in n to the hfa\n"
+ "-m, --match n add match string to be tested\n"
+ "-M, --match-file n add match strings in n to be tested\n"
+ "-o, --out n write generated hfa to n\n"
+ "-O, --optimize [n] set optimization flags\n"
+ "-D, --dump [n] dump info\n\n"
+ "Match and expr entries are expressed as \"# string\"\n"
+ " eg. -e \"1 /.*\" -m \"1 /abc\"\n"
+ , progname);
+}
+
+const char *short_options = "h::o:tc:s:e:E:m:M:D::O:";
+struct option long_options[] = {
+ {"help", 2, 0, 'h'},
+ {"out", 1, 0, 'o'},
+ {"time", 0, 0, 't'},
+ {"count", 1, 0, 'c'},
+ {"seperator", 1, 0, 's'},
+ {"expr", 1, 0, 'e'},
+ {"expr-file", 1, 0, 'E'},
+ {"match", 1, 0, 'm'},
+ {"match-file", 1, 0, 'M'},
+ {"dump", 2, 0, 'D'},
+ {"optimize", 2, 0, 'O'},
+ {NULL, 0, 0, 0},
+};
+
+static int process_args(int argc, char *argv[])
+{
+ int c, o;
+
+ while ((c = getopt_long(argc, argv, short_options, long_options, &o)) != -1) {
+ long tmp;
+ switch (c) {
+ case 0:
+ fprintf(stderr, "Error in getopt_long handling\n");
+ exit(1);
+ break;
+ case 'h':
+ if (!optarg) {
+ usage();
+ } else if (strcmp(optarg, "Dump") == 0 ||
+ strcmp(optarg, "dump") == 0 ||
+ strcmp(optarg, "D") == 0) {
+ display_dump(progname);
+ } else if (strcmp(optarg, "Optimize") == 0 ||
+ strcmp(optarg, "optimize") == 0 ||
+ strcmp(optarg, "O") == 0) {
+ display_optimize(progname);
+ } else {
+ fprintf(stderr, "%s: Invalid --help option %s\n",
+ progname, optarg);
+ exit(1);
+ }
+ exit(0);
+ break;
+ case 't':
+ g_print_time = 1;
+ break;
+ case 'c': /* repeat count */
+ tmp = strtol(optarg, NULL, 0);
+ if (tmp < 1)
+ fprintf(stderr, "Error bad repeat count '%s'\n",
+ optarg);
+ else if (tmp == LONG_MAX && errno == ERANGE)
+ fprintf(stderr, "Error repeat count '%s' out of range\n", optarg);
+ else
+ g_repeat_count = tmp;
+ break;
+ case 's':
+ g_sep = optarg;
+ break;
+ case 'e': /* expression */
+ if (!process_expr_line(optarg))
+ fprintf(stderr, "Error processing expr '%s'\n",
+ optarg);
+ break;
+ case 'E':
+ if (!process_expr_file(optarg)) {
+ fprintf(stderr, "Error processing expr file '%s'\n", optarg);
+ exit(1);
+ }
+ break;
+ case 'm': /* text to match */
+ if (!process_match_line(optarg))
+ fprintf(stderr, "Error processing match '%s'\n",
+ optarg);
+ break;
+ case 'M':
+ if (!process_match_file(optarg)) {
+ fprintf(stderr, "Error processing match file '%s'\n", optarg);
+ exit(1);
+ }
+ break;
+ case 'o':
+ g_out_file = optarg;
+ break;
+ case 'D':
+ if (!optarg) {
+ g_dump_info = 1;
+ handle_flag_table(dumpflag_table, "stats",
+ &hfaflags);
+ } else if (!handle_flag_table(dumpflag_table, optarg,
+ &hfaflags)) {
+ fprintf(stderr, "%s: Invalid --Dump option %s\n",
+ progname, optarg);
+ exit(1);
+ }
+ break;
+ case 'O':
+ if (!optarg) {
+ /* todo: default optimization */
+ } else if (!handle_flag_table(optflag_table, optarg,
+ &hfaflags)) {
+ fprintf(stderr, "%s: Invalid --Optimize option %s\n",
+ progname, optarg);
+ exit(1);
+ }
+ break;
+
+ }
+
+ }
+
+ return optind;
+}
+
+char *load_file(const char *path)
+{
+ struct stat stat;
+ char *buffer;
+ ssize_t remaining;
+ int fd, res;
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1) {
+ fprintf(stderr, " Error '%s', failed to open '%s'\n", strerror(errno), path);
+ goto out;
+ }
+
+ res = fstat(fd, &stat);
+ if (res != 0) {
+ fprintf(stderr, "Error '%s', could not get size of file '%s'\n", strerror(errno), path);
+ close(fd);
+ goto out_fd;
+ }
+
+ buffer = (char *) malloc(stat.st_size + 1);
+ if (!buffer) {
+ fprintf(stderr, "Error could not allocate buffer '%s'\n", path);
+ close(fd);
+ goto out_fd;
+ }
+
+ remaining = stat.st_size;
+ do {
+ ssize_t size;
+ size = read(fd, buffer, remaining);
+ if (size == -1) {
+ if (errno != EAGAIN) {
+ fprintf(stderr, "Error reading file '%s'\n", path);
+ goto out_buffer;
+ }
+ } else
+ remaining -= size;
+ } while (remaining);
+
+ close(fd);
+ buffer[stat.st_size] = 0;
+
+ return buffer;
+
+out_buffer:
+ free(buffer);
+out_fd:
+ close(fd);
+out:
+ return NULL;
+}
+
+int parse_entry(const char *line, entry *e)
+{
+ char *pos;
+ unsigned long tmp;
+
+ while(isspace(*line))
+ line++;
+ if (*line == 0)
+ return -1;
+
+ tmp = strtoul(line, &pos, 0);
+ if ((tmp == ULONG_MAX && errno == ERANGE) || !pos)
+ {
+ fprintf(stderr, "Error: parsing entry '%s'\n", line);
+ return 0;
+ }
+ e->perm = tmp;
+
+ while(isspace(*pos))
+ pos++;
+ e->str = pos;
+
+ return 1;
+}
+
+int process_expr_line(const char *line)
+{
+ entry ent;
+ int res = parse_entry(line, &ent);
+ if (!res)
+ return 0;
+ else if (res == -1)
+ return 1;
+
+ if (!g_rules->add_rule(ent.str, 0, ent.perm, 0, 0)) {
+ fprintf(stderr, "Error failed to add rule '%s' to hfa\n",
+ ent.str);
+ return 0;
+ }
+
+ return 1;
+}
+
+int process_expr_file(const char *path)
+{
+ char *pos;
+ char *line;
+ char *buffer = load_file(path);
+ if (!buffer)
+ return 0;
+
+ pos = buffer;
+ for (line = strsep(&pos, g_sep); line; line = strsep(&pos, g_sep)) {
+ if (!process_expr_line(line))
+ return 0;
+ }
+
+ return 1;
+}
+
+int process_match_line(const char *line)
+{
+ entry ent;
+ int res = parse_entry(line, &ent);
+ if (!res)
+ return 0;
+ else if (res == -1)
+ return 1;
+
+ g_matches.push_back(ent);
+
+ return 1;
+}
+
+int process_match_file(const char *path)
+{
+ char *pos;
+ char *line;
+ char *buffer = load_file(path);
+ if (!buffer)
+ return 0;
+
+ pos = buffer;
+ for (line = strsep(&pos, g_sep); line; line = strsep(&pos, g_sep)) {
+ if (!process_match_line(line))
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/* return the number of failures */
+int do_matches(aa_hfa *hfa, unsigned int count)
+{
+ unsigned int failures = 0;
+ clock_t t = clock();
+
+ for (unsigned int i = 0; i < count; i++) {
+ for (std::list<entry>::iterator j = g_matches.begin(); j != g_matches.end(); j++) {
+ struct aa_state state;
+ aa_hfa_match(hfa, &state, j->str);
+ unsigned int accept = aa_hfa_accept(hfa, &state);
+ if (accept != j->perm) {
+ failures++;
+ }
+ }
+ }
+ t = clock() - t;
+ unsigned int secs = t/CLOCKS_PER_SEC;
+ if (g_print_time)
+ printf("elapsed time: %u.%3.3lds\n", secs, (((t % CLOCKS_PER_SEC)*1000+500)/CLOCKS_PER_SEC));
+
+ return failures;
+}
+
+int main(int argc, char **argv)
+{
+ struct direct_mapped_accept accept;
+ const char *err;
+
+ progname = argv[0];
+
+ if (argc < 3) {
+ usage();
+ return 1;
+ }
+
+ g_rules = new aare_rules(0);
+ if (!g_rules) {
+ fprintf(stderr, "Error failed to create ruleset\n");
+ exit(1);
+ }
+
+ optind = process_args(argc, argv);
+
+ for (int i = optind; i <= argc && argv[i]; i++) {
+ if (!process_match_line(argv[i]))
+ fprintf(stderr, "Error failed to process match arg '%s'\n", argv[i]);
+ }
+
+ if (!g_matches.size() && !g_out_file) {
+ fprintf(stderr, "Error at least one match string must be defined\n");
+ exit(1);
+ }
+
+ if (!g_rules->rule_count) {
+ fprintf(stderr, "Error at least one Expr pattern must be defined\n");
+ exit(1);
+ }
+ if (g_dump_info) {
+ fprintf(stderr, "Processed\n"
+ " %ld expr entries\n"
+ " %ld match entries\n",
+ (long) g_rules->rule_count, g_matches.size());
+ fprintf(stderr, "Creating HFA\n");
+ }
+ size_t size;
+ void *chfa = g_rules->create_dfa(&size, hfaflags);
+ if (!chfa) {
+ fprintf(stderr, "Error failed to compile hfa\n");
+ exit(1);
+ }
+ delete g_rules;
+
+ if (g_out_file) {
+ if (g_dump_info)
+ fprintf(stderr, "Writing HFA to '%s'\n", g_out_file);
+ FILE *f = fopen(g_out_file, "w");
+ if (!f) {
+ fprintf(stderr, "Error failed to dump hfa to '%s'\n", g_out_file);
+ exit(1);
+ }
+ fwrite(chfa, size, 1, f);
+ fclose(f);
+ }
+
+ if (g_dump_info)
+ fprintf(stderr, "Unpacking HFA\n");
+ struct aa_hfa *hfa = aa_hfa_unpack(chfa, size, &err, &accept);
+ if (!hfa) {
+ fprintf(stderr, "Error failed to unpack compressed hfa: %s\n", err);
+ exit(1);
+ }
+ free(chfa);
+
+ if (g_dump_info)
+ fprintf(stderr, "Starting matches\n");
+ if (g_matches.size()) {
+ int failures = do_matches(hfa, g_repeat_count);
+ if (failures) {
+ fprintf(stderr, "Error failed to match to expected perms %d times\n", failures);
+ exit(2);
+ }
+ }
+
+ aa_hfa_free(hfa);
+ return 0;
+}
diff --git a/libraries/libapparmor/src/Makefile.am b/libraries/libapparmor/src/Makefile.am
index deca53e..4cdae94 100644
--- a/libraries/libapparmor/src/Makefile.am
+++ b/libraries/libapparmor/src/Makefile.am
@@ -26,9 +26,9 @@ INCLUDES = $(all_includes)
# For more information, see:
# http://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html
#
-AA_LIB_CURRENT = 3
-AA_LIB_REVISION = 1
-AA_LIB_AGE = 2
+AA_LIB_CURRENT = 3 # TODO: increment
+AA_LIB_REVISION = 1 # TODO: set to 0
+AA_LIB_AGE = 2 # TODO: increment
SUFFIXES = .pc.in .pc
@@ -46,9 +46,10 @@ af_protos.h: /usr/include/netinet/in.h
LC_ALL=C sed -n -e "/IPPROTO_MAX/d" -e "s/^\#define[ \\t]\\+IPPROTO_\\([A-Z0-9_]\\+\\)\\(.*\\)$$/AA_GEN_PROTO_ENT(\\UIPPROTO_\\1, \"\\L\\1\")/p" $< > $@
lib_LTLIBRARIES = libapparmor.la
-noinst_HEADERS = grammar.h parser.h scanner.h af_protos.h private.h
+noinst_HEADERS = grammar.h parser.h scanner.h af_protos.h private.h hfa.h \
+ hfa_private.h
-libapparmor_la_SOURCES = grammar.y libaalogparse.c kernel.c scanner.c private.c features.c kernel_interface.c policy_cache.c
+libapparmor_la_SOURCES = grammar.y libaalogparse.c kernel.c scanner.c private.c features.c kernel_interface.c policy_cache.c hfa.c hfa_unpack.c hfa_print.c
libapparmor_la_LDFLAGS = -version-info $(AA_LIB_CURRENT):$(AA_LIB_REVISION):$(AA_LIB_AGE) -XCClinker -dynamic -pthread \
-Wl,--version-script=$(top_srcdir)/src/libapparmor.map
diff --git a/libraries/libapparmor/src/hfa.c b/libraries/libapparmor/src/hfa.c
new file mode 100644
index 0000000..ec31a15
--- /dev/null
+++ b/libraries/libapparmor/src/hfa.c
@@ -0,0 +1,304 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor eHFA based regular expression matching engine
+ *
+ * Copyright 2016 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * AppArmor's extended Hybrid Finite Atomata (eHFA) matching engine is
+ * essentially an NFA with additional DFA constraints, with some limited
+ * function callouts and scratch memory (it is not turing complete nor
+ * even a full PFA).
+ *
+ * It is not a true NFA as it does not allow for lambda transitions, nor
+ * does it allow for an arbitrary set of follow states for any given
+ * character transition. Instead it should be thought of as a DFA with
+ * limited NFA states that have constraints such that the number of
+ * potential NFA states to track in parallel is known in advanced and
+ * of a fixed number.
+ *
+ * Atm this code only implements the DFA portion of the match and does
+ * not allow for NFA states nor the extended work memory.
+ */
+
+#include <stdlib.h>
+
+#include "../include/sys/apparmor.h"
+#include "hfa.h"
+#include "hfa_private.h"
+
+
+/**
+ * aa_hfa_accept - return accept table information for @state in @hfa
+ * @hfa: the hfa to find accept information for
+ * @state: the state to get the accept information for
+ *
+ * Returns: the states accept entry (maybe 0)
+ */
+unsigned int aa_hfa_accept(struct aa_hfa *hfa, struct aa_state *state)
+{
+ if (state->state < hfa->nstates)
+ return hfa->hfa16.states.accept[state->state];
+ return 0;
+}
+
+#define match_C(state, def, base, next, check, C) \
+do { \
+ u32 b = (base)[(state)]; \
+ size_t pos = base_idx(b) + (C); \
+ if ((check)[pos] != (state)) { \
+ (state) = (def)[(state)]; \
+ if (b & MATCH_FLAG_DIFF_ENCODE) \
+ continue; \
+ break; \
+ } \
+ (state) = (next)[pos]; \
+ break; \
+} while (1)
+
+
+/* This version of match_C was 3.5-4% slower in quick testing
+#define match_C(state, def, base, next, check, C) \
+do { \
+ u32 b = (base)[(state)]; \
+ size_t pos = base_idx(b) + (C); \
+ if ((check)[pos] == (state)) { \
+ (state) = (next)[pos]; \
+ break; \
+ } \
+ (state) = (def)[(state)]; \
+ if (!(b & MATCH_FLAG_DIFF_ENCODE)) \
+ break; \
+} while (1)
+*/
+
+#define match_char(state, hfa, C) \
+ match_C(state, hfa->hfa16.states.def, hfa->hfa16.states.base, hfa->hfa16.trans.next, \
+ hfa->hfa16.trans.check, (u8) (C))
+
+#define match_EC_char(state, hfa, C) \
+ match_char(state, hfa, hfa->ec[(u8) (C)])
+
+
+/**
+ * aa_hfa_init_state - initialize state information
+ * @hfa: hfa to base initialization off of
+ * @state: state tracking struct to initialize
+ *
+ * Returns: 0 on success else error
+ */
+int aa_hfa_init_state(struct aa_hfa *hfa, struct aa_state *state)
+{
+ state->state = AA_HFA_START;
+
+ return 0;
+}
+
+/**
+ * aa_hfa_new_state - allocate a new state tracking structure
+ * @hfa: hfa to allocate state tracking structure for
+ *
+ * Returns: state tracking structure on success else NULL
+ */
+struct aa_state *aa_hfa_new_state(struct aa_hfa *hfa)
+{
+ struct aa_state *state = calloc(1, sizeof(struct aa_state));
+ if (!state)
+ return NULL;
+ if (!aa_hfa_init_state(hfa, state)) {
+ free(state);
+ return NULL;
+ }
+
+ return state;
+}
+
+/**
+ * aa_hfa_reset - reset a state tracking structure to start a new match
+ * @hfa: dfa to reset for
+ * @state: state to reset
+ *
+ * Returns: 0 on success else error
+ */
+int aa_hfa_reset(struct aa_hfa *hfa, struct aa_state *state)
+{
+ state->state = AA_HFA_START;
+
+ return 0;
+}
+
+/**
+ * aa_hfa_can_fail - evaluates whether @state could potentially fail for @hfa
+ * @hfa: hfa to consider
+ * @hfa: state struct to be paired with @hfa
+ *
+ * Returns: true if the combination can fail, else false
+ */
+bool aa_hfa_can_fail(struct aa_hfa *hfa, struct aa_state *state)
+{
+ return false;
+}
+
+/**
+ * aa_hfa_nomatch - returns true if in the non matching trap state
+ * @state: state to test if in trap state
+ *
+ * Returns: true if in trap state and will never successfully match
+ */
+bool aa_hfa_nomatch(struct aa_state *state)
+{
+ return state->state == AA_HFA_NOMATCH;
+}
+
+/**
+ * aa_hfa_matchn_cont - traverse @hfa from @state to find state @str stops at
+ * @hfa: the hfa to match @str against (NOT NULL)
+ * @state: the state of the hfa to start matching in
+ * @str: the string of bytes to match against the hfa (NOT NULL)
+ * @len: length of the string of bytes to match
+ *
+ * aa_hfa_matchn will match @str against the hfa and return the state it
+ * finished matching in. The final state can be used to look up the accepting
+ * label, or as the start state of a continuing match.
+ *
+ * This function will happily match again the 0 byte and only finishes
+ * when @len input is consumed.
+ *
+ * Returns: 0 on success else error.
+ *
+ * Note: most matches are guarenteed to succeed, see aa_hfa_reset, and
+ * aa_hfa_can_fail.
+ */
+int aa_hfa_continuen(struct aa_hfa *hfa, struct aa_state *state,
+ const char *str, size_t len)
+{
+ unsigned int s = state->state;
+
+ if (s == 0)
+ return 0;
+
+ /* current state is <state>, matching character *str */
+ if (hfa->ec) {
+ for (; len; len--)
+ match_EC_char(s, hfa, *str++);
+ } else {
+ for (; len; len--)
+ match_char(s, hfa, *str++);
+ }
+ state->state = s;
+
+ return 0;
+}
+
+/**
+ * aa_hfa_continue - traverse @hfa from @state to find state @str stops at
+ * @hfa: the hfa to match @str against (NOT NULL)
+ * @state: the state of the hfa to start matching in
+ * @str: the null terminated string of bytes to match against the hfa (NOT NULL)
+ *
+ * aa_hfa_match will match @str against the hfa and return the state it
+ * finished matching in. The final state can be used to look up the accepting
+ * label, or as the start state of a continuing match.
+ *
+ * Returns: 0 on success else error.
+ *
+ * Note: most matches are guarenteed to succeed, see aa_hfa_start, and
+ * aa_hfa_can_fail.
+ */
+int aa_hfa_continue(struct aa_hfa *hfa, struct aa_state *state, const char *str)
+{
+ unsigned int s = state->state;
+
+ if (s == 0)
+ return 0;
+
+ if (hfa->ec) {
+ while (*str)
+ match_EC_char(s, hfa, *str++);
+ } else {
+ while (*str)
+ match_char(s, hfa, *str++);
+ }
+ state->state = s;
+
+ return 0;
+}
+
+/**
+ * aa_hfa_matchn - reset and traverse @hfa to find state @str stops at
+ * @hfa: the hfa to match @str against (NOT NULL)
+ * @state: the state of the hfa to start matching in
+ * @str: the string of bytes to match against the hfa (NOT NULL)
+ * @len: length of the string of bytes to match
+ *
+ * aa_hfa_matchn will match @str against the hfa and return the state it
+ * finished matching in. The final state can be used to look up the accepting
+ * label, or as the start state of a continuing match.
+ *
+ * This function will happily match again the 0 byte and only finishes
+ * when @len input is consumed.
+ *
+ * Returns: 0 on success else error.
+ *
+ * Note: most matches are guarenteed to succeed, see aa_hfa_reset, and
+ * aa_hfa_can_fail.
+ */
+int aa_hfa_matchn(struct aa_hfa *hfa, struct aa_state *state, const char *str,
+ size_t len)
+{
+ int err = aa_hfa_reset(hfa, state);
+ if (err)
+ return err;
+ return aa_hfa_continuen(hfa, state, str, len);
+}
+
+/**
+ * aa_hfa_match - reset and traverse @hfa to find state @str stops at
+ * @hfa: the hfa to match @str against (NOT NULL)
+ * @state: the state of the hfa to start matching in
+ * @str: the null terminated string of bytes to match against the hfa (NOT NULL)
+ *
+ * aa_hfa_match will match @str against the hfa and return the state it
+ * finished matching in. The final state can be used to look up the accepting
+ * label, or as the start state of a continuing match.
+ *
+ * Returns: 0 on success else error.
+ *
+ * Note: most matches are guarenteed to succeed, see aa_hfa_start, and
+ * aa_hfa_can_fail.
+ */
+int aa_hfa_match(struct aa_hfa *hfa, struct aa_state *state, const char *str)
+{
+ int err = aa_hfa_reset(hfa, state);
+ if (err)
+ return err;
+ return aa_hfa_continue(hfa, state, str);
+}
+
+/**
+ * aa_hfa_next - step one character to the next state in the hfa
+ * @hfa: the hfa to tranverse (NOT NULL)
+ * @state: the state to start in
+ * @c: the input character to transition on
+ *
+ * aa_hfa_match will step through the hfa by one input character @c
+ *
+ * Returns: 0 on success else error.
+ *
+ * Note: most matches are guarenteed to succeed, see aa_hfa_start, and
+ * aa_hfa_can_fail.
+ */
+int aa_hfa_next(struct aa_hfa *hfa, struct aa_state *state, const char c)
+{
+ if (hfa->ec)
+ match_EC_char(state->state, hfa, c);
+ else
+ match_char(state->state, hfa, c);
+
+ return 0;
+}
diff --git a/libraries/libapparmor/src/hfa.h b/libraries/libapparmor/src/hfa.h
new file mode 100644
index 0000000..6c4002d
--- /dev/null
+++ b/libraries/libapparmor/src/hfa.h
@@ -0,0 +1,83 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor policy hfa matching engine definitions.
+ *
+ * Copyright 2009-2016 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_HFA_H
+#define __AA_HFA_H
+
+#include <ctype.h>
+#include <stdint.h>
+
+__BEGIN_DECLS
+
+#ifndef u16
+#define u16 uint16_t
+#endif
+#ifndef u32
+#define u32 uint32_t
+#endif
+#ifndef u64
+#define u64 uint64_t
+#endif
+
+#ifndef bool
+#define bool int
+#endif
+
+/* used for direct mapped accept tables, if present */
+struct accept64 {
+ union {
+ /* trick to treat value as 32 or 64 bit depending */
+ struct {
+ u32 accept1;
+ u32 accept2;
+ };
+ u64 accept;
+ };
+};
+
+struct direct_mapped_accept {
+ u32 size;
+ struct accept64 *table;
+};
+
+/* hfa matching routines */
+struct aa_hfa;
+struct aa_state;
+extern void aa_hfa_free(struct aa_hfa *hfa);
+extern struct aa_hfa *aa_hfa_unpack(void *blob, size_t size, const char **error,
+ struct direct_mapped_accept *accept);
+
+int aa_hfa_init_state(struct aa_hfa *hfa, struct aa_state *state);
+struct aa_state *aa_hfa_new_state(struct aa_hfa *hfa);
+int aa_hfa_reset(struct aa_hfa *hfa, struct aa_state *state);
+bool aa_hfa_can_fail(struct aa_hfa *hfa, struct aa_state *state);
+
+unsigned int aa_hfa_accept(struct aa_hfa *hfa, struct aa_state *state);
+bool aa_hfa_nomatch(struct aa_state *state);
+
+int aa_hfa_match(struct aa_hfa *hfa, struct aa_state *state, const char *str);
+int aa_hfa_matchn(struct aa_hfa *hfa, struct aa_state *state, const char *str,
+ size_t len);
+int aa_hfa_continue(struct aa_hfa *hfa, struct aa_state *state,
+ const char *str);
+int aa_hfa_continuen(struct aa_hfa *hfa, struct aa_state *state,
+ const char *str, size_t len);
+int aa_hfa_next(struct aa_hfa *hfa, struct aa_state *state, const char c);
+
+
+#include <stdio.h>
+int fprint_hfa(FILE *f, struct aa_hfa *hfa);
+
+__END_DECLS
+
+#endif /* __AA_HFA_H */
diff --git a/libraries/libapparmor/src/hfa_print.c b/libraries/libapparmor/src/hfa_print.c
new file mode 100644
index 0000000..bb297f5
--- /dev/null
+++ b/libraries/libapparmor/src/hfa_print.c
@@ -0,0 +1,209 @@
+/*
+ * AppArmor security module
+ *
+ * Copyright 2016 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <stdlib.h>
+
+#include "../include/sys/apparmor.h"
+#include "hfa.h"
+#include "hfa_private.h"
+
+
+#define return_err(FN) \
+({ \
+ int err; \
+ if ((err = (FN)) == -1) { \
+ return err; \
+ } \
+ err; \
+})
+
+static int fprint_c(FILE *f, u8 c)
+{
+ if (isprint(c))
+ return fprintf(f, "0x%02x (%c)", c, c);
+ else
+ return fprintf(f, "0x%02x ", c);
+}
+
+static int fprint_chr(FILE *f, u8 *equiv, u8 c)
+{
+/*
+ if (equiv) {
+ u8 b = equiv[c];
+ printf("eq[");
+ print_c(c);
+ printf("] == ");
+ print_c(b);
+ } else
+*/
+ return fprint_c(f, c);
+}
+
+static int fprint_trans(FILE *f, struct aa_hfa *hfa, unsigned int state,
+ int trans)
+{
+ u32 *base = hfa->hfa16.states.base;
+ u16 *next = hfa->hfa16.trans.next;
+ u8 *equiv = hfa->ec;
+ u32 b = (base)[(state)];
+ unsigned int pos = base_idx(b) + trans;
+ int size = 0;
+
+ size += return_err(fprintf(f, " "));
+ size += return_err(fprint_chr(f, equiv, trans));
+ size += return_err(fprintf(f, ": -> {%d}\n", next[pos]));
+
+ return size;
+}
+
+static int fprint_diff_trans(FILE *f, struct aa_hfa *hfa, unsigned int state,
+ unsigned int orig_default, int trans)
+{
+ u16 *def = hfa->hfa16.states.def;
+ u32 *base = hfa->hfa16.states.base;
+ u16 *next = hfa->hfa16.trans.next;
+ u16 *check = hfa->hfa16.trans.check;
+ int size = 0;
+
+ size += return_err(fprintf(f, " "));
+ size += return_err(fprint_chr(f, NULL, trans));
+ size += return_err(fprintf(f, ":"));
+ do {
+ u32 b = (base)[(state)];
+ unsigned int pos = base_idx(b) + (trans);
+ if ((check)[pos] != (state)) {
+ (state) = (def)[(state)];
+ size += return_err(fprintf(f, " -> {%d}", state));
+ if (b & MATCH_FLAG_DIFF_ENCODE)
+ continue;
+ break;
+ }
+ (state) = (next)[pos];
+ size += return_err(fprintf(f, " -> {%d}", state));
+ break;
+ } while (1);
+ size += return_err(fprintf(f, "\n"));
+
+ return size;
+}
+
+static int cmpuint(const void *s1, const void *s2)
+{
+ return *((unsigned int *) s1) - *((unsigned int *) s2);
+}
+
+/* find most frequent target - it will be used as the default */
+static unsigned int diff_default(struct aa_hfa *hfa, unsigned int state)
+{
+ unsigned int trans[256];
+ unsigned int candidate;
+ int count, high, i;
+
+ /* we want to reconstruct the non-diff-encoded default state */
+ for (i = 0; i < 256; i++) {
+ struct aa_state s = { .state = state };
+ aa_hfa_next(hfa, &s, i);
+ trans[i] = s.state;
+ }
+
+ qsort(trans, 256, sizeof(unsigned int), cmpuint);
+ candidate = trans[0];
+ count = high = 1;
+ for (i = 1; i < 256 ; i++) {
+ if (trans[i] != trans[i - 1]) {
+ if (count > high) {
+ candidate = trans[i - 1];
+ high = count;
+ }
+ count = 1;
+ } else
+ count++;
+ }
+ if (count > high)
+ candidate = trans[i - 1];
+
+ return candidate;
+}
+
+int fprint_state(FILE *f, struct aa_hfa *hfa, unsigned int state)
+{
+ u16 *def = hfa->hfa16.states.def;
+ u32 *base = hfa->hfa16.states.base;
+ u16 *next = hfa->hfa16.trans.next;
+ u16 *check = hfa->hfa16.trans.check;
+
+ u16 *accept = hfa->hfa16.states.accept;
+
+ int i, count = 0;
+ int size = 0;
+
+ unsigned int pos = base_idx(base[state]);
+ int flags = base_flags(base[state]);
+ unsigned int orig_default = def[state];
+
+ if (flags & MATCH_FLAG_DIFF_ENCODE)
+ orig_default = diff_default(hfa, state);
+ size += return_err(fprintf(f, " {%d} ", state));
+ size += return_err(fprintf(f, "flags: 0x%x, base: %d, default: %d",
+ flags, pos, def[state]));
+ if (flags & MATCH_FLAG_DIFF_ENCODE)
+ size += return_err(fprintf(f, " -> %d", orig_default));
+ size += return_err(fprintf(f, ", accept: %d", accept[state]));
+ if (state == AA_HFA_NOMATCH)
+ size += return_err(fprintf(f, " <no match>"));
+ if (state == AA_HFA_START)
+ size += return_err(fprintf(f, " <=="));
+ size += return_err(fprintf(f, "\n"));
+
+ for (i = 0; i < 256; i++) {
+ struct aa_state s = { .state = state };
+ aa_hfa_next(hfa, &s, i);
+ if (state == check[pos + i] &&
+ ((flags & MATCH_FLAG_DIFF_ENCODE) || s.state != orig_default)) {
+ size += return_err(fprint_trans(f, hfa, state, i));
+ count++;
+ } else if ((flags & MATCH_FLAG_DIFF_ENCODE) &&
+ s.state != orig_default) {
+ size += return_err(fprint_diff_trans(f, hfa, state,
+ orig_default, i));
+ count++;
+ }
+ }
+ if (count < 256) {
+ if ((flags & MATCH_FLAG_DIFF_ENCODE))
+ size += return_err(fprintf(f, " [] -> {%d} -> .. -> {%d}\n",
+ def[state], orig_default));
+ else
+ size += return_err(fprintf(f, " [] -> {%d}\n",
+ orig_default));
+ }
+
+ return size;
+}
+
+int fprint_hfa(FILE *f, struct aa_hfa *hfa)
+{
+ unsigned int state;
+ int size = 0;
+
+ size += return_err(fprintf(f, "HFA: flags: 0x%x", hfa->flags));
+ if (hfa->flags & YYTSH_FLAG_DIFF_ENCODE) {
+ size += return_err(fprintf(f, " (diff-encode)"));
+ }
+ size += return_err(fprintf(f, " states:%d next/check size: %d\n",
+ hfa->nstates, hfa->ntrans));
+
+ for (state = 0; state < hfa->nstates; state++) {
+ size += return_err(fprint_state(f, hfa, state));
+ }
+
+ return size;
+}
diff --git a/libraries/libapparmor/src/hfa_private.h b/libraries/libapparmor/src/hfa_private.h
new file mode 100644
index 0000000..620cfce
--- /dev/null
+++ b/libraries/libapparmor/src/hfa_private.h
@@ -0,0 +1,101 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor policy hfa matching engine definitions.
+ *
+ * Copyright 2016 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_HFA_PRIVATE_H
+#define __AA_HFA_PRIVATE_H
+
+#include <ctype.h>
+
+__BEGIN_DECLS
+
+#define u8 unsigned char
+#ifndef u16
+#define u16 uint16_t
+#endif
+#ifndef u32
+#define u32 uint32_t
+#endif
+#ifndef u64
+#define u64 uint64_t
+#endif
+
+#ifndef AA_HFA_NOMATCH
+#define AA_HFA_NOMATCH 0
+#define AA_HFA_START 1
+#endif
+
+#define YYTSH_FLAG_DIFF_ENCODE 1
+
+#define MARK_DIFF_ENCODE 0x40000000
+#define MATCH_FLAG_DIFF_ENCODE 0x80000000
+#define base_idx(X) ((X) & 0xffffff)
+#define base_flags(X) ((X) & 0xff000000)
+
+/* struct aa_state16 - Tables entries index by the state
+ * @base: table of index into the transition table for this state
+ * @def: table of state to default to if transition doesn't belong to this state
+ * @accept: index into accept table. 0 is none matching state
+ */
+struct aa_state16 {
+ u32 *base;
+ u16 *def;
+ u16 *accept;
+};
+
+/* struct aa_trans16 - Tables index by the state.base + character
+ * @next: the state to transition to if this state is owned by indexing state
+ * @check: the state that owns the @next transition
+ */
+struct aa_trans16 {
+ u16 *next;
+ u16 *check;
+};
+
+/* struct aa_hfa16 - Tables and state needed for the 16 bit hfa
+ * @states: table of states
+ * @trans: table of transitions
+ */
+struct aa_hfa16 {
+ struct aa_state16 states;
+ struct aa_trans16 trans;
+
+};
+
+/* struct aa_hfa - Tables and state needed for all hfa types
+ * @count: ref count
+ * @flags: flags for hfa behavior
+ * @nstates: # of entries in the @states table (and accept)
+ * @ntrans: # of entries in the @trans table
+ * @max_accept: highest value in accept table
+ * @ec: equivalence class table
+ */
+struct aa_hfa {
+ u16 flags;
+ u32 nstates;
+ u32 ntrans;
+ u32 max_accept;
+ u8 *ec;
+
+ struct aa_hfa16 hfa16;
+};
+
+/* struct aa_state - object to track position in a match
+ * @state: the state the match is in
+ */
+struct aa_state {
+ unsigned int state;
+};
+
+__END_DECLS
+
+#endif /* __AA_HFA_PRIVATE_H */
diff --git a/libraries/libapparmor/src/hfa_unpack.c b/libraries/libapparmor/src/hfa_unpack.c
new file mode 100644
index 0000000..c23f214
--- /dev/null
+++ b/libraries/libapparmor/src/hfa_unpack.c
@@ -0,0 +1,636 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains the unpack, remap to host, and verification routines
+ * for the compressed binary format of the AppArmor hfa based regular
+ * expression matching engine.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2016 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+
+/**
+ * Defines used to unpack, the eHFA tables to native format used by the
+ * matching engine.
+ *
+ * The format used for transition tables is loosely based on the GNU flex
+ * table file format (--tables-file option; see Table File Format in the flex
+ * info pages and the flex sources for documentation). The magic number
+ * used in the header is 0x1B5E783D instead of 0xF13C57B1 though, because
+ * new tables have been defined and others YY_ID_CHK (check) and YY_ID_DEF
+ * (default) tables are used slightly differently (see the apparmor hfa
+ * whitepaper).
+ *
+ * The data in the packed eHFA is stored in network byte order, and the tables
+ * are arranged for flexibility. We convert the table data to host native
+ * byte order.
+ *
+ * The stored eHFA begins with a table set header, and is followed by the
+ * actual tables.
+ *
+ * We unpack to local tables instead of remapping to a state struct and
+ * trans struct where all common components of the state or transition
+ * are grouped together, because of how the data is accessed during a
+ * walk.
+ *
+ * The base entry of state and check entry of transitions are always used
+ * but the default, accept, and next entries are only conditionally used
+ * based on check, and flags in base. Because of this, grouping default,
+ * and accept with base, and check with next, results in poorer performance
+ * as cache space is wasted on entries that aren't used.
+ *
+ * The exact performance hit depends on the eHFA, the input being matched
+ * and even the processor being tested on but in testing it ranged from
+ * 10-25% reduction in performance.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+#include <hfa.h>
+#include <hfa_private.h>
+
+#define AA_BUG(X, args...) AA_BUG_FMT((X), "" args )
+#define AA_BUG_FMT(X, fmt, args...) assert(!(X))
+
+#define ALIGN_MASK(addr, mask) (((addr) + (mask)) & ~(mask))
+#define ALIGN(addr, align) ALIGN_MASK((addr), (typeof(addr))(align) -1)
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+#define be16_to_cpu(X) ntohs(X)
+#define be32_to_cpu(X) ntohl(X)
+
+#define YYTSH_MAGIC 0x1B5E783D
+
+struct table_set_header {
+ u32 tsh_magic; /* YYTSH_MAGIC */
+ u32 tsh_hsize;
+ u32 tsh_ssize;
+ u16 tsh_flags;
+ char tsh_version[];
+} __attribute__((__packed__));
+
+/* The YYTD_ID are one less than flex table mappings. The id has 1 subtracted
+ * at table load time, this allows us to directly use the ID's as indexes.
+ */
+#define YYTD_ID_ACCEPT 0
+#define YYTD_ID_BASE 1
+#define YYTD_ID_CHK 2
+#define YYTD_ID_DEF 3
+#define YYTD_ID_EC 4
+#define YYTD_ID_META 5
+#define YYTD_ID_ACCEPT2 6
+#define YYTD_ID_NXT 7
+#define YYTD_ID_ACCEPT_IDX 8
+#define YYTD_ID_TSIZE 9
+#define YYTD_ID_MAX YYTD_ID_TSIZE
+
+#define YYTD_DATA8 1
+#define YYTD_DATA16 2
+#define YYTD_DATA32 4
+#define YYTD_DATA64 8
+
+/* ACCEPT & ACCEPT2 tables gets 6 dedicated flags, YYTD_DATAX define the
+ * first flags
+ */
+#define ACCEPT1_FLAGS(X) ((X) & 0x3f)
+#define ACCEPT2_FLAGS(X) ACCEPT1_FLAGS((X) >> YYTD_ID_ACCEPT2)
+#define TO_ACCEPT1_FLAG(X) ACCEPT1_FLAGS(X)
+#define TO_ACCEPT2_FLAG(X) (ACCEPT1_FLAGS(X) << YYTD_ID_ACCEPT2)
+#define HFA_FLAG_VERIFY_STATES 0x1000
+
+struct table_header {
+ u16 td_id;
+ u16 td_flags;
+ u32 td_reserved;
+ u32 td_size;
+ char td_data[];
+} __attribute__((__packed__));
+
+#define DEFAULT_TABLE(HFA) ((u16 *)((HFA)->tables[YYTD_ID_DEF]->td_data))
+#define BASE_TABLE(HFA) ((u32 *)((HFA)->tables[YYTD_ID_BASE]->td_data))
+#define NEXT_TABLE(HFA) ((u16 *)((HFA)->tables[YYTD_ID_NXT]->td_data))
+#define CHECK_TABLE(HFA) ((u16 *)((HFA)->tables[YYTD_ID_CHK]->td_data))
+#define EQUIV_TABLE(HFA) ((u8 *)((HFA)->tables[YYTD_ID_EC]->td_data))
+#define ACCEPT_TABLE(HFA) ((u32 *)((HFA)->tables[YYTD_ID_ACCEPT]->td_data))
+#define ACCEPT_TABLE2(HFA) ((u32 *)((HFA)->tables[YYTD_ID_ACCEPT2]->td_data))
+
+
+#define byte_to_byte(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)
+
+#define UNPACK_TO_STRUCT(TABLE, BLOB, LEN, TYPE, NTOHX, ELEMENT) \
+ do { \
+ typeof(LEN) __i; \
+ TYPE *__b = (TYPE *) BLOB; \
+ for (__i = 0; __i < LEN; __i++) { \
+ TABLE[__i].ELEMENT = NTOHX(__b[__i]); \
+ } \
+ } while (0)
+
+static size_t table_size(size_t len, size_t el_size)
+{
+ return ALIGN(sizeof(struct table_header) + len * el_size, 8);
+}
+
+/**
+ * unpack_table - unpack a hfa table (one of accept, default, base, next check)
+ * @data: data to unpack (NOT NULL)
+ * @bsize: size of data
+ *
+ * Returns: pointer to table else NULL on failure
+ *
+ */
+#include <stdio.h>
+static void *unpack_table(const struct table_header *th, u16 id)
+{
+ u8 *data = NULL;
+ size_t len;
+ u16 flags;
+
+ AA_BUG(id != be16_to_cpu(th->td_id) - 1);
+ len = be32_to_cpu(th->td_size);
+ flags = be16_to_cpu(th->td_flags);
+
+ data = calloc(1, table_size(len, flags));
+ if (data) {
+ if (flags == YYTD_DATA8)
+ UNPACK_ARRAY(data, th->td_data, len, u8, byte_to_byte);
+ else if (flags == YYTD_DATA16)
+ UNPACK_ARRAY(data, th->td_data, len, u16, be16_to_cpu);
+ else if (flags == YYTD_DATA32)
+ UNPACK_ARRAY(data, th->td_data, len, u32, be32_to_cpu);
+ else {
+ errno = EINVAL;
+ free(data);
+ return NULL;
+ }
+ }
+
+ return data;
+}
+
+/**
+ * aa_hfa_free - free a hfa allocated by aa_hfa_unpack
+ * @hfa: the hfa to free (MAYBE NULL)
+ *
+ * Requires: reference count to hfa == 0
+ */
+void aa_hfa_free(struct aa_hfa *hfa)
+{
+ if (hfa) {
+ free(hfa->ec);
+ free(hfa->hfa16.states.base);
+ free(hfa->hfa16.states.def);
+ free(hfa->hfa16.states.accept);
+ free(hfa->hfa16.trans.next);
+ free(hfa->hfa16.trans.check);
+ free(hfa);
+ }
+}
+
+static struct aa_hfa *alloc_hfa(u16 flags, u32 nstates, u32 ntrans)
+{
+ struct aa_hfa *hfa;
+
+ hfa = calloc(1, sizeof(struct aa_hfa));
+ if (!hfa)
+ return NULL;
+
+ hfa->flags = flags;
+ hfa->nstates = nstates;
+ hfa->ntrans = ntrans;
+
+ return hfa;
+}
+
+static const char *find_tables(unsigned char *data, size_t size,
+ struct table_header **tables)
+{
+ while (size > 0) {
+ struct table_header *th;
+ size_t tsize;
+ u16 id, flags;
+
+ if (size < sizeof(struct table_header))
+ return "HFA bad table header size";
+
+ th = (struct table_header *) data;
+ id = be16_to_cpu(th->td_id) - 1;
+ tsize = be32_to_cpu(th->td_size);
+ flags = be16_to_cpu(th->td_flags);
+ if (id > YYTD_ID_MAX)
+ return "HFA table bad id";
+
+ if (tables[id])
+ return "HFA table duplicate entry";
+
+ tables[id] = th;
+
+ if (!(flags == YYTD_DATA32 ||
+ flags == YYTD_DATA16 ||
+ flags == YYTD_DATA8))
+ return "HFA table invalid data size";
+
+ tsize = table_size(tsize, flags);
+ if (size < tsize)
+ return "HFA table bad size";
+
+ data += tsize;
+ size -= tsize;
+ }
+
+ return NULL;
+}
+
+static const char *basic_table_checks(struct table_header **tables)
+{
+ u32 nstates, ntrans;
+
+ /* check that required tables exist */
+ if (!tables[YYTD_ID_DEF])
+ return "HFA missing \'Default\' table";
+ if (!tables[YYTD_ID_BASE])
+ return "HFA missing \'Base\' table";
+ if (!tables[YYTD_ID_NXT])
+ return "HFA missing \'Next\' table";
+ if (!tables[YYTD_ID_CHK])
+ return "HFA missing \'Check\' table";
+
+ /* accept.size == def.size == base.size
+ * -direct comparison of values in table does not need endian conversion
+ */
+ nstates = tables[YYTD_ID_BASE]->td_size;
+ if (nstates != tables[YYTD_ID_DEF]->td_size)
+ return "HFA bad table size default != number of states";
+
+ if (tables[YYTD_ID_ACCEPT_IDX]) {
+ if (tables[YYTD_ID_ACCEPT] || tables[YYTD_ID_ACCEPT2])
+ return "HFA both \'accept index\' and \'accept table\'"
+ " present";
+ if (nstates != tables[YYTD_ID_ACCEPT_IDX]->td_size)
+ return "HFA bad table size \'accept index\' != number "
+ "of states";
+ } else {
+ if (!tables[YYTD_ID_ACCEPT])
+ return "HFA \'accept\' table missing";
+ if (!tables[YYTD_ID_ACCEPT2])
+ return "HFA \'accept2\' table missing";
+
+ if (nstates != tables[YYTD_ID_ACCEPT]->td_size)
+ return "HFA bad table size \'accept\' != number of "
+ "states";
+ if (nstates != tables[YYTD_ID_ACCEPT2]->td_size)
+ return "HFA bad table size \'accept2\' != number of "
+ "states";
+ }
+
+ ntrans = tables[YYTD_ID_NXT]->td_size;
+ if (ntrans != tables[YYTD_ID_CHK]->td_size)
+ return "HFA bad table size \'next\' != \'check\'";
+ if (tables[YYTD_ID_EC] &&
+ be32_to_cpu(tables[YYTD_ID_EC]->td_size) != 256)
+ return "HFA bad size for \'EC\' table";
+
+ if (be16_to_cpu(tables[YYTD_ID_BASE]->td_flags) != YYTD_DATA32)
+ return "HFA bad data type for \'Base\' table";
+ if (be16_to_cpu(tables[YYTD_ID_DEF]->td_flags) != YYTD_DATA16)
+ return "HFA bad data type for \'Default\' table";
+ if (be16_to_cpu(tables[YYTD_ID_NXT]->td_flags) != YYTD_DATA16)
+ return "HFA bad data type for \'Next\' table";
+ if (be16_to_cpu(tables[YYTD_ID_CHK]->td_flags) != YYTD_DATA16)
+ return "HFA bad data type for \'Check\' table";
+ if (tables[YYTD_ID_EC] &&
+ be16_to_cpu(tables[YYTD_ID_EC]->td_flags) != YYTD_DATA8)
+ return "HFA bad data type for \'EC\' table";
+
+ if (tables[YYTD_ID_ACCEPT_IDX] &&
+ be16_to_cpu(tables[YYTD_ID_ACCEPT_IDX]->td_flags) != YYTD_DATA16)
+ return "HFA bad data type for \'accept index\'";
+ if (tables[YYTD_ID_ACCEPT] &&
+ be16_to_cpu(tables[YYTD_ID_ACCEPT]->td_flags) != YYTD_DATA32)
+ return "HFA bad data type for \'accept\' table";
+ if (tables[YYTD_ID_ACCEPT2] &&
+ be16_to_cpu(tables[YYTD_ID_ACCEPT2]->td_flags) != YYTD_DATA32)
+ return "HFA bad data type for \'accept2\' table";
+
+ return NULL;
+}
+
+/**
+ * verify_hfa - verify that transitions and states in the tables are in bounds.
+ * @hfa: hfa to test (NOT NULL)
+ *
+ * Assumes hfa has gone through the first pass verification done by unpacking
+ * NOTE: this does not validate accept table values
+ *
+ * Returns: NULL else error message
+ */
+static const char *verify_hfa(struct aa_hfa *hfa)
+{
+ size_t i;
+
+ for (i = 0; i < hfa->nstates; i++) {
+ if (!(hfa->hfa16.states.base[i] & MATCH_FLAG_DIFF_ENCODE) &&
+ hfa->hfa16.states.def[i] >= hfa->nstates)
+ return "HFA \'default\' entry out of bounds";
+ if (base_idx(hfa->hfa16.states.base[i]) + 255 >= hfa->ntrans)
+ return "HFA \'base\' entry out of bounds";
+ /* Note: accept index is bound by external tables and
+ * must be checked externally
+ */
+ }
+
+ for (i = 0; i < hfa->ntrans; i++) {
+ if (hfa->hfa16.trans.next[i] >= hfa->nstates)
+ return "HFA \'next\' entry out of bounds";
+ if (hfa->hfa16.trans.check[i] >= hfa->nstates)
+ return "HFA \'check\' entry out of bounds";
+ }
+
+ if (hfa->ec && hfa->nstates < 255) {
+ for (i = 0; i < 256; i++) {
+ if (hfa->ec[i] >= hfa->nstates)
+ return "HFA \'ec\' entry out of bounds";
+ }
+ }
+
+ /* Now that all the other tables are verified, verify diffencoding */
+ for (i = 0; i < hfa->nstates; i++) {
+ size_t j, k;
+ for (j = i;
+ (hfa->hfa16.states.base[j] & MATCH_FLAG_DIFF_ENCODE) &&
+ !(hfa->hfa16.states.base[j] & MARK_DIFF_ENCODE);
+ j = k) {
+ k = hfa->hfa16.states.def[j];
+ if (k == i)
+ return "HFA diff encode has reference cycle";
+ if (j == k)
+ return "HFA diff encoded state is self "
+ "referential";
+ if (k < i)
+ break; /* already verified */
+ hfa->hfa16.states.base[j] |= MARK_DIFF_ENCODE;
+ }
+ }
+
+ return NULL;
+}
+
+static int cmp_idx(const void *p1, const void *p2, void *arg)
+{
+ const u16 *i1 = p1, *i2 = p2;
+ struct accept64 *table = arg;
+ if (table[*i1].accept < table[*i2].accept)
+ return -1;
+ if (table[*i1].accept == table[*i2].accept)
+ return 0;
+ return 1;
+}
+
+/**
+ * remap_accept_to_idx - remap direct mapped accept to indexed accept
+ * @nstates: number of states
+ * @accept1: accept1 table
+ * @accept2: accept2 table
+ * @accept: remapped accept table with single entry for each unique entry
+ * @idx: per state accept index into @accept64
+ *
+ * Returns: number of unique accept entries. 0 on failure
+ */
+static u32 remap_accept_to_idx(u32 nstates, char *accept1, char *accept2,
+ struct accept64 **accept, u16 **idx)
+{
+ struct accept64 *tmp_accept = NULL;
+ u16 *states = NULL;
+ u32 prev, uniq, i, j;
+
+ *accept = NULL;
+ *idx = NULL;
+
+ if (!(tmp_accept = calloc(nstates, sizeof(struct accept64))))
+ goto fail;
+ if (!(states = calloc(nstates, sizeof(u16))))
+ goto fail;
+ if (!(*idx = calloc(nstates, sizeof(u16))))
+ goto fail;
+
+ /* already verified to DATA32 in basic_table_checks() */
+ UNPACK_TO_STRUCT(tmp_accept, accept1, nstates, u32, be32_to_cpu,
+ accept1);
+ UNPACK_TO_STRUCT(tmp_accept, accept2, nstates, u32, be32_to_cpu,
+ accept2);
+ /* set up an state table to sort and do merge based off of */
+ for (i = 0; i < nstates; i++)
+ states[i] = i;
+ qsort_r(states, nstates, sizeof(u16), cmp_idx, tmp_accept);
+ prev = 0;
+ for (uniq = i = 1; i < nstates; i++) {
+ if (tmp_accept[states[prev]].accept !=
+ tmp_accept[states[i]].accept) {
+ prev = i;
+ uniq++;
+ }
+ }
+ *accept = calloc(uniq, sizeof(struct accept64));
+ if (!*accept)
+ goto fail;
+ /* remap tmp_accept to a table with a single entry per unique entry
+ * map idx so each states idx is to the unique entry in remapped accept
+ */
+ j = prev = 0;
+ (*accept)[j] = tmp_accept[states[0]];
+ for (i = 1; i < nstates; i++) {
+ if (tmp_accept[states[prev]].accept !=
+ tmp_accept[states[i]].accept) {
+ prev = i;
+ (*accept)[++j] = tmp_accept[states[i]];
+ }
+ (*idx)[states[i]] = j;
+ }
+ AA_BUG(j + 1 != uniq);
+
+ /* verify accept[0] maps to null permissions */
+ if ((*idx)[AA_HFA_NOMATCH] != 0 || (*accept)[0].accept != 0L ) {
+ errno = EINVAL;
+ goto fail;
+ }
+ free(tmp_accept);
+ free(states);
+
+ return uniq;
+
+fail:
+ free(tmp_accept);
+ free(states);
+ free(*accept);
+ free(*idx);
+ *accept = NULL;
+ *idx = NULL;
+
+ return 0;
+}
+
+/* TODO: wrapper around this that doesn't allow for direct_mapped_accept
+ * hfa - work area, param and allocation
+ * aa_hfa_state(struct aa_hfa *) - create a state/work area for a given hfa
+ */
+
+/**
+ * aa_hfa_unpack - unpack the binary tables of a serialized hfa
+ * @blob: aligned serialized stream of data to unpack (NOT NULL)
+ * @size: size of data to unpack
+ * @error: Returns constant string describing error (MAY BE NULL)
+ * @accept: If preset allows direct mapped accept (MAY BE NULL)
+ *
+ * Unpack a hfa that has been serialized. To find information on the hfa
+ * format look in Documentation/security/apparmor.txt
+ * Assumes the hfa @blob stream has been aligned on a 8 byte boundary
+ *
+ * If accept is passed, hfas containing direct mapped accept tables
+ * will be allowed, and remapped to an accept_idx. The remapped accept
+ * tables and their remapped length will be returned in the accept
+ * struct. It is up to the caller to free them separately from the
+ * hfa. If the hfa does NOT contain direct mapped accept tables then
+ * the struct will be zeroed.
+ *
+ * Returns: an unpacked hfa ready for matching or NULL + errno on failure
+ */
+struct aa_hfa *aa_hfa_unpack(void *blob, size_t size, const char **error,
+ struct direct_mapped_accept *accept)
+{
+ const char *err_str = NULL;
+ unsigned char *data = blob;
+ struct table_set_header *tsh = blob;
+ struct table_header *tables[YYTD_ID_MAX];
+ u16 flags;
+ int hsize;
+ struct aa_hfa *hfa;
+
+ errno = EINVAL;
+
+ /* get hfa table set header */
+ if (size < sizeof(struct table_set_header)) {
+ err_str = "data size smaller than table set header";
+ goto fail;
+ }
+
+ if (ntohl(tsh->tsh_magic) != YYTSH_MAGIC) {
+ err_str = "bad magic number";
+ goto fail;
+ }
+
+ hsize = ntohl(tsh->tsh_hsize);
+ if (size < hsize) {
+ err_str = "data smaller than specified in header";
+ goto fail;
+ }
+
+ flags = ntohs(tsh->tsh_flags);
+ if (flags != 0 && flags != YYTSH_FLAG_DIFF_ENCODE) {
+ err_str = "invalid table set flag";
+ goto fail;
+ }
+
+ data += hsize;
+ size -= hsize;
+
+ memset(tables, 0, sizeof(tables));
+ err_str = find_tables(data, size, tables);
+ if (err_str)
+ goto fail;
+
+ err_str = basic_table_checks(tables);
+ if (err_str)
+ goto fail;
+
+ errno = ENOMEM;
+ /* remap tables to internal format */
+ hfa = alloc_hfa(flags, be32_to_cpu(tables[YYTD_ID_BASE]->td_size),
+ be32_to_cpu(tables[YYTD_ID_NXT]->td_size));
+ if (!hfa)
+ goto fail;
+
+ if (!(hfa->hfa16.states.base = unpack_table(tables[YYTD_ID_BASE], YYTD_ID_BASE))) {
+ if (errno == EINVAL)
+ err_str = "invalid 'base' table data type";
+ goto fail;
+ }
+ if (!(hfa->hfa16.states.def = unpack_table(tables[YYTD_ID_DEF], YYTD_ID_DEF))) {
+ if (errno == EINVAL)
+ err_str = "invalid 'default' table data type";
+ goto fail;
+ }
+ if (!(hfa->hfa16.trans.next = unpack_table(tables[YYTD_ID_NXT], YYTD_ID_NXT))) {
+ if (errno == EINVAL)
+ err_str = "invalid 'next' table data type";
+ goto fail;
+ }
+ if (!(hfa->hfa16.trans.check = unpack_table(tables[YYTD_ID_CHK], YYTD_ID_CHK))) {
+ if (errno == EINVAL)
+ err_str = "invalid 'check' table data type";
+ goto fail;
+ }
+ if (tables[YYTD_ID_EC] && !(hfa->ec = unpack_table(tables[YYTD_ID_EC], YYTD_ID_EC))) {
+ if (errno == EINVAL)
+ err_str = "invalid 'ec' table data type";
+ goto fail;
+ }
+ if (tables[YYTD_ID_ACCEPT_IDX]) {
+ u32 i;
+ hfa->hfa16.states.accept = unpack_table(tables[YYTD_ID_ACCEPT_IDX], YYTD_ID_ACCEPT_IDX);
+ if (!hfa->hfa16.states.accept) {
+ if (errno == EINVAL)
+ err_str = "invalid 'accept index' table data type";
+ goto fail;
+ }
+ hfa->max_accept = 0;
+ for (i = 1; i < hfa->nstates; i++) {
+ if (hfa->max_accept < hfa->hfa16.states.accept[i])
+ hfa->max_accept = hfa->hfa16.states.accept[i];
+ }
+ } else { /* basic_table_checks() ensures idx or direct mapped exist */
+ hfa->max_accept = remap_accept_to_idx(hfa->nstates,
+ tables[YYTD_ID_ACCEPT]->td_data,
+ tables[YYTD_ID_ACCEPT2]->td_data,
+ &accept->table,
+ &hfa->hfa16.states.accept);
+ accept->size = hfa->max_accept;
+ if (!hfa->max_accept)
+ goto fail;
+ }
+
+ err_str = verify_hfa(hfa);
+ if (err_str)
+ goto fail;
+
+ return hfa;
+
+fail:
+ if (error) {
+ if (errno == ENOMEM)
+ *error = "out of memory";
+ else
+ *error = err_str;
+ }
+
+ return NULL;
+}
diff --git a/libraries/libapparmor/src/libapparmor.map b/libraries/libapparmor/src/libapparmor.map
index 98d97ea..cbd030f 100644
--- a/libraries/libapparmor/src/libapparmor.map
+++ b/libraries/libapparmor/src/libapparmor.map
@@ -94,6 +94,13 @@ PRIVATE {
_aa_autoclose;
_aa_autofclose;
_aa_dirat_for_each;
+ aa_hfa_free;
+ aa_hfa_unpack;
+ aa_hfa_match_len;
+ aa_hfa_match;
+ aa_hfa_next;
+ aa_hfa_accept;
+ fprint_hfa;
local:
*;
};
diff --git a/libraries/libapparmor/swig/SWIG/libapparmor.i b/libraries/libapparmor/swig/SWIG/libapparmor.i
index 69b4cc2..47213a1 100644
--- a/libraries/libapparmor/swig/SWIG/libapparmor.i
+++ b/libraries/libapparmor/swig/SWIG/libapparmor.i
@@ -68,5 +68,14 @@ extern int aa_query_link_path_len(const char *label, size_t label_len,
int *allowed, int *audited);
extern int aa_query_link_path(const char *label, const char *target,
const char *link, int *allowed, int *audited);
+extern void aa_dfa_free(struct aa_dfa *dfa);
+extern struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags);
+extern unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start,
+ const char *str, int len);
+extern unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start,
+ const char *str);
+extern unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state,
+ const char c);
+extern unsigned int aa_dfa_accept(struct aa_dfa *dfa, unsigned int state);
%exception;
diff --git a/parser/libapparmor_re/Makefile b/parser/libapparmor_re/Makefile
index bb22b5a..2718084 100644
--- a/parser/libapparmor_re/Makefile
+++ b/parser/libapparmor_re/Makefile
@@ -10,8 +10,8 @@ endif
TARGET=libapparmor_re.a
-CFLAGS ?= -g -Wall -O2 ${EXTRA_CFLAGS} -std=gnu++0x
-CXXFLAGS := ${CFLAGS} ${INCLUDE_APPARMOR}
+CFLAGS ?= -g -Wall -O2 ${EXTRA_CFLAGS} ${INCLUDE_APPARMOR} -std=gnu++0x
+CXXFLAGS := ${CFLAGS}
ARFLAGS=-rcs
diff --git a/parser/libapparmor_re/aare_rules.h b/parser/libapparmor_re/aare_rules.h
index 87b79f5..f7f10fc 100644
--- a/parser/libapparmor_re/aare_rules.h
+++ b/parser/libapparmor_re/aare_rules.h
@@ -22,6 +22,7 @@
#define __LIBAA_RE_RULES_H
#include <stdint.h>
+#include <stdio.h>
#include "apparmor_re.h"
#include "expr-tree.h"
--
2.7.0.rc3
More information about the AppArmor
mailing list