[apparmor] patch: override AF_MAX for kernels that don't support proper masking

John Johansen john.johansen at canonical.com
Thu Mar 3 21:42:13 UTC 2011


Older versions of the apparmor kernel patches didn't handle receiving
network tables of a larger size than expected.

Allow the parser to detect the kernel version and override the AF_MAX
value for those kernels.

This also replaces the hack using a hardcoded limit of 36 for kernels
missing the features flag.

---

=== modified file 'parser/parser.h'
--- parser/parser.h	2010-12-20 20:29:10 +0000
+++ parser/parser.h	2011-03-03 21:22:44 +0000
@@ -179,6 +179,7 @@
 #define FLAG_CHANGEHAT_1_4  2
 #define FLAG_CHANGEHAT_1_5  3
 extern int kernel_supports_network;
+extern int net_af_max_override;
 extern int flag_changehat_version;
 extern int read_implies_exec;
 extern dfaflags_t dfaflags;

=== modified file 'parser/parser_main.c'
--- parser/parser_main.c	2011-02-22 22:58:49 +0000
+++ parser/parser_main.c	2011-03-03 18:57:18 +0000
@@ -90,6 +90,7 @@
 int regex_type = AARE_DFA;
 int perms_create = 0;		/* perms contain create flag */
 int kernel_supports_network = 1;	/* kernel supports network rules */
+int net_af_max_override = -1;		/* use kernel to determine af_max */
 char *profile_namespace = NULL;
 int flag_changehat_version = FLAG_CHANGEHAT_1_5;
 FILE *ofile = NULL;

=== modified file 'parser/parser_misc.c'
--- parser/parser_misc.c	2010-12-20 20:29:10 +0000
+++ parser/parser_misc.c	2011-03-03 21:38:34 +0000
@@ -29,6 +29,10 @@
 #include <linux/limits.h>
 #include <arpa/inet.h>
 #include <linux/capability.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
 
 #include "parser.h"
 #include "parser_yacc.h"
@@ -203,6 +207,68 @@
 	{NULL, 0, NULL, 0, NULL, 0}
 };
 
+/* The apparmor kernel patches up until 2.6.38 didn't handle networking
+ * tables with sizes > AF_MAX correctly.  This could happen when the
+ * parser was built against newer kernel headers and then used to load
+ * policy on an older kernel.  This could happen during upgrades or
+ * in multi-kernel boot systems.
+ *
+ * Try to detect the running kernel version and use that to determine
+ * AF_MAX
+ */
+#define PROC_VERSION "/proc/sys/kernel/osrelease"
+static size_t kernel_af_max(void) {
+	char buffer[32];
+	int major;
+	int fd, res;
+
+	if (!net_af_max_override) {
+		return 0;
+	}
+	/* the override parameter is specifying the max value */
+	if (net_af_max_override > 0)
+		return net_af_max_override;
+
+	fd = open(PROC_VERSION, O_RDONLY);
+	if (!fd)
+		/* fall back to default provided during build */
+		return 0;
+	res = read(fd, &buffer, sizeof(buffer));
+	close(fd);
+	if (!res)
+		return 0;
+	res = sscanf(buffer, "2.6.%d", &major);
+	if (res != 1)
+		return 0;
+
+	switch(major) {
+	case 24:
+	case 25:
+	case 26:
+		return 34;
+	case 27:
+		return 35;
+	case 28:
+	case 29:
+	case 30:
+		return 36;
+	case 31:
+	case 32:
+	case 33:
+	case 34:
+	case 35:
+		return 37;
+	case 36:
+	case 37:
+		return 38;
+	/* kernels .38 and later should handle this correctly so no
+	 * static mapping needed
+	 */
+	default:
+		return 0;
+	}
+}
+
 /* Yuck. We grab AF_* values to define above from linux/socket.h because
  * they are more accurate than sys/socket.h for what the kernel actually
  * supports. However, we can't just include linux/socket.h directly,
@@ -213,13 +279,29 @@
  * hence the wrapping function.
  */
 size_t get_af_max() {
+	size_t af_max;
 	/* HACK: declare that version without "create" had a static AF_MAX */
-	if (!perms_create) return 36;
+	if (!perms_create && !net_af_max_override)
+		net_af_max_override = -1;
+
 #if AA_AF_MAX > AF_MAX
-	return AA_AF_MAX;
+	af_max = AA_AF_MAX;
 #else
-	return AF_MAX;
+	af_max = AF_MAX;
 #endif
+
+	/* HACK: some kernels didn't handle network tables from parsers
+	 * compiled against newer kernel headers as they are larger than
+	 * the running kernel expected.  If net_override is defined check
+	 * to see if there is a static max specified for that kernel
+	 */
+	if (net_af_max_override) {
+		size_t max = kernel_af_max();
+		if (max && max < af_max)
+			return max;
+	}
+
+	return af_max;
 }
 struct aa_network_entry *new_network_ent(unsigned int family,
 					 unsigned int type,




More information about the AppArmor mailing list