[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