mirror of
https://gitlab.com/apparmor/apparmor.git
synced 2025-03-04 08:24:42 +01:00
dfa module, d_path fixes, chroot hook, path cache
This commit is contained in:
parent
2395fa7d35
commit
d84a0cb8ae
10 changed files with 1624 additions and 0 deletions
39
kernel-patches/for-mainline/apparmor-d_path_flags.diff
Normal file
39
kernel-patches/for-mainline/apparmor-d_path_flags.diff
Normal file
|
@ -0,0 +1,39 @@
|
|||
Index: linux-2.6.19.1/security/apparmor/main.c
|
||||
===================================================================
|
||||
--- linux-2.6.19.1.orig/security/apparmor/main.c
|
||||
+++ linux-2.6.19.1/security/apparmor/main.c
|
||||
@@ -804,6 +804,7 @@ char *aa_get_name(struct dentry *dentry,
|
||||
{
|
||||
char *buffer, *name;
|
||||
int order = 0;
|
||||
+ unsigned int pconds;
|
||||
|
||||
*addr = NULL;
|
||||
buffer = (char *)aa_get_path(GFP_KERNEL);
|
||||
@@ -813,7 +814,8 @@ char *aa_get_name(struct dentry *dentry,
|
||||
goto out;
|
||||
}
|
||||
|
||||
- name = d_path(dentry, mnt, buffer, PAGE_SIZE << order);
|
||||
+ name = d_path_flags(dentry, mnt, buffer, PAGE_SIZE << order,
|
||||
+ DPATH_NSROOT, &pconds);
|
||||
/* check for (deleted) that d_path appends to pathnames if the dentry
|
||||
* has been removed from the cache.
|
||||
* The size > deleted_size and strcmp checks are redundant safe guards.
|
||||
@@ -826,16 +828,6 @@ char *aa_get_name(struct dentry *dentry,
|
||||
order++;
|
||||
buffer = kmalloc(PAGE_SIZE << order, GFP_KERNEL);
|
||||
goto retry;
|
||||
- } else {
|
||||
- const char deleted_str[] = " (deleted)";
|
||||
- const size_t deleted_size = sizeof(deleted_str) - 1;
|
||||
- size_t size;
|
||||
- size = strlen(name);
|
||||
- if (!IS_ROOT(dentry) && d_unhashed(dentry) &&
|
||||
- size > deleted_size &&
|
||||
- strcmp(name + size - deleted_size, deleted_str) == 0)
|
||||
- name[size - deleted_size] = '\0';
|
||||
- AA_DEBUG("%s: full_path=%s\n", __FUNCTION__, name);
|
||||
}
|
||||
|
||||
out:
|
505
kernel-patches/for-mainline/apparmor-dfa.diff
Normal file
505
kernel-patches/for-mainline/apparmor-dfa.diff
Normal file
|
@ -0,0 +1,505 @@
|
|||
Index: linux-2.6.19.1/security/apparmor/match/Kbuild
|
||||
===================================================================
|
||||
--- linux-2.6.19.1.orig/security/apparmor/match/Kbuild
|
||||
+++ linux-2.6.19.1/security/apparmor/match/Kbuild
|
||||
@@ -1,6 +1,6 @@
|
||||
# Makefile for AppArmor aamatch submodule
|
||||
#
|
||||
|
||||
-obj-$(CONFIG_SECURITY_APPARMOR) += aamatch_pcre.o
|
||||
+obj-$(CONFIG_SECURITY_APPARMOR) += aamatch_dfa.o
|
||||
|
||||
-aamatch_pcre-y := match_pcre.o pcre_exec.o
|
||||
+aamatch_dfa-y := match_dfa.o
|
||||
Index: linux-2.6.19.1/security/apparmor/match/match_dfa.c
|
||||
===================================================================
|
||||
--- /dev/null
|
||||
+++ linux-2.6.19.1/security/apparmor/match/match_dfa.c
|
||||
@@ -0,0 +1,398 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2002-2005 Novell/SUSE
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation, version 2 of the
|
||||
+ * License.
|
||||
+ *
|
||||
+ * http://forge.novell.com/modules/xfmod/project/?apparmor
|
||||
+ *
|
||||
+ * AppArmor aamatch submodule (w/ pattern expansion).
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#include <asm/unaligned.h>
|
||||
+#include <linux/module.h>
|
||||
+#include "match.h"
|
||||
+
|
||||
+static const char *features="literal tailglob pattern=aadfa";
|
||||
+
|
||||
+#define YYTH_MAGIC 0x1B5E783D
|
||||
+
|
||||
+struct table_set_header {
|
||||
+ u32 th_magic; /* TH_MAGIC */
|
||||
+ u32 th_hsize;
|
||||
+ u32 th_ssize;
|
||||
+ u16 th_flags;
|
||||
+ char th_version[];
|
||||
+};
|
||||
+
|
||||
+#define YYTD_ID_ACCEPT 1 /* 1 */
|
||||
+#define YYTD_ID_BASE 2 /* 2 */
|
||||
+#define YYTD_ID_CHK 3 /* 3 */
|
||||
+#define YYTD_ID_DEF 4 /* 4 */
|
||||
+#define YYTD_ID_EC 5 /* 5 */
|
||||
+#define YYTD_ID_NXT 6 /* 8 */
|
||||
+#define YYTD_ID_META 7 /* 6 */
|
||||
+
|
||||
+#define YYTD_DATA8 1
|
||||
+#define YYTD_DATA16 2
|
||||
+#define YYTD_DATA32 4
|
||||
+
|
||||
+struct table_header {
|
||||
+ u16 td_id;
|
||||
+ u16 td_flags;
|
||||
+ u32 td_hilen;
|
||||
+ u32 td_lolen;
|
||||
+ char td_data[];
|
||||
+};
|
||||
+
|
||||
+#define DEFAULT_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_DEF - 1]->td_data))
|
||||
+#define BASE_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_BASE - 1]->td_data))
|
||||
+#define NEXT_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_NXT - 1]->td_data))
|
||||
+#define CHECK_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_CHK - 1]->td_data))
|
||||
+#define EQUIV_TABLE(DFA) ((u8 *)((DFA)->tables[YYTD_ID_EC - 1]->td_data))
|
||||
+#define ACCEPT_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT - 1]->td_data))
|
||||
+
|
||||
+struct aa_dfa {
|
||||
+ struct table_header *tables[YYTD_ID_NXT];
|
||||
+
|
||||
+ struct table_set_header th;
|
||||
+};
|
||||
+
|
||||
+#define ntohb(X) (X)
|
||||
+
|
||||
+#define UNPACK_ARRAY(TABLE, BLOB, LEN, TYPE, NTOHX) \
|
||||
+ do { \
|
||||
+ typeof(LEN) __i; \
|
||||
+ TYPE *__t = (TYPE *) TABLE; \
|
||||
+ TYPE *__b = (TYPE *) BLOB; \
|
||||
+ for (__i = 0; __i < LEN; __i++) { \
|
||||
+ __t[__i] = NTOHX(__b[__i]); \
|
||||
+ } \
|
||||
+ } while (0)
|
||||
+
|
||||
+static inline size_t pad64(size_t i)
|
||||
+{
|
||||
+ return (i + (size_t)7) & ~(size_t)7;
|
||||
+}
|
||||
+
|
||||
+static inline size_t table_size(size_t len, size_t el_size)
|
||||
+{
|
||||
+ return pad64(sizeof(struct table_header) + len * el_size);
|
||||
+}
|
||||
+
|
||||
+static struct table_header *unpack_table(void *blob, size_t bsize)
|
||||
+{
|
||||
+ struct table_header *table = NULL;
|
||||
+ struct table_header th;
|
||||
+ size_t tsize;
|
||||
+
|
||||
+ if (bsize < sizeof(struct table_header))
|
||||
+ goto out;
|
||||
+
|
||||
+ th.td_id = ntohs(get_unaligned((u16 *) (blob)));
|
||||
+ th.td_flags = ntohs(get_unaligned((u16 *) (blob + 2)));
|
||||
+ th.td_lolen = ntohl(get_unaligned((u32 *) (blob + 8)));
|
||||
+ blob += sizeof(struct table_header);
|
||||
+
|
||||
+ if (!(th.td_flags == YYTD_DATA16 || th.td_flags == YYTD_DATA32 ||
|
||||
+ th.td_flags == YYTD_DATA8))
|
||||
+ goto out;
|
||||
+
|
||||
+ tsize = table_size(th.td_lolen, th.td_flags);
|
||||
+ if (bsize < tsize)
|
||||
+ goto out;
|
||||
+
|
||||
+ table = kmalloc(tsize, GFP_KERNEL);
|
||||
+ if (table) {
|
||||
+ *table = th;
|
||||
+ if (th.td_flags == YYTD_DATA8)
|
||||
+ UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
|
||||
+ u8, ntohb);
|
||||
+ else if (th.td_flags == YYTD_DATA16)
|
||||
+ UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
|
||||
+ u16, ntohs);
|
||||
+ else
|
||||
+ UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
|
||||
+ u32, ntohl);
|
||||
+ }
|
||||
+
|
||||
+out:
|
||||
+ return table;
|
||||
+}
|
||||
+
|
||||
+static int unpack_dfa(struct aa_dfa *dfa, void *blob, size_t size)
|
||||
+{
|
||||
+ int i;
|
||||
+ int error = -ENOMEM;
|
||||
+
|
||||
+ /* get dfa table set header */
|
||||
+ if (size < sizeof(struct table_set_header))
|
||||
+ goto fail;
|
||||
+
|
||||
+ dfa->th.th_magic = ntohl(get_unaligned((u32 *) (blob + 0)));
|
||||
+ dfa->th.th_hsize = ntohl(get_unaligned((u32 *) (blob + 4)));
|
||||
+ dfa->th.th_ssize = ntohl(get_unaligned((u32 *) (blob + 8)));
|
||||
+ dfa->th.th_flags = ntohs(get_unaligned((u16 *) (blob + 12)));
|
||||
+
|
||||
+ if (dfa->th.th_magic != YYTH_MAGIC)
|
||||
+ goto fail;
|
||||
+
|
||||
+ if (size < dfa->th.th_hsize)
|
||||
+ goto fail;
|
||||
+
|
||||
+ blob += dfa->th.th_hsize;
|
||||
+ size -= dfa->th.th_hsize;
|
||||
+
|
||||
+ while (size > 0) {
|
||||
+ struct table_header *table;
|
||||
+ table = unpack_table(blob, size);
|
||||
+ if (!table)
|
||||
+ goto fail;
|
||||
+
|
||||
+ switch(table->td_id) {
|
||||
+ case YYTD_ID_ACCEPT:
|
||||
+ case YYTD_ID_BASE:
|
||||
+ dfa->tables[table->td_id - 1] = table;
|
||||
+ if (table->td_flags != YYTD_DATA32)
|
||||
+ goto fail_proto;
|
||||
+ break;
|
||||
+ case YYTD_ID_DEF:
|
||||
+ case YYTD_ID_NXT:
|
||||
+ case YYTD_ID_CHK:
|
||||
+ dfa->tables[table->td_id - 1] = table;
|
||||
+ if (table->td_flags != YYTD_DATA16)
|
||||
+ goto fail_proto;
|
||||
+ break;
|
||||
+ case YYTD_ID_EC:
|
||||
+ dfa->tables[table->td_id - 1] = table;
|
||||
+ if (table->td_flags != YYTD_DATA8)
|
||||
+ goto fail_proto;
|
||||
+ break;
|
||||
+ default:
|
||||
+ kfree(table);
|
||||
+ goto fail_proto;
|
||||
+ }
|
||||
+
|
||||
+ blob += table_size(table->td_lolen, table->td_flags);
|
||||
+ size -= table_size(table->td_lolen, table->td_flags);
|
||||
+ }
|
||||
+
|
||||
+ error = 0;
|
||||
+
|
||||
+ return error;
|
||||
+
|
||||
+fail_proto:
|
||||
+ error = -EPROTO;
|
||||
+fail:
|
||||
+ for (i = 0; i < YYTD_ID_NXT; i++) {
|
||||
+ if (dfa->tables[i]) {
|
||||
+ kfree(dfa->tables[i]);
|
||||
+ dfa->tables[i] = NULL;
|
||||
+ }
|
||||
+ }
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * verify_dfa - verify that all the transitions and states in the dfa tables
|
||||
+ * are in bounds.
|
||||
+ * @dfa: dfa to test
|
||||
+ *
|
||||
+ * assumes dfa has gone through the verification done by unpacking
|
||||
+ */
|
||||
+static int verify_dfa(struct aa_dfa *dfa)
|
||||
+{
|
||||
+ size_t i, state_count, trans_count;
|
||||
+ int error = -EPROTO;
|
||||
+
|
||||
+ /* check that required tables exist */
|
||||
+ if (!(dfa->tables[YYTD_ID_ACCEPT -1 ] &&
|
||||
+ dfa->tables[YYTD_ID_DEF - 1] &&
|
||||
+ dfa->tables[YYTD_ID_BASE - 1] &&
|
||||
+ dfa->tables[YYTD_ID_NXT - 1] &&
|
||||
+ dfa->tables[YYTD_ID_CHK - 1]))
|
||||
+ goto out;
|
||||
+
|
||||
+ /* accept.size == default.size == base.size */
|
||||
+ state_count = dfa->tables[YYTD_ID_BASE - 1]->td_lolen;
|
||||
+ if (!(state_count == dfa->tables[YYTD_ID_DEF - 1]->td_lolen &&
|
||||
+ state_count == dfa->tables[YYTD_ID_ACCEPT - 1]->td_lolen))
|
||||
+ goto out;
|
||||
+
|
||||
+ /* next.size == chk.size */
|
||||
+ trans_count = dfa->tables[YYTD_ID_NXT - 1]->td_lolen;
|
||||
+ if (trans_count != dfa->tables[YYTD_ID_CHK - 1]->td_lolen)
|
||||
+ goto out;
|
||||
+
|
||||
+ /* if equivalence classes then its table must be 256 */
|
||||
+ if (dfa->tables[YYTD_ID_EC - 1] &&
|
||||
+ dfa->tables[YYTD_ID_EC - 1]->td_lolen != 256)
|
||||
+ goto out;
|
||||
+
|
||||
+ for (i = 0; i < state_count; i++) {
|
||||
+ if (DEFAULT_TABLE(dfa)[i] >= state_count)
|
||||
+ goto out;
|
||||
+ if (BASE_TABLE(dfa)[i] >= trans_count + 256)
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < trans_count ; i++) {
|
||||
+ if (NEXT_TABLE(dfa)[i] >= state_count)
|
||||
+ goto out;
|
||||
+ if (CHECK_TABLE(dfa)[i] >= state_count)
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ error = 0;
|
||||
+out:
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * aadfa_label - return the permissions associated with @state
|
||||
+ * @dfa: dfa to get state permission from
|
||||
+ * @state: state in the dfa for which to get a label
|
||||
+ *
|
||||
+ * Assumes that state is a valid state of the dfa
|
||||
+ *
|
||||
+ * Returns the label associated with @state. 0 indicates the state
|
||||
+ * is no-accepting/provides no permissions.
|
||||
+ */
|
||||
+inline unsigned int aadfa_label(struct aa_dfa *dfa, int state)
|
||||
+{
|
||||
+ return ACCEPT_TABLE(dfa)[state] & AA_VALID_PERM_MASK;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * aadfa_match - match @path against @dfa starting in @state
|
||||
+ * @dfa: the dfa to match @path against
|
||||
+ * @state: the state to start matching in
|
||||
+ * @path: the path to match against the dfa
|
||||
+ *
|
||||
+ * aadfa_match will match the full path length and return the state it
|
||||
+ * finished matching in. The final state returned can be used to
|
||||
+ * lookup the accepting label or as a starting point to continue matching
|
||||
+ * with a new string if the path has been broken into multiple components.
|
||||
+ */
|
||||
+static unsigned int aadfa_match(struct aa_dfa *dfa, unsigned int state,
|
||||
+ const char *path)
|
||||
+{
|
||||
+ u8 *s = (u8 *) path;
|
||||
+ u16 *def = DEFAULT_TABLE(dfa);
|
||||
+ u32 *base = BASE_TABLE(dfa);
|
||||
+ u16 *next = NEXT_TABLE(dfa);
|
||||
+ u16 *check = CHECK_TABLE(dfa);
|
||||
+ unsigned int pos;
|
||||
+
|
||||
+ /* current state is <state>, matching character *s */
|
||||
+ if (dfa->tables[YYTD_ID_EC - 1]) {
|
||||
+ u8 *equiv = EQUIV_TABLE(dfa);
|
||||
+ for ( ; *s; ++s) {
|
||||
+ pos = base[state] + equiv[*s];
|
||||
+ if (check[pos] == state)
|
||||
+ state = next[pos];
|
||||
+ else
|
||||
+ state = def[state];
|
||||
+ }
|
||||
+ } else {
|
||||
+ for ( ; *s; ++s) {
|
||||
+ pos = base[state] + *s;
|
||||
+ if (check[pos] == state)
|
||||
+ state = next[pos];
|
||||
+ else
|
||||
+ state = def[state];
|
||||
+ }
|
||||
+ }
|
||||
+ return state;
|
||||
+}
|
||||
+
|
||||
+void* aamatch_alloc(enum entry_match_type entry_type)
|
||||
+{
|
||||
+ void *ptr=NULL;
|
||||
+
|
||||
+ if (entry_type == aa_entry_pattern) {
|
||||
+ ptr = kmalloc(sizeof(struct aa_dfa), GFP_KERNEL);
|
||||
+ if (ptr)
|
||||
+ memset(ptr, 0, sizeof(struct aa_dfa));
|
||||
+ else
|
||||
+ ptr=ERR_PTR(-ENOMEM);
|
||||
+ } else if (entry_type != aa_entry_literal &&
|
||||
+ entry_type != aa_entry_tailglob) {
|
||||
+ ptr = ERR_PTR(-EINVAL);
|
||||
+ }
|
||||
+
|
||||
+ return ptr;
|
||||
+}
|
||||
+
|
||||
+void aamatch_free(void *ptr)
|
||||
+{
|
||||
+ if (ptr) {
|
||||
+ int i;
|
||||
+ struct aa_dfa *dfa = (struct aa_dfa *) ptr;
|
||||
+ for (i = 0; i < YYTD_ID_NXT; i++) {
|
||||
+ if (dfa->tables[i])
|
||||
+ kfree(dfa->tables[i]);
|
||||
+ }
|
||||
+ }
|
||||
+ kfree(ptr);
|
||||
+}
|
||||
+
|
||||
+const char *aamatch_features(void)
|
||||
+{
|
||||
+ return features;
|
||||
+}
|
||||
+
|
||||
+int aamatch_serialize(void *entry_extradata, struct aa_ext *e,
|
||||
+ aamatch_serializecb cb)
|
||||
+{
|
||||
+ int error = 0;
|
||||
+ char *blob = NULL;
|
||||
+ size_t size;
|
||||
+
|
||||
+ struct aa_dfa *dfa = (struct aa_dfa *) entry_extradata;
|
||||
+ if (dfa == NULL)
|
||||
+ goto done;
|
||||
+
|
||||
+ error = -EPROTO;
|
||||
+ size = cb(e, AA_BLOB_LOC, &blob, "aadfa");
|
||||
+
|
||||
+ if (size)
|
||||
+ error = unpack_dfa(dfa, blob, size);
|
||||
+
|
||||
+ if (!error)
|
||||
+ error = verify_dfa(dfa);
|
||||
+done:
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+int aamatch_match(struct aa_entry *entry, const char *pathname)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ if (entry->type == aa_entry_pattern) {
|
||||
+ unsigned int state;
|
||||
+ struct aa_dfa *dfa = (struct aa_dfa *) entry->extradata;
|
||||
+
|
||||
+ state = aadfa_match(dfa, 1, pathname);
|
||||
+
|
||||
+ /* label returned is the permissions of the matched state */
|
||||
+ ret = aadfa_label(dfa, state);
|
||||
+ } else {
|
||||
+ ret = aamatch_match_common(entry, pathname);
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+EXPORT_SYMBOL_GPL(aamatch_alloc);
|
||||
+EXPORT_SYMBOL_GPL(aamatch_free);
|
||||
+EXPORT_SYMBOL_GPL(aamatch_features);
|
||||
+EXPORT_SYMBOL_GPL(aamatch_serialize);
|
||||
+EXPORT_SYMBOL_GPL(aamatch_match);
|
||||
+
|
||||
+MODULE_DESCRIPTION("AppArmor aa_match module [dfa]");
|
||||
+MODULE_AUTHOR("John Johansen <jjohansen@suse.de>");
|
||||
+MODULE_LICENSE("GPL");
|
||||
Index: linux-2.6.19.1/security/apparmor/module_interface.c
|
||||
===================================================================
|
||||
--- linux-2.6.19.1.orig/security/apparmor/module_interface.c
|
||||
+++ linux-2.6.19.1/security/apparmor/module_interface.c
|
||||
@@ -206,6 +206,7 @@ static void aaconvert(enum aa_code code,
|
||||
*(u16 *)dest = le16_to_cpu(get_unaligned((u16 *)src));
|
||||
break;
|
||||
case AA_U32:
|
||||
+ case AA_BLOB_LOC:
|
||||
case AA_STATIC_BLOB:
|
||||
*(u32 *)dest = le32_to_cpu(get_unaligned((u32 *)src));
|
||||
break;
|
||||
@@ -239,7 +240,8 @@ static u32 aa_is_X(struct aa_ext *e, enu
|
||||
int ret = 0;
|
||||
if (!aa_inbounds(e, AA_CODE_BYTE + aacode_datasize[code]))
|
||||
goto fail;
|
||||
- if (code != *(u8 *)e->pos)
|
||||
+ if (code != *(u8 *)e->pos &&
|
||||
+ !(code == AA_BLOB_LOC && AA_STATIC_BLOB == *(u8 *)e->pos))
|
||||
goto out;
|
||||
e->pos += AA_CODE_BYTE;
|
||||
if (code == AA_NAME) {
|
||||
@@ -271,6 +273,20 @@ static u32 aa_is_X(struct aa_ext *e, enu
|
||||
}
|
||||
e->pos += size;
|
||||
ret = size;
|
||||
+
|
||||
+ } else if (code == AA_BLOB_LOC) {
|
||||
+ u32 size;
|
||||
+ /* blobs are followed by X bytes */
|
||||
+ size = le32_to_cpu(get_unaligned((u32 *)e->pos));
|
||||
+ e->pos += aacode_datasize[AA_STATIC_BLOB];
|
||||
+ if (!aa_inbounds(e, (size_t) size))
|
||||
+ goto fail;
|
||||
+ if (data) {
|
||||
+ * (char **)data = e->pos;
|
||||
+ }
|
||||
+ e->pos += size;
|
||||
+ ret = size;
|
||||
+
|
||||
} else if (code == AA_STATIC_BLOB) {
|
||||
u32 size;
|
||||
/* blobs are followed by X bytes, that can be 2^32 */
|
||||
@@ -434,7 +450,6 @@ static inline struct aa_entry *aa_activa
|
||||
return entry;
|
||||
|
||||
fail:
|
||||
- aamatch_free(entry->extradata);
|
||||
free_aa_entry(entry);
|
||||
return NULL;
|
||||
}
|
||||
Index: linux-2.6.19.1/security/apparmor/module_interface.h
|
||||
===================================================================
|
||||
--- linux-2.6.19.1.orig/security/apparmor/module_interface.h
|
||||
+++ linux-2.6.19.1/security/apparmor/module_interface.h
|
||||
@@ -20,6 +20,7 @@ enum aa_code {
|
||||
AA_LIST,
|
||||
AA_LISTEND,
|
||||
AA_OFFSET,
|
||||
+ AA_BLOB_LOC,
|
||||
AA_BAD
|
||||
};
|
||||
|
||||
Index: linux-2.6.19.1/security/apparmor/shared.h
|
||||
===================================================================
|
||||
--- linux-2.6.19.1.orig/security/apparmor/shared.h
|
||||
+++ linux-2.6.19.1/security/apparmor/shared.h
|
||||
@@ -28,6 +28,9 @@
|
||||
#define POS_AA_EXEC_UNSAFE (POS_AA_EXEC_MMAP + 1)
|
||||
#define POS_AA_FILE_MAX POS_AA_EXEC_UNSAFE
|
||||
|
||||
+/* Invalid perm permission */
|
||||
+#define POS_AA_INVALID_POS 31
|
||||
+
|
||||
/* Modeled after MAY_READ, MAY_WRITE, MAY_EXEC def'ns */
|
||||
#define AA_MAY_EXEC (0x01 << POS_AA_MAY_EXEC)
|
||||
#define AA_MAY_WRITE (0x01 << POS_AA_MAY_WRITE)
|
||||
@@ -38,9 +41,11 @@
|
||||
#define AA_EXEC_PROFILE (0x01 << POS_AA_EXEC_PROFILE)
|
||||
#define AA_EXEC_MMAP (0x01 << POS_AA_EXEC_MMAP)
|
||||
#define AA_EXEC_UNSAFE (0x01 << POS_AA_EXEC_UNSAFE)
|
||||
+#define AA_INVALID_PERM (0x01 << POS_AA_INVALID_POS)
|
||||
|
||||
#define AA_EXEC_MODIFIERS (AA_EXEC_INHERIT | \
|
||||
AA_EXEC_UNCONSTRAINED | \
|
||||
AA_EXEC_PROFILE)
|
||||
+#define AA_VALID_PERM_MASK ((1 << (POS_AA_FILE_MAX + 1)) - 1)
|
||||
|
||||
#endif /* _SHARED_H */
|
289
kernel-patches/for-mainline/apparmor-match_perms.diff
Normal file
289
kernel-patches/for-mainline/apparmor-match_perms.diff
Normal file
|
@ -0,0 +1,289 @@
|
|||
Index: linux-2.6.19.1/security/apparmor/main.c
|
||||
===================================================================
|
||||
--- linux-2.6.19.1.orig/security/apparmor/main.c
|
||||
+++ linux-2.6.19.1/security/apparmor/main.c
|
||||
@@ -61,7 +61,7 @@ static inline int aa_taskattr_access(con
|
||||
static inline int aa_file_mode(struct aaprofile *profile, const char *name)
|
||||
{
|
||||
struct aa_entry *entry;
|
||||
- int mode = 0;
|
||||
+ int perms = 0;
|
||||
|
||||
AA_DEBUG("%s: %s\n", __FUNCTION__, name);
|
||||
if (!name) {
|
||||
@@ -74,12 +74,10 @@ static inline int aa_file_mode(struct aa
|
||||
goto out;
|
||||
}
|
||||
list_for_each_entry(entry, &profile->file_entry, list) {
|
||||
- if (aamatch_match(name, entry->filename,
|
||||
- entry->type, entry->extradata))
|
||||
- mode |= entry->mode;
|
||||
+ perms |= aamatch_match(entry, name);
|
||||
}
|
||||
out:
|
||||
- return mode;
|
||||
+ return perms;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,8 +107,7 @@ static inline int aa_get_execmode(struct
|
||||
int *xmod, int *unsafe)
|
||||
{
|
||||
struct aa_entry *entry;
|
||||
- struct aa_entry *match = NULL;
|
||||
-
|
||||
+ int entry_perms = 0, match_perms = 0;
|
||||
int pattern_match_invalid = 0, rc = 0;
|
||||
|
||||
/* search list of profiles with 'x' permission
|
||||
@@ -127,47 +124,44 @@ static inline int aa_get_execmode(struct
|
||||
listp[POS_AA_MAY_EXEC]) {
|
||||
if (!pattern_match_invalid &&
|
||||
entry->type == aa_entry_pattern &&
|
||||
- aamatch_match(name, entry->filename,
|
||||
- entry->type, entry->extradata)) {
|
||||
- if (match &&
|
||||
- AA_EXEC_UNSAFE_MASK(entry->mode) !=
|
||||
- AA_EXEC_UNSAFE_MASK(match->mode))
|
||||
+ (entry_perms = aamatch_match(entry, name))) {
|
||||
+ if (match_perms &&
|
||||
+ AA_EXEC_UNSAFE_MASK(entry_perms) !=
|
||||
+ AA_EXEC_UNSAFE_MASK(match_perms))
|
||||
pattern_match_invalid = 1;
|
||||
else
|
||||
/* keep searching for an exact match */
|
||||
- match = entry;
|
||||
+ match_perms = entry_perms;
|
||||
} else if ((entry->type == aa_entry_literal ||
|
||||
(!pattern_match_invalid &&
|
||||
entry->type == aa_entry_tailglob)) &&
|
||||
- aamatch_match(name, entry->filename,
|
||||
- entry->type,
|
||||
- entry->extradata)) {
|
||||
+ (entry_perms = aamatch_match(entry, name))) {
|
||||
if (entry->type == aa_entry_literal) {
|
||||
/* got an exact match -- there can be only
|
||||
* one, asserted at profile load time
|
||||
*/
|
||||
- match = entry;
|
||||
+ match_perms = entry_perms;
|
||||
pattern_match_invalid = 0;
|
||||
break;
|
||||
} else {
|
||||
- if (match &&
|
||||
- AA_EXEC_UNSAFE_MASK(entry->mode) !=
|
||||
- AA_EXEC_UNSAFE_MASK(match->mode))
|
||||
+ if (match_perms &&
|
||||
+ AA_EXEC_UNSAFE_MASK(entry_perms) !=
|
||||
+ AA_EXEC_UNSAFE_MASK(match_perms))
|
||||
pattern_match_invalid = 1;
|
||||
else
|
||||
/* got a tailglob match, keep searching
|
||||
* for an exact match
|
||||
*/
|
||||
- match = entry;
|
||||
+ match_perms = entry_perms;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- rc = match && !pattern_match_invalid;
|
||||
+ rc = match_perms && !pattern_match_invalid;
|
||||
|
||||
if (rc) {
|
||||
- int mode = AA_EXEC_MASK(match->mode);
|
||||
+ int mode = AA_EXEC_MASK(match_perms);
|
||||
|
||||
/* check for qualifiers, if present
|
||||
* we just return the qualifier
|
||||
@@ -176,8 +170,8 @@ static inline int aa_get_execmode(struct
|
||||
mode = mode & ~AA_MAY_EXEC;
|
||||
|
||||
*xmod = mode;
|
||||
- *unsafe = (match->mode & AA_EXEC_UNSAFE);
|
||||
- } else if (!match) {
|
||||
+ *unsafe = (match_perms & AA_EXEC_UNSAFE);
|
||||
+ } else if (!match_perms) {
|
||||
AA_DEBUG("%s: Unable to find execute entry in profile "
|
||||
"for image '%s'\n",
|
||||
__FUNCTION__,
|
||||
@@ -251,7 +245,8 @@ static inline void aa_permerror2result(i
|
||||
static unsigned int aa_file_perm(struct aaprofile *active, const char *name,
|
||||
int mask)
|
||||
{
|
||||
- int i, error = 0, mode;
|
||||
+ int i, error = 0;
|
||||
+ int perms;
|
||||
|
||||
#define PROCPFX "/proc/"
|
||||
#define PROCLEN sizeof(PROCPFX) - 1
|
||||
@@ -270,7 +265,7 @@ static unsigned int aa_file_perm(struct
|
||||
aa_taskattr_access(name + PROCLEN))
|
||||
goto done;
|
||||
|
||||
- mode = 0;
|
||||
+ perms = 0;
|
||||
|
||||
/* iterate over partition, one permission bit at a time */
|
||||
for (i = 0; i <= POS_AA_FILE_MAX; i++) {
|
||||
@@ -278,32 +273,27 @@ static unsigned int aa_file_perm(struct
|
||||
|
||||
/* do we have to accumulate this bit?
|
||||
* or have we already accumulated it (shortcut below)? */
|
||||
- if (!(mask & (1 << i)) || mode & (1 << i))
|
||||
+ if (!(mask & (1 << i)) || perms & (1 << i))
|
||||
continue;
|
||||
|
||||
list_for_each_entry(entry, &active->file_entryp[i],
|
||||
listp[i]) {
|
||||
- if (aamatch_match(name, entry->filename,
|
||||
- entry->type, entry->extradata)) {
|
||||
- /* Shortcut, accumulate all bits present */
|
||||
- mode |= entry->mode;
|
||||
-
|
||||
- /* Mask bits are overloaded
|
||||
- * MAY_{EXEC,WRITE,READ,APPEND} are used by
|
||||
- * kernel, other values are used locally only.
|
||||
- */
|
||||
- if ((mode & mask) == mask) {
|
||||
- AA_DEBUG("MATCH! %s=0x%x [total mode=0x%x]\n",
|
||||
- name, mask, mode);
|
||||
+ perms |= aamatch_match(entry, name);
|
||||
|
||||
- goto done;
|
||||
- }
|
||||
+ /* Mask bits are overloaded
|
||||
+ * MAY_{EXEC,WRITE,READ,APPEND} are used by
|
||||
+ * kernel, other values are used locally only.
|
||||
+ */
|
||||
+ if ((perms & mask) == mask) {
|
||||
+ AA_DEBUG("MATCH! %s=0x%x [total mode=0x%x]\n",
|
||||
+ name, mask, perms);
|
||||
+ goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* return permissions not satisfied */
|
||||
- error = mask & ~mode;
|
||||
+ error = mask & ~perms;
|
||||
|
||||
done:
|
||||
return error;
|
||||
Index: linux-2.6.19.1/security/apparmor/match/match.h
|
||||
===================================================================
|
||||
--- linux-2.6.19.1.orig/security/apparmor/match/match.h
|
||||
+++ linux-2.6.19.1/security/apparmor/match/match.h
|
||||
@@ -69,16 +69,11 @@ extern int aamatch_serialize(void *entry
|
||||
|
||||
/**
|
||||
* aamatch_match: determine if pathname matches entry
|
||||
+ * @entry: rule entry to match against
|
||||
* @pathname: pathname to verify
|
||||
- * @entry_name: entry name
|
||||
- * @type: type of entry
|
||||
- * @entry_extradata: data previously allocated by aamatch_alloc
|
||||
- * Return value: 1 match, 0 othersise
|
||||
+ * Return value: permission match, 0 othersise
|
||||
*/
|
||||
-extern unsigned int aamatch_match(const char *pathname, const char *entry_name,
|
||||
- enum entry_match_type type,
|
||||
- void *entry_extradata);
|
||||
-
|
||||
+extern int aamatch_match(struct aa_entry *entry, const char *pathname);
|
||||
|
||||
/**
|
||||
* sd_getmatch_type - return string representation of entry_match_type
|
||||
@@ -107,26 +102,25 @@ static inline const char *sd_getmatch_ty
|
||||
* @entry_name: name from aa_entry
|
||||
* @type: type of entry
|
||||
*/
|
||||
-static inline int aamatch_match_common(const char *path,
|
||||
- const char *entry_name,
|
||||
- enum entry_match_type type)
|
||||
+static inline int aamatch_match_common(struct aa_entry *entry,
|
||||
+ const char *path)
|
||||
{
|
||||
int retval;
|
||||
|
||||
/* literal, no pattern matching characters */
|
||||
- if (type == aa_entry_literal) {
|
||||
- retval = (strcmp(entry_name, path) == 0);
|
||||
+ if (entry->type == aa_entry_literal) {
|
||||
+ retval = (strcmp(entry->filename, path) == 0);
|
||||
/* trailing ** glob pattern */
|
||||
- } else if (type == aa_entry_tailglob) {
|
||||
- retval = (strncmp(entry_name, path,
|
||||
- strlen(entry_name) - 2) == 0);
|
||||
+ } else if (entry->type == aa_entry_tailglob) {
|
||||
+ retval = (strncmp(entry->filename, path,
|
||||
+ strlen(entry->filename) - 2) == 0);
|
||||
} else {
|
||||
AA_WARN("%s: Invalid entry_match_type %d\n",
|
||||
- __FUNCTION__, type);
|
||||
+ __FUNCTION__, entry->type);
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
- return retval;
|
||||
+ return retval ? entry->mode : 0;
|
||||
}
|
||||
|
||||
#endif /* __MATCH_H */
|
||||
Index: linux-2.6.19.1/security/apparmor/match/match_default.c
|
||||
===================================================================
|
||||
--- linux-2.6.19.1.orig/security/apparmor/match/match_default.c
|
||||
+++ linux-2.6.19.1/security/apparmor/match/match_default.c
|
||||
@@ -36,12 +36,11 @@ int aamatch_serialize(void *entry_extrad
|
||||
return 0;
|
||||
}
|
||||
|
||||
-unsigned int aamatch_match(const char *pathname, const char *entry_name,
|
||||
- enum entry_match_type type, void *entry_extradata)
|
||||
+int aamatch_match(struct aa_entry *entry, const char *pathname)
|
||||
{
|
||||
int ret;
|
||||
|
||||
- ret = aamatch_match_common(pathname, entry_name, type);
|
||||
+ ret = aamatch_match_common(entry, pathname);
|
||||
|
||||
return ret;
|
||||
}
|
||||
Index: linux-2.6.19.1/security/apparmor/match/match_pcre.c
|
||||
===================================================================
|
||||
--- linux-2.6.19.1.orig/security/apparmor/match/match_pcre.c
|
||||
+++ linux-2.6.19.1/security/apparmor/match/match_pcre.c
|
||||
@@ -132,27 +132,26 @@ done:
|
||||
return error;
|
||||
}
|
||||
|
||||
-unsigned int aamatch_match(const char *pathname, const char *entry_name,
|
||||
- enum entry_match_type entry_type, void *entry_extradata)
|
||||
+int aamatch_match(struct aa_entry *entry, const char *pathname)
|
||||
{
|
||||
int ret;
|
||||
|
||||
- if (entry_type == aa_entry_pattern) {
|
||||
+ if (entry->type == aa_entry_pattern) {
|
||||
int pcreret;
|
||||
struct aamatch_entry *ed =
|
||||
- (struct aamatch_entry *) entry_extradata;
|
||||
+ (struct aamatch_entry *) entry->extradata;
|
||||
|
||||
pcreret = pcre_exec(ed->compiled, NULL,
|
||||
pathname, strlen(pathname),
|
||||
0, 0, NULL, 0);
|
||||
|
||||
- ret = (pcreret >= 0);
|
||||
+ ret = (pcreret >= 0) ? entry->mode : 0;
|
||||
|
||||
// XXX - this needs access to subdomain_debug, hmmm
|
||||
//AA_DEBUG("%s(%d): %s %s %d\n", __FUNCTION__,
|
||||
// ret, pathname, ed->pattern, pcreret);
|
||||
} else {
|
||||
- ret = aamatch_match_common(pathname, entry_name, entry_type);
|
||||
+ ret = aamatch_match_common(entry, pathname);
|
||||
}
|
||||
|
||||
return ret;
|
169
kernel-patches/for-mainline/apparmor-path_resize.diff
Normal file
169
kernel-patches/for-mainline/apparmor-path_resize.diff
Normal file
|
@ -0,0 +1,169 @@
|
|||
Index: linux-2.6.19.1/security/apparmor/apparmor.h
|
||||
===================================================================
|
||||
--- linux-2.6.19.1.orig/security/apparmor/apparmor.h
|
||||
+++ linux-2.6.19.1/security/apparmor/apparmor.h
|
||||
@@ -255,7 +255,8 @@ extern int aa_audit_message(struct aapro
|
||||
extern int aa_audit_syscallreject(struct aaprofile *active, gfp_t gfp,
|
||||
const char *);
|
||||
extern int aa_audit(struct aaprofile *active, const struct aa_audit *);
|
||||
-extern char *aa_get_name(struct dentry *dentry, struct vfsmount *mnt);
|
||||
+extern char *aa_get_name(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ char **addr);
|
||||
|
||||
extern int aa_attr(struct aaprofile *active, struct dentry *dentry,
|
||||
struct vfsmount *mnt, struct iattr *iattr);
|
||||
Index: linux-2.6.19.1/security/apparmor/inline.h
|
||||
===================================================================
|
||||
--- linux-2.6.19.1.orig/security/apparmor/inline.h
|
||||
+++ linux-2.6.19.1/security/apparmor/inline.h
|
||||
@@ -220,9 +220,12 @@ static inline struct aaprofile *alloc_aa
|
||||
* Release space (free_page) allocated to hold pathname
|
||||
* name may be NULL (checked for by free_page)
|
||||
*/
|
||||
-static inline void aa_put_name(const char *name)
|
||||
+static inline void aa_put_name(const char *name, char *addr)
|
||||
{
|
||||
- aa_put_path((char *)name);
|
||||
+ if (addr)
|
||||
+ kfree(addr);
|
||||
+ else
|
||||
+ aa_put_path((char *)name);
|
||||
}
|
||||
|
||||
/** __aa_find_profile
|
||||
Index: linux-2.6.19.1/security/apparmor/main.c
|
||||
===================================================================
|
||||
--- linux-2.6.19.1.orig/security/apparmor/main.c
|
||||
+++ linux-2.6.19.1/security/apparmor/main.c
|
||||
@@ -454,8 +454,9 @@ static int _aa_perm_vfsmount(struct aapr
|
||||
struct vfsmount *mnt, struct aa_audit *sa, int mask)
|
||||
{
|
||||
int permerror, error;
|
||||
+ char *addr;
|
||||
|
||||
- sa->name = aa_get_name(dentry, mnt);
|
||||
+ sa->name = aa_get_name(dentry, mnt, &addr);
|
||||
|
||||
if (IS_ERR(sa->name)) {
|
||||
permerror = PTR_ERR(sa->name);
|
||||
@@ -468,7 +469,7 @@ static int _aa_perm_vfsmount(struct aapr
|
||||
|
||||
error = aa_audit(active, sa);
|
||||
|
||||
- aa_put_name(sa->name);
|
||||
+ aa_put_name(sa->name, addr);
|
||||
|
||||
return error;
|
||||
}
|
||||
@@ -794,27 +795,37 @@ out:
|
||||
* aa_get_name - retrieve fully qualified path name
|
||||
* @dentry: relative path element
|
||||
* @mnt: where in tree
|
||||
- *
|
||||
+ * @addr: the true start address of returned names buffer if buffer > a
|
||||
+ * single page
|
||||
* Returns fully qualified path name on sucess, NULL on failure.
|
||||
* aa_put_name must be used to free allocated buffer.
|
||||
*/
|
||||
-char *aa_get_name(struct dentry *dentry, struct vfsmount *mnt)
|
||||
+char *aa_get_name(struct dentry *dentry, struct vfsmount *mnt, char **addr)
|
||||
{
|
||||
- char *page, *name;
|
||||
+ char *buffer, *name;
|
||||
+ int order = 0;
|
||||
|
||||
- page = (char *)aa_get_path(GFP_KERNEL);
|
||||
- if (!page) {
|
||||
+ *addr = NULL;
|
||||
+ buffer = (char *)aa_get_path(GFP_KERNEL);
|
||||
+ retry:
|
||||
+ if (!buffer) {
|
||||
name = ERR_PTR(-ENOMEM);
|
||||
goto out;
|
||||
}
|
||||
|
||||
- name = d_path(dentry, mnt, page, PAGE_SIZE);
|
||||
+ name = d_path(dentry, mnt, buffer, PAGE_SIZE << order);
|
||||
/* check for (deleted) that d_path appends to pathnames if the dentry
|
||||
* has been removed from the cache.
|
||||
* The size > deleted_size and strcmp checks are redundant safe guards.
|
||||
*/
|
||||
if (IS_ERR(name)) {
|
||||
- aa_put_path(page);
|
||||
+ if (order == 0)
|
||||
+ aa_put_path(buffer);
|
||||
+ else
|
||||
+ kfree(buffer);
|
||||
+ order++;
|
||||
+ buffer = kmalloc(PAGE_SIZE << order, GFP_KERNEL);
|
||||
+ goto retry;
|
||||
} else {
|
||||
const char deleted_str[] = " (deleted)";
|
||||
const size_t deleted_size = sizeof(deleted_str) - 1;
|
||||
@@ -828,6 +839,8 @@ char *aa_get_name(struct dentry *dentry,
|
||||
}
|
||||
|
||||
out:
|
||||
+ if (order > 0)
|
||||
+ *addr = buffer;
|
||||
return name;
|
||||
}
|
||||
|
||||
@@ -902,6 +915,7 @@ int aa_perm(struct aaprofile *active, st
|
||||
{
|
||||
int error = 0;
|
||||
struct aa_audit sa;
|
||||
+ char *addr;
|
||||
|
||||
if ((mask = aa_filter_mask(mask, dentry->d_inode)) == 0)
|
||||
goto out;
|
||||
@@ -986,9 +1000,10 @@ int aa_link(struct aaprofile *active,
|
||||
{
|
||||
int permerror = -EPERM, error;
|
||||
struct aa_audit sa;
|
||||
+ char *addr, *paddr;
|
||||
|
||||
- sa.name = aa_get_name(link, link_mnt);
|
||||
- sa.pval = aa_get_name(target, target_mnt);
|
||||
+ sa.name = aa_get_name(link, link_mnt, &addr);
|
||||
+ sa.pval = aa_get_name(target, target_mnt, &paddr);
|
||||
|
||||
if (IS_ERR(sa.name)) {
|
||||
permerror = PTR_ERR(sa.name);
|
||||
@@ -1010,8 +1025,8 @@ int aa_link(struct aaprofile *active,
|
||||
|
||||
error = aa_audit(active, &sa);
|
||||
|
||||
- aa_put_name(sa.name);
|
||||
- aa_put_name(sa.pval);
|
||||
+ aa_put_name(sa.name, addr);
|
||||
+ aa_put_name(sa.pval, paddr);
|
||||
|
||||
return error;
|
||||
}
|
||||
@@ -1078,6 +1093,7 @@ int aa_fork(struct task_struct *p)
|
||||
int aa_register(struct linux_binprm *bprm)
|
||||
{
|
||||
char *filename;
|
||||
+ char *addr;
|
||||
struct file *filp = bprm->file;
|
||||
struct aaprofile *active;
|
||||
struct aaprofile *newprofile = NULL, unconstrained_flag;
|
||||
@@ -1090,7 +1106,7 @@ int aa_register(struct linux_binprm *bpr
|
||||
|
||||
AA_DEBUG("%s\n", __FUNCTION__);
|
||||
|
||||
- filename = aa_get_name(filp->f_dentry, filp->f_vfsmnt);
|
||||
+ filename = aa_get_name(filp->f_dentry, filp->f_vfsmnt, &addr);
|
||||
if (IS_ERR(filename)) {
|
||||
AA_WARN("%s: Failed to get filename\n", __FUNCTION__);
|
||||
goto out;
|
||||
@@ -1339,7 +1355,7 @@ apply_profile:
|
||||
}
|
||||
|
||||
cleanup:
|
||||
- aa_put_name(filename);
|
||||
+ aa_put_name(filename, addr);
|
||||
|
||||
put_aaprofile(active);
|
||||
|
219
kernel-patches/for-mainline/apparmor-percpu_path_cache.diff
Normal file
219
kernel-patches/for-mainline/apparmor-percpu_path_cache.diff
Normal file
|
@ -0,0 +1,219 @@
|
|||
Index: linux-2.6.19.1/security/apparmor/apparmor.h
|
||||
===================================================================
|
||||
--- linux-2.6.19.1.orig/security/apparmor/apparmor.h
|
||||
+++ linux-2.6.19.1/security/apparmor/apparmor.h
|
||||
@@ -234,7 +234,19 @@ enum aa_xattroptype {
|
||||
#define BASE_PROFILE(p) ((p)->parent ? (p)->parent : (p))
|
||||
#define IN_SUBPROFILE(p) ((p)->parent)
|
||||
|
||||
+/* path name buffer cache */
|
||||
+#define AAPATH_CACHE_MAX_COUNT 2
|
||||
+
|
||||
+struct aa_path_cache_head {
|
||||
+ unsigned int count;
|
||||
+ struct list_head list;
|
||||
+};
|
||||
+
|
||||
/* main.c */
|
||||
+extern void aa_destroy_path_cache(void);
|
||||
+extern int aa_init_path_cache(void);
|
||||
+extern char *aa_get_path(gfp_t gfp);
|
||||
+extern void aa_put_path(char *path);
|
||||
extern int alloc_null_complain_profile(void);
|
||||
extern void free_null_complain_profile(void);
|
||||
extern int attach_nullprofile(struct aaprofile *profile);
|
||||
Index: linux-2.6.19.1/security/apparmor/inline.h
|
||||
===================================================================
|
||||
--- linux-2.6.19.1.orig/security/apparmor/inline.h
|
||||
+++ linux-2.6.19.1/security/apparmor/inline.h
|
||||
@@ -222,7 +222,7 @@ static inline struct aaprofile *alloc_aa
|
||||
*/
|
||||
static inline void aa_put_name(const char *name)
|
||||
{
|
||||
- free_page((unsigned long)name);
|
||||
+ aa_put_path((char *)name);
|
||||
}
|
||||
|
||||
/** __aa_find_profile
|
||||
Index: linux-2.6.19.1/security/apparmor/lsm.c
|
||||
===================================================================
|
||||
--- linux-2.6.19.1.orig/security/apparmor/lsm.c
|
||||
+++ linux-2.6.19.1/security/apparmor/lsm.c
|
||||
@@ -814,6 +814,11 @@ static int __init apparmor_init(void)
|
||||
goto alloc_out;
|
||||
}
|
||||
|
||||
+ if ((error = aa_init_path_cache())) {
|
||||
+ AA_ERROR("Unable to allocate path cache\n");
|
||||
+ goto path_out;
|
||||
+ }
|
||||
+
|
||||
if ((error = register_security(&apparmor_ops))) {
|
||||
AA_ERROR("Unable to load AppArmor\n");
|
||||
goto register_security_out;
|
||||
@@ -828,6 +833,9 @@ static int __init apparmor_init(void)
|
||||
return error;
|
||||
|
||||
register_security_out:
|
||||
+ aa_destroy_path_cache();
|
||||
+
|
||||
+path_out:
|
||||
free_null_complain_profile();
|
||||
|
||||
alloc_out:
|
||||
Index: linux-2.6.19.1/security/apparmor/main.c
|
||||
===================================================================
|
||||
--- linux-2.6.19.1.orig/security/apparmor/main.c
|
||||
+++ linux-2.6.19.1/security/apparmor/main.c
|
||||
@@ -12,12 +12,133 @@
|
||||
#include <linux/security.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/audit.h>
|
||||
+#include <linux/mm.h>
|
||||
|
||||
#include "apparmor.h"
|
||||
#include "match/match.h"
|
||||
|
||||
#include "inline.h"
|
||||
|
||||
+static DEFINE_PER_CPU(struct aa_path_cache_head, aa_path_cache);
|
||||
+
|
||||
+/**
|
||||
+ * aa_destroy_path_cache - destroy the path cache initialized
|
||||
+ */
|
||||
+void aa_destroy_path_cache(void)
|
||||
+{
|
||||
+ int cpu;
|
||||
+
|
||||
+ for_each_possible_cpu(cpu) {
|
||||
+ struct list_head *n, *tmp;
|
||||
+ if (per_cpu(aa_path_cache, cpu).count == 0)
|
||||
+ continue;
|
||||
+ per_cpu(aa_path_cache, cpu).count = 0;
|
||||
+ list_for_each_safe(n, tmp, &per_cpu(aa_path_cache, cpu).list) {
|
||||
+ list_del(n);
|
||||
+ free_page((unsigned long) n);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+#define ALIGN_TO_PAGE(X) (((unsigned long)(X)) & PAGE_MASK)
|
||||
+
|
||||
+static inline int aa_push_path(struct aa_path_cache_head *cache, char *path)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ if (cache->count < AAPATH_CACHE_MAX_COUNT) {
|
||||
+ list_add((struct list_head *) ALIGN_TO_PAGE(path),
|
||||
+ &cache->list);
|
||||
+ cache->count++;
|
||||
+ ret = 1;
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * aa_init_path_cache - initialize AA's path cache
|
||||
+ */
|
||||
+int aa_init_path_cache(void)
|
||||
+{
|
||||
+ int cpu;
|
||||
+ int error = -ENOMEM;
|
||||
+
|
||||
+ for_each_possible_cpu(cpu) {
|
||||
+ per_cpu(aa_path_cache, cpu).count = 0;
|
||||
+ INIT_LIST_HEAD(&per_cpu(aa_path_cache, cpu).list);
|
||||
+ }
|
||||
+
|
||||
+ /* initialize the path cache with 2 pages/cpu */
|
||||
+ for_each_possible_cpu(cpu) {
|
||||
+ char *page;
|
||||
+
|
||||
+ page = (char *) __get_free_page(GFP_KERNEL);
|
||||
+ if (!page)
|
||||
+ goto out;
|
||||
+ aa_push_path(&per_cpu(aa_path_cache, cpu), page);
|
||||
+ page = (char *) __get_free_page(GFP_KERNEL);
|
||||
+ if (!page)
|
||||
+ goto out;
|
||||
+ aa_push_path(&per_cpu(aa_path_cache, cpu), page);
|
||||
+ error = 0;
|
||||
+ }
|
||||
+
|
||||
+out:
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * aa_get_path - get a path buffer for use in path lookups
|
||||
+ * @gfp: the type of memory allocation to perform if no buffer available in
|
||||
+ * the cache.
|
||||
+ */
|
||||
+char *aa_get_path(gfp_t gfp)
|
||||
+{
|
||||
+ struct aa_path_cache_head *cache;
|
||||
+ char *path;
|
||||
+
|
||||
+ cache = &get_cpu_var(aa_path_cache);
|
||||
+ if (cache->count) {
|
||||
+ struct list_head *node;
|
||||
+ list_for_each(node, &cache->list) {
|
||||
+ list_del(node);
|
||||
+ break;
|
||||
+ }
|
||||
+ cache->count--;
|
||||
+ path = (char *) node;
|
||||
+ put_cpu_var(aa_path_cache);
|
||||
+ } else {
|
||||
+ put_cpu_var(aa_path_cache);
|
||||
+ path = (char *) __get_free_page(gfp);
|
||||
+ }
|
||||
+ return path;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * aa_put_path - put a path buffer obtained with aa_get_path
|
||||
+ * @path: the path buffer to return to the path buffer cache
|
||||
+ */
|
||||
+void aa_put_path(char *path)
|
||||
+{
|
||||
+ if (!path)
|
||||
+ goto out;
|
||||
+
|
||||
+ /* does the path buffer belong on the current cpu's node */
|
||||
+ if (cpu_to_node(smp_processor_id()) ==
|
||||
+ page_to_nid(virt_to_page(path))) {
|
||||
+ struct aa_path_cache_head *cache = &get_cpu_var(aa_path_cache);
|
||||
+ int success = aa_push_path(cache, path);
|
||||
+ put_cpu_var(aa_path_cache);
|
||||
+ if (success)
|
||||
+ goto out;
|
||||
+ }
|
||||
+ free_page((unsigned long) path);
|
||||
+
|
||||
+out:
|
||||
+ return;
|
||||
+}
|
||||
+
|
||||
/* NULL complain profile
|
||||
*
|
||||
* Used when in complain mode, to emit Permitting messages for non-existant
|
||||
@@ -681,7 +802,7 @@ char *aa_get_name(struct dentry *dentry,
|
||||
{
|
||||
char *page, *name;
|
||||
|
||||
- page = (char *)__get_free_page(GFP_KERNEL);
|
||||
+ page = (char *)aa_get_path(GFP_KERNEL);
|
||||
if (!page) {
|
||||
name = ERR_PTR(-ENOMEM);
|
||||
goto out;
|
||||
@@ -693,7 +814,7 @@ char *aa_get_name(struct dentry *dentry,
|
||||
* The size > deleted_size and strcmp checks are redundant safe guards.
|
||||
*/
|
||||
if (IS_ERR(name)) {
|
||||
- free_page((unsigned long)page);
|
||||
+ aa_put_path(page);
|
||||
} else {
|
||||
const char deleted_str[] = " (deleted)";
|
||||
const size_t deleted_size = sizeof(deleted_str) - 1;
|
101
kernel-patches/for-mainline/d_path_flags.diff
Normal file
101
kernel-patches/for-mainline/d_path_flags.diff
Normal file
|
@ -0,0 +1,101 @@
|
|||
Index: linux-2.6.19.1/fs/dcache.c
|
||||
===================================================================
|
||||
--- linux-2.6.19.1.orig/fs/dcache.c
|
||||
+++ linux-2.6.19.1/fs/dcache.c
|
||||
@@ -1731,9 +1731,11 @@ shouldnt_be_hashed:
|
||||
* @rootmnt: vfsmnt to which the root dentry belongs
|
||||
* @buffer: buffer to return value in
|
||||
* @buflen: buffer length
|
||||
+ * @flags: flags indicating what should be in the path
|
||||
*
|
||||
* Convert a dentry into an ASCII path name. If the entry has been deleted
|
||||
- * the string " (deleted)" is appended. Note that this is ambiguous.
|
||||
+ * and the DPATH_DELETED flag is set the string " (deleted)" is appended.
|
||||
+ * Note that this is ambiguous.
|
||||
*
|
||||
* Returns the buffer or an error code if the path was too long.
|
||||
*
|
||||
@@ -1741,7 +1743,7 @@ shouldnt_be_hashed:
|
||||
*/
|
||||
static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
|
||||
struct dentry *root, struct vfsmount *rootmnt,
|
||||
- char *buffer, int buflen)
|
||||
+ char *buffer, int buflen, unsigned int flags)
|
||||
{
|
||||
char * end = buffer+buflen;
|
||||
char * retval;
|
||||
@@ -1749,7 +1751,8 @@ static char * __d_path( struct dentry *d
|
||||
|
||||
*--end = '\0';
|
||||
buflen--;
|
||||
- if (!IS_ROOT(dentry) && d_unhashed(dentry)) {
|
||||
+ if ((flags & DPATH_DELETED) &&
|
||||
+ !IS_ROOT(dentry) && d_unhashed(dentry)) {
|
||||
buflen -= 10;
|
||||
end -= 10;
|
||||
if (buflen < 0)
|
||||
@@ -1808,8 +1811,8 @@ Elong:
|
||||
}
|
||||
|
||||
/* write full pathname into buffer and return start of pathname */
|
||||
-char * d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
|
||||
- char *buf, int buflen)
|
||||
+char * d_path_flags(struct dentry *dentry, struct vfsmount *vfsmnt,
|
||||
+ char *buf, int buflen, unsigned int flags)
|
||||
{
|
||||
char *res;
|
||||
struct vfsmount *rootmnt;
|
||||
@@ -1820,7 +1823,7 @@ char * d_path(struct dentry *dentry, str
|
||||
root = dget(current->fs->root);
|
||||
read_unlock(¤t->fs->lock);
|
||||
spin_lock(&dcache_lock);
|
||||
- res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen);
|
||||
+ res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen, flags);
|
||||
spin_unlock(&dcache_lock);
|
||||
dput(root);
|
||||
mntput(rootmnt);
|
||||
@@ -1869,7 +1872,8 @@ asmlinkage long sys_getcwd(char __user *
|
||||
unsigned long len;
|
||||
char * cwd;
|
||||
|
||||
- cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE);
|
||||
+ cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE,
|
||||
+ DPATH_DELETED);
|
||||
spin_unlock(&dcache_lock);
|
||||
|
||||
error = PTR_ERR(cwd);
|
||||
@@ -2119,7 +2123,7 @@ EXPORT_SYMBOL(d_invalidate);
|
||||
EXPORT_SYMBOL(d_lookup);
|
||||
EXPORT_SYMBOL(d_move);
|
||||
EXPORT_SYMBOL_GPL(d_materialise_unique);
|
||||
-EXPORT_SYMBOL(d_path);
|
||||
+EXPORT_SYMBOL(d_path_flags);
|
||||
EXPORT_SYMBOL(d_prune_aliases);
|
||||
EXPORT_SYMBOL(d_rehash);
|
||||
EXPORT_SYMBOL(d_splice_alias);
|
||||
Index: linux-2.6.19.1/include/linux/dcache.h
|
||||
===================================================================
|
||||
--- linux-2.6.19.1.orig/include/linux/dcache.h
|
||||
+++ linux-2.6.19.1/include/linux/dcache.h
|
||||
@@ -176,6 +176,9 @@ d_iput: no no no yes
|
||||
|
||||
#define DCACHE_INOTIFY_PARENT_WATCHED 0x0020 /* Parent inode is watched */
|
||||
|
||||
+/* d_path flags */
|
||||
+#define DPATH_DELETED 0x0001 /* append " (deleted)" */
|
||||
+
|
||||
extern spinlock_t dcache_lock;
|
||||
|
||||
/**
|
||||
@@ -293,7 +296,10 @@ extern struct dentry * d_hash_and_lookup
|
||||
/* validate "insecure" dentry pointer */
|
||||
extern int d_validate(struct dentry *, struct dentry *);
|
||||
|
||||
-extern char * d_path(struct dentry *, struct vfsmount *, char *, int);
|
||||
+#define d_path(D, V, B, BL) d_path_flags(D, V, B, BL, DPATH_DELETED)
|
||||
+
|
||||
+extern char * d_path_flags(struct dentry *, struct vfsmount *, char *, int,
|
||||
+ unsigned int);
|
||||
|
||||
/* Allocation counts.. */
|
||||
|
74
kernel-patches/for-mainline/d_path_namespace_root.diff
Normal file
74
kernel-patches/for-mainline/d_path_namespace_root.diff
Normal file
|
@ -0,0 +1,74 @@
|
|||
Index: linux-2.6.19.1/fs/dcache.c
|
||||
===================================================================
|
||||
--- linux-2.6.19.1.orig/fs/dcache.c
|
||||
+++ linux-2.6.19.1/fs/dcache.c
|
||||
@@ -1733,10 +1733,12 @@ shouldnt_be_hashed:
|
||||
* @buflen: buffer length
|
||||
* @flags: flags indicating what should be in the path
|
||||
*
|
||||
- * Convert a dentry into an ASCII path name. If the entry has been deleted
|
||||
- * and the DPATH_DELETED flag is set the string " (deleted)" is appended.
|
||||
- * Note that this is ambiguous.
|
||||
- *
|
||||
+ * Convert a dentry into an ASCII path name.
|
||||
+ * If the entry has been deleted and the DPATH_DELETED flag is set the
|
||||
+ * string " (deleted)" is appended. Note that this is ambiguous.
|
||||
+ * If the DPATH_NSROOT flag is set the path returned will walk past the
|
||||
+ * chroot.
|
||||
+ *
|
||||
* Returns the buffer or an error code if the path was too long.
|
||||
*
|
||||
* "buflen" should be positive. Caller holds the dcache_lock.
|
||||
@@ -1769,7 +1771,8 @@ static char * __d_path( struct dentry *d
|
||||
for (;;) {
|
||||
struct dentry * parent;
|
||||
|
||||
- if (dentry == root && vfsmnt == rootmnt)
|
||||
+ if (!(flags & DPATH_NSROOT) &&
|
||||
+ dentry == root && vfsmnt == rootmnt)
|
||||
break;
|
||||
if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
|
||||
/* Global root? */
|
||||
@@ -1815,18 +1818,22 @@ char * d_path_flags(struct dentry *dentr
|
||||
char *buf, int buflen, unsigned int flags)
|
||||
{
|
||||
char *res;
|
||||
- struct vfsmount *rootmnt;
|
||||
- struct dentry *root;
|
||||
+ struct vfsmount *rootmnt = NULL;
|
||||
+ struct dentry *root = NULL;
|
||||
|
||||
- read_lock(¤t->fs->lock);
|
||||
- rootmnt = mntget(current->fs->rootmnt);
|
||||
- root = dget(current->fs->root);
|
||||
- read_unlock(¤t->fs->lock);
|
||||
+ if (!(flags & DPATH_NSROOT)) {
|
||||
+ read_lock(¤t->fs->lock);
|
||||
+ rootmnt = mntget(current->fs->rootmnt);
|
||||
+ root = dget(current->fs->root);
|
||||
+ read_unlock(¤t->fs->lock);
|
||||
+ }
|
||||
spin_lock(&dcache_lock);
|
||||
res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen, flags);
|
||||
spin_unlock(&dcache_lock);
|
||||
- dput(root);
|
||||
- mntput(rootmnt);
|
||||
+ if (!(flags & DPATH_NSROOT)) {
|
||||
+ dput(root);
|
||||
+ mntput(rootmnt);
|
||||
+ }
|
||||
return res;
|
||||
}
|
||||
|
||||
Index: linux-2.6.19.1/include/linux/dcache.h
|
||||
===================================================================
|
||||
--- linux-2.6.19.1.orig/include/linux/dcache.h
|
||||
+++ linux-2.6.19.1/include/linux/dcache.h
|
||||
@@ -178,6 +178,7 @@ d_iput: no no no yes
|
||||
|
||||
/* d_path flags */
|
||||
#define DPATH_DELETED 0x0001 /* append " (deleted)" */
|
||||
+#define DPATH_NSROOT 0x0002 /* continue past fsroot (chroot) */
|
||||
|
||||
extern spinlock_t dcache_lock;
|
||||
|
134
kernel-patches/for-mainline/d_path_return_flags.diff
Normal file
134
kernel-patches/for-mainline/d_path_return_flags.diff
Normal file
|
@ -0,0 +1,134 @@
|
|||
Index: linux-2.6.19.1/fs/dcache.c
|
||||
===================================================================
|
||||
--- linux-2.6.19.1.orig/fs/dcache.c
|
||||
+++ linux-2.6.19.1/fs/dcache.c
|
||||
@@ -1732,6 +1732,8 @@ shouldnt_be_hashed:
|
||||
* @buffer: buffer to return value in
|
||||
* @buflen: buffer length
|
||||
* @flags: flags indicating what should be in the path
|
||||
+ * @pcons: if none null will contain flags indicating path lookup conditions
|
||||
+ * that may affect the path name.
|
||||
*
|
||||
* Convert a dentry into an ASCII path name.
|
||||
* If the entry has been deleted and the DPATH_DELETED flag is set the
|
||||
@@ -1745,21 +1747,25 @@ shouldnt_be_hashed:
|
||||
*/
|
||||
static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
|
||||
struct dentry *root, struct vfsmount *rootmnt,
|
||||
- char *buffer, int buflen, unsigned int flags)
|
||||
+ char *buffer, int buflen, unsigned int flags,
|
||||
+ unsigned int *pconds)
|
||||
{
|
||||
char * end = buffer+buflen;
|
||||
char * retval;
|
||||
+ unsigned int lpconds = 0;
|
||||
int namelen;
|
||||
|
||||
*--end = '\0';
|
||||
buflen--;
|
||||
- if ((flags & DPATH_DELETED) &&
|
||||
- !IS_ROOT(dentry) && d_unhashed(dentry)) {
|
||||
- buflen -= 10;
|
||||
- end -= 10;
|
||||
- if (buflen < 0)
|
||||
- goto Elong;
|
||||
- memcpy(end, " (deleted)", 10);
|
||||
+ if (!IS_ROOT(dentry) && d_unhashed(dentry)) {
|
||||
+ if (flags & DPATH_DELETED) {
|
||||
+ buflen -= 10;
|
||||
+ end -= 10;
|
||||
+ if (buflen < 0)
|
||||
+ goto Elong;
|
||||
+ memcpy(end, " (deleted)", 10);
|
||||
+ }
|
||||
+ lpconds |= DPATH_DELETED;
|
||||
}
|
||||
|
||||
if (buflen < 1)
|
||||
@@ -1771,9 +1777,11 @@ static char * __d_path( struct dentry *d
|
||||
for (;;) {
|
||||
struct dentry * parent;
|
||||
|
||||
- if (!(flags & DPATH_NSROOT) &&
|
||||
- dentry == root && vfsmnt == rootmnt)
|
||||
- break;
|
||||
+ if (dentry == root && vfsmnt == rootmnt) {
|
||||
+ if (!(flags & DPATH_NSROOT))
|
||||
+ break;
|
||||
+ lpconds |= DPATH_NSROOT;
|
||||
+ }
|
||||
if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
|
||||
/* Global root? */
|
||||
spin_lock(&vfsmount_lock);
|
||||
@@ -1799,6 +1807,8 @@ static char * __d_path( struct dentry *d
|
||||
dentry = parent;
|
||||
}
|
||||
|
||||
+ if (lpconds)
|
||||
+ *pconds = lpconds;
|
||||
return retval;
|
||||
|
||||
global_root:
|
||||
@@ -1808,6 +1818,8 @@ global_root:
|
||||
goto Elong;
|
||||
retval -= namelen-1; /* hit the slash */
|
||||
memcpy(retval, dentry->d_name.name, namelen);
|
||||
+ if (lpconds)
|
||||
+ *pconds = lpconds;
|
||||
return retval;
|
||||
Elong:
|
||||
return ERR_PTR(-ENAMETOOLONG);
|
||||
@@ -1815,7 +1827,8 @@ Elong:
|
||||
|
||||
/* write full pathname into buffer and return start of pathname */
|
||||
char * d_path_flags(struct dentry *dentry, struct vfsmount *vfsmnt,
|
||||
- char *buf, int buflen, unsigned int flags)
|
||||
+ char *buf, int buflen, unsigned int flags,
|
||||
+ unsigned int *pconds)
|
||||
{
|
||||
char *res;
|
||||
struct vfsmount *rootmnt = NULL;
|
||||
@@ -1828,7 +1841,8 @@ char * d_path_flags(struct dentry *dentr
|
||||
read_unlock(¤t->fs->lock);
|
||||
}
|
||||
spin_lock(&dcache_lock);
|
||||
- res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen, flags);
|
||||
+ res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen, flags,
|
||||
+ pconds);
|
||||
spin_unlock(&dcache_lock);
|
||||
if (!(flags & DPATH_NSROOT)) {
|
||||
dput(root);
|
||||
@@ -1858,6 +1872,7 @@ char * d_path_flags(struct dentry *dentr
|
||||
asmlinkage long sys_getcwd(char __user *buf, unsigned long size)
|
||||
{
|
||||
int error;
|
||||
+ unsigned int conds;
|
||||
struct vfsmount *pwdmnt, *rootmnt;
|
||||
struct dentry *pwd, *root;
|
||||
char *page = (char *) __get_free_page(GFP_USER);
|
||||
@@ -1880,7 +1895,7 @@ asmlinkage long sys_getcwd(char __user *
|
||||
char * cwd;
|
||||
|
||||
cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE,
|
||||
- DPATH_DELETED);
|
||||
+ DPATH_DELETED, &conds);
|
||||
spin_unlock(&dcache_lock);
|
||||
|
||||
error = PTR_ERR(cwd);
|
||||
Index: linux-2.6.19.1/include/linux/dcache.h
|
||||
===================================================================
|
||||
--- linux-2.6.19.1.orig/include/linux/dcache.h
|
||||
+++ linux-2.6.19.1/include/linux/dcache.h
|
||||
@@ -297,10 +297,10 @@ extern struct dentry * d_hash_and_lookup
|
||||
/* validate "insecure" dentry pointer */
|
||||
extern int d_validate(struct dentry *, struct dentry *);
|
||||
|
||||
-#define d_path(D, V, B, BL) d_path_flags(D, V, B, BL, DPATH_DELETED)
|
||||
+#define d_path(D, V, B, BL) d_path_flags(D, V, B, BL, DPATH_DELETED, NULL)
|
||||
|
||||
extern char * d_path_flags(struct dentry *, struct vfsmount *, char *, int,
|
||||
- unsigned int);
|
||||
+ unsigned int, unsigned int *);
|
||||
|
||||
/* Allocation counts.. */
|
||||
|
85
kernel-patches/for-mainline/security_chroot.diff
Normal file
85
kernel-patches/for-mainline/security_chroot.diff
Normal file
|
@ -0,0 +1,85 @@
|
|||
Index: linux-2.6.19.1/fs/open.c
|
||||
===================================================================
|
||||
--- linux-2.6.19.1.orig/fs/open.c
|
||||
+++ linux-2.6.19.1/fs/open.c
|
||||
@@ -483,6 +483,10 @@ asmlinkage long sys_chroot(const char __
|
||||
if (!capable(CAP_SYS_CHROOT))
|
||||
goto dput_and_out;
|
||||
|
||||
+ error = security_chroot(&nd);
|
||||
+ if (error)
|
||||
+ goto dput_and_out;
|
||||
+
|
||||
set_fs_root(current->fs, nd.mnt, nd.dentry);
|
||||
set_fs_altroot();
|
||||
error = 0;
|
||||
Index: linux-2.6.19.1/include/linux/security.h
|
||||
===================================================================
|
||||
--- linux-2.6.19.1.orig/include/linux/security.h
|
||||
+++ linux-2.6.19.1/include/linux/security.h
|
||||
@@ -247,6 +247,9 @@ struct request_sock;
|
||||
* Update module state after a successful pivot.
|
||||
* @old_nd contains the nameidata structure for the old root.
|
||||
* @new_nd contains the nameidata structure for the new root.
|
||||
+ * @sb_chroot:
|
||||
+ * Check permission before chroot to chroot to point named by @nd
|
||||
+ * @nd contains the nameidata object for the new root
|
||||
*
|
||||
* Security hooks for inode operations.
|
||||
*
|
||||
@@ -1219,6 +1222,7 @@ struct security_operations {
|
||||
struct nameidata * new_nd);
|
||||
void (*sb_post_pivotroot) (struct nameidata * old_nd,
|
||||
struct nameidata * new_nd);
|
||||
+ int (*sb_chroot) (struct nameidata * nd);
|
||||
|
||||
int (*inode_alloc_security) (struct inode *inode);
|
||||
void (*inode_free_security) (struct inode *inode);
|
||||
@@ -1617,6 +1621,11 @@ static inline void security_sb_post_pivo
|
||||
security_ops->sb_post_pivotroot (old_nd, new_nd);
|
||||
}
|
||||
|
||||
+static inline int security_chroot (struct nameidata *nd)
|
||||
+{
|
||||
+ return security_ops->sb_chroot (nd);
|
||||
+}
|
||||
+
|
||||
static inline int security_inode_alloc (struct inode *inode)
|
||||
{
|
||||
inode->i_security = NULL;
|
||||
@@ -2367,6 +2376,11 @@ static inline void security_sb_post_pivo
|
||||
struct nameidata *new_nd)
|
||||
{ }
|
||||
|
||||
+static inline int security_sb_chroot (struct nameidata *nd)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static inline int security_inode_alloc (struct inode *inode)
|
||||
{
|
||||
return 0;
|
||||
Index: linux-2.6.19.1/security/dummy.c
|
||||
===================================================================
|
||||
--- linux-2.6.19.1.orig/security/dummy.c
|
||||
+++ linux-2.6.19.1/security/dummy.c
|
||||
@@ -248,6 +248,11 @@ static void dummy_sb_post_pivotroot (str
|
||||
return;
|
||||
}
|
||||
|
||||
+static int dummy_sb_chroot (struct nameidata *nd)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int dummy_inode_alloc_security (struct inode *inode)
|
||||
{
|
||||
return 0;
|
||||
@@ -1003,6 +1008,7 @@ void security_fixup_ops (struct security
|
||||
set_to_dummy_if_null(ops, sb_post_addmount);
|
||||
set_to_dummy_if_null(ops, sb_pivotroot);
|
||||
set_to_dummy_if_null(ops, sb_post_pivotroot);
|
||||
+ set_to_dummy_if_null(ops, sb_chroot);
|
||||
set_to_dummy_if_null(ops, inode_alloc_security);
|
||||
set_to_dummy_if_null(ops, inode_free_security);
|
||||
set_to_dummy_if_null(ops, inode_init_security);
|
|
@ -26,6 +26,10 @@ vfs-listxattr.diff
|
|||
security-listxattr.diff
|
||||
vfs-removexattr.diff
|
||||
security-removexattr.diff
|
||||
d_path_flags.diff
|
||||
d_path_namespace_root.diff
|
||||
d_path_return_flags.diff
|
||||
security_chroot.diff
|
||||
apparmor-audit.diff
|
||||
apparmor-intree.diff
|
||||
apparmor.diff
|
||||
|
@ -34,3 +38,8 @@ apparmor-builtinonly.diff
|
|||
apparmor-bootdisable.diff
|
||||
apparmor-twophaseinit.diff
|
||||
apparmor-novalidfstype.diff
|
||||
apparmor-match_perms.diff
|
||||
apparmor-dfa.diff
|
||||
apparmor-percpu_path_cache.diff
|
||||
apparmor-path_resize.diff
|
||||
apparmor-d_path_flags.diff
|
||||
|
|
Loading…
Add table
Reference in a new issue