2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-08-31 14:25:52 +00:00

Some more minor cleanups

This commit is contained in:
Andreas Gruenbacher
2007-02-15 03:46:53 +00:00
parent e4c5a59fa4
commit 597f751050
11 changed files with 661 additions and 438 deletions

View File

@@ -1,169 +0,0 @@
Index: linux-2.6/security/apparmor/apparmor.h
===================================================================
--- linux-2.6.orig/security/apparmor/apparmor.h
+++ linux-2.6/security/apparmor/apparmor.h
@@ -218,7 +218,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/security/apparmor/inline.h
===================================================================
--- linux-2.6.orig/security/apparmor/inline.h
+++ linux-2.6/security/apparmor/inline.h
@@ -214,9 +214,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/security/apparmor/main.c
===================================================================
--- linux-2.6.orig/security/apparmor/main.c
+++ linux-2.6/security/apparmor/main.c
@@ -318,8 +318,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);
@@ -332,7 +333,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;
}
@@ -658,27 +659,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;
@@ -692,6 +703,8 @@ char *aa_get_name(struct dentry *dentry,
}
out:
+ if (order > 0)
+ *addr = buffer;
return name;
}
@@ -766,6 +779,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;
@@ -850,9 +864,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);
@@ -874,8 +889,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;
}
@@ -942,6 +957,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;
@@ -954,7 +970,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;
@@ -1206,7 +1222,7 @@ apply_profile:
}
cleanup:
- aa_put_name(filename);
+ aa_put_name(filename, addr);
put_aaprofile(active);

View File

@@ -1,218 +0,0 @@
Index: linux-2.6/security/apparmor/apparmor.h
===================================================================
--- linux-2.6.orig/security/apparmor/apparmor.h
+++ linux-2.6/security/apparmor/apparmor.h
@@ -197,7 +197,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/security/apparmor/inline.h
===================================================================
--- linux-2.6.orig/security/apparmor/inline.h
+++ linux-2.6/security/apparmor/inline.h
@@ -216,7 +216,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/security/apparmor/lsm.c
===================================================================
--- linux-2.6.orig/security/apparmor/lsm.c
+++ linux-2.6/security/apparmor/lsm.c
@@ -816,6 +816,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;
@@ -830,6 +835,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/security/apparmor/main.c
===================================================================
--- linux-2.6.orig/security/apparmor/main.c
+++ linux-2.6/security/apparmor/main.c
@@ -12,11 +12,132 @@
#include <linux/security.h>
#include <linux/namei.h>
#include <linux/audit.h>
+#include <linux/mm.h>
#include "apparmor.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
@@ -545,7 +666,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;
@@ -557,7 +678,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;

View File

@@ -1,43 +1,87 @@
Index: linux-2.6/fs/dcache.c
Fix __d_path() for lazy unmounts and make it unambiguous
First, when d_path() hits a lazily unmounted mount point, it tries to
prepend the name of the lazily unmounted dentry to the path name. It
gets this wrong, and also overwrites the slash that separates the name
from the following pathname component.
Second, it isn't always possible to tell from the __d_path result
whether the specified root and rootmnt (i.e., the chroot) was reached:
lazy unmounts of bind mounts will produce a path that does start with a
non-slash so we can tell from that, but other lazy unmounts will produce
a path that starts with a slash, just like "ordinary" paths.
Third, sys_getcwd() shouldn't return disconnected paths. The patch
checks for that, and makes it fail with -ENOENT in that case.
The attached patch cleans up __d_path() to fix the bug with overlapping
pathname components. It also adds a @fail_deleted argument, which allows
to get rid of some of the mess in sys_getcwd(). We make sure that paths
will only start with a slash if the path leads all the way up to the
root. If the resulting path would otherwise be empty, we return "."
instead so that some users of seq_path for files in /proc won't break.
The @fail_deleted argument allows sys_getcwd() to be simplified.
Grabbing the dcache_lock can be moved into __d_path().
The @fail_deleted argument could be added to d_path() as well: this would
allow callers to recognize deleted files without having to resort to the
ambiguous check for the " (deleted)" string at the end of the pathnames.
This is not currently done, but it might be worthwhile.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Reviewed-by: NeilBrown <neilb@suse.de>
Index: b/fs/dcache.c
===================================================================
--- linux-2.6.orig/fs/dcache.c
+++ linux-2.6/fs/dcache.c
@@ -1739,45 +1739,43 @@ shouldnt_be_hashed:
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1732,52 +1732,51 @@ shouldnt_be_hashed:
}
/**
- * d_path - return the path of a dentry
+ * __d_path - return the path of a dentry
* @dentry: dentry to report
* @vfsmnt: vfsmnt to which the dentry belongs
* @root: root dentry
* @rootmnt: vfsmnt to which the root dentry belongs
* @buffer: buffer to return value in
* @buflen: buffer length
+ * @fail_deleted: what to return when hitting a deleted dentry
+ * @fail_deleted: what to return for deleted files
*
- * Convert a dentry into an ASCII path name. If the entry has been deleted
- * the string " (deleted)" is appended. Note that this is ambiguous.
+ * Convert a dentry into an ASCII path name. If the entry has been deleted,
+ * then if @fail_deleted is true, ERR_PTR(-ENOENT) is returned. Otherwise,
+ * the the string " (deleted)" is appended. Note that this is ambiguous.
* the string " (deleted)" is appended. Note that this is ambiguous.
*
- * Returns the buffer or an error code if the path was too long.
- *
+ * If @dentry is not connected to @root, the path returned will be relative
+ * (i.e., it will not start with a slash).
*
- * "buflen" should be positive. Caller holds the dcache_lock.
+ * Returns the buffer or an error code.
*/
-static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
- struct dentry *root, struct vfsmount *rootmnt,
- char *buffer, int buflen)
-{
- char * end = buffer+buflen;
- char * retval;
- int namelen;
+static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
+ struct dentry *root, struct vfsmount *rootmnt,
+ char *buffer, int buflen, int fail_deleted)
{
- char * end = buffer+buflen;
- char * retval;
+ char *end = buffer + buflen - 1;
int namelen;
- *--end = '\0';
+ buffer = end;
+{
+ int namelen, is_slash;
+
+ if (buflen < 2)
+ return ERR_PTR(-ENAMETOOLONG);
+ *end = '\0';
buflen--;
+
+ buffer += --buflen;
+ *buffer = '\0';
- *--end = '\0';
- buflen--;
+ spin_lock(&dcache_lock);
if (!IS_ROOT(dentry) && d_unhashed(dentry)) {
- buflen -= 10;
@@ -72,26 +116,26 @@ Index: linux-2.6/fs/dcache.c
spin_lock(&vfsmount_lock);
if (vfsmnt->mnt_parent == vfsmnt) {
spin_unlock(&vfsmount_lock);
@@ -1791,33 +1789,49 @@ static char * __d_path( struct dentry *d
@@ -1791,33 +1790,63 @@ static char * __d_path( struct dentry *d
parent = dentry->d_parent;
prefetch(parent);
namelen = dentry->d_name.len;
- buflen -= namelen + 1;
- if (buflen < 0)
+ if (buflen <= namelen)
+ if (buflen < namelen + 1)
goto Elong;
- end -= namelen;
- memcpy(end, dentry->d_name.name, namelen);
- *--end = '/';
- retval = end;
+ buflen -= namelen + 1;
+ buffer -= namelen;
+ buffer -= namelen + 1;
+ memcpy(buffer, dentry->d_name.name, namelen);
+ *--buffer = '/';
+ *buffer = '/';
dentry = parent;
}
+ /* Get '/' right */
+ if (buffer == end)
+ /* Get '/' right. */
+ if (*buffer != '/')
+ *--buffer = '/';
- return retval;
@@ -101,27 +145,40 @@ Index: linux-2.6/fs/dcache.c
global_root:
+ /*
+ * We went past the (vfsmount, dentry) we were loking for and have
+ * either hit a root dentry, a lazily unmounted dentry, or an
+ * unconnected dentry. Make sure we won't return a pathname rooted
+ * in '/'.
+ * We went past the (vfsmount, dentry) we were looking for and have
+ * either hit a root dentry, a lazily unmounted dentry, an
+ * unconnected dentry, or the file is on a pseudo filesystem.
+ */
namelen = dentry->d_name.len;
- buflen -= namelen;
- if (buflen < 0)
- goto Elong;
+ is_slash = (namelen == 1 && *dentry->d_name.name == '/');
+ if (is_slash || (dentry->d_sb->s_flags & MS_NOUSER)) {
+ /*
+ * Make sure we won't return a pathname starting with '/'.
+ *
+ * Historically, we also glue together the root dentry and
+ * remaining name for pseudo filesystems like pipefs, which
+ * have the MS_NOUSER flag set. This results in pathnames
+ * like "pipe:[439336]".
+ */
+ if (*buffer == '/') {
+ buffer++;
+ buflen++;
+ }
+ if (is_slash) {
+ if (*buffer == '\0')
+ *--buffer = '.';
+ goto out;
+ }
+ }
+ if (buflen < namelen)
goto Elong;
- retval -= namelen-1; /* hit the slash */
- memcpy(retval, dentry->d_name.name, namelen);
- return retval;
+ if (namelen == 1 && *dentry->d_name.name == '/') {
+ if (buffer != end)
+ buffer++;
+ } else {
+ if (buflen < namelen)
+ goto Elong;
+ buffer -= namelen;
+ memcpy(buffer, dentry->d_name.name, namelen);
+ }
+ buffer -= namelen;
+ memcpy(buffer, dentry->d_name.name, namelen);
+ goto out;
+
Elong:
@@ -138,7 +195,7 @@ Index: linux-2.6/fs/dcache.c
{
char *res;
struct vfsmount *rootmnt;
@@ -1827,9 +1841,7 @@ char * d_path(struct dentry *dentry, str
@@ -1827,9 +1856,7 @@ char * d_path(struct dentry *dentry, str
rootmnt = mntget(current->fs->rootmnt);
root = dget(current->fs->root);
read_unlock(&current->fs->lock);
@@ -149,7 +206,7 @@ Index: linux-2.6/fs/dcache.c
dput(root);
mntput(rootmnt);
return res;
@@ -1855,10 +1867,10 @@ char * d_path(struct dentry *dentry, str
@@ -1855,10 +1882,10 @@ char * d_path(struct dentry *dentry, str
*/
asmlinkage long sys_getcwd(char __user *buf, unsigned long size)
{
@@ -162,11 +219,15 @@ Index: linux-2.6/fs/dcache.c
if (!page)
return -ENOMEM;
@@ -1870,29 +1882,18 @@ asmlinkage long sys_getcwd(char __user *
@@ -1870,29 +1897,21 @@ asmlinkage long sys_getcwd(char __user *
root = dget(current->fs->root);
read_unlock(&current->fs->lock);
- error = -ENOENT;
+ cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE, 1);
+ error = PTR_ERR(cwd);
+ if (IS_ERR(cwd))
+ goto out;
error = -ENOENT;
- /* Has the current directory has been unlinked? */
- spin_lock(&dcache_lock);
- if (pwd->d_parent == pwd || !d_unhashed(pwd)) {
@@ -179,7 +240,9 @@ Index: linux-2.6/fs/dcache.c
- error = PTR_ERR(cwd);
- if (IS_ERR(cwd))
- goto out;
-
+ if (*cwd != '/')
+ goto out;
- error = -ERANGE;
- len = PAGE_SIZE + page - cwd;
- if (len <= size) {
@@ -189,11 +252,6 @@ Index: linux-2.6/fs/dcache.c
- }
- } else
- spin_unlock(&dcache_lock);
+ cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE, 1);
+ error = PTR_ERR(cwd);
+ if (IS_ERR(cwd))
+ goto out;
+
+ error = -ERANGE;
+ len = PAGE_SIZE + page - cwd;
+ if (len <= size) {

View File

@@ -0,0 +1,92 @@
Index: b/security/apparmor/match.c
===================================================================
--- a/security/apparmor/match.c
+++ b/security/apparmor/match.c
@@ -160,7 +160,7 @@ int verify_dfa(struct aa_dfa *dfa)
if (trans_count != dfa->tables[YYTD_ID_CHK - 1]->td_lolen)
goto out;
- /* if equivalence classes then its table must be 256 */
+ /* if equivalence classes then its table size must be 256 */
if (dfa->tables[YYTD_ID_EC - 1] &&
dfa->tables[YYTD_ID_EC - 1]->td_lolen != 256)
goto out;
@@ -201,67 +201,46 @@ void aa_match_free(struct aa_dfa *dfa)
}
/**
- * 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_dfa_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
*
* aa_dfa_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.
+ * finished matching in. The final state is used to look up the accepting
+ * label.
*/
-inline unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int state,
- const char *path)
+inline unsigned int aa_dfa_match(struct aa_dfa *dfa, const char *str)
{
- 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;
+ unsigned int state = 1, pos;
- /* current state is <state>, matching character *s */
+ /* current state is <state>, matching character *str */
if (dfa->tables[YYTD_ID_EC - 1]) {
u8 *equiv = EQUIV_TABLE(dfa);
- for ( ; *s; ++s) {
- pos = base[state] + equiv[*s];
+ while (*str) {
+ pos = base[state] + equiv[(u8)*str++];
if (check[pos] == state)
state = next[pos];
else
state = def[state];
}
} else {
- for ( ; *s; ++s) {
- pos = base[state] + *s;
+ while (*str) {
+ pos = base[state] + (u8)*str++;
if (check[pos] == state)
state = next[pos];
else
state = def[state];
}
}
- return state;
+ return ACCEPT_TABLE(dfa)[state];
}
unsigned int aa_match(struct aa_dfa *dfa, const char *pathname)
{
- if (dfa)
- return aadfa_label(dfa, aa_dfa_match(dfa, 1, pathname));
-
- return 0;
+ return dfa ? aa_dfa_match(dfa, pathname) : 0;
}

View File

@@ -0,0 +1,52 @@
Remove some remains of the matcher modules.
Index: b/security/apparmor/apparmor.h
===================================================================
--- a/security/apparmor/apparmor.h
+++ b/security/apparmor/apparmor.h
@@ -278,7 +278,6 @@ struct aa_dfa *aa_match_alloc(void);
void aa_match_free(struct aa_dfa *dfa);
int unpack_dfa(struct aa_dfa *dfa, void *blob, size_t size);
int verify_dfa(struct aa_dfa *dfa);
-const char *aa_match_features(void);
unsigned int aa_match(struct aa_dfa *dfa, const char *pathname);
#endif /* __APPARMOR_H */
Index: b/security/apparmor/apparmorfs.c
===================================================================
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -141,7 +141,7 @@ static int aa_prof_release(struct inode
static ssize_t aa_matching_read(struct file *file, char __user *buf,
size_t size, loff_t *ppos)
{
- const char *matching = aa_match_features();
+ const char *matching = "pattern=aadfa";
return simple_read_from_buffer(buf, size, ppos, matching,
strlen(matching));
Index: b/security/apparmor/match.c
===================================================================
--- a/security/apparmor/match.c
+++ b/security/apparmor/match.c
@@ -16,8 +16,6 @@
#include <linux/module.h>
#include "match.h"
-static const char *features="pattern=aadfa";
-
static struct table_header *unpack_table(void *blob, size_t bsize)
{
struct table_header *table = NULL;
@@ -202,11 +200,6 @@ void aa_match_free(struct aa_dfa *dfa)
kfree(dfa);
}
-const char *aa_match_features(void)
-{
- return features;
-}
-
/**
* aadfa_label - return the permissions associated with @state
* @dfa: dfa to get state permission from

View File

@@ -0,0 +1,181 @@
Hide unreachable mount points in /proc/mounts and /proc/$PID/mountstats
What's mounted on unreachable mount points isn't interesting to
processes: they can't get there in the first place. This patch hides
unreachable mounts from processes.
Processes living in the root namespace whill still see all mounts they
were seeing before except for the rootfs mount, which is never reachable
from an "ordinary" process.
Only the initial initrd init process will actually have access to the
rootfs mount. For this process that mount *is* reachable, and so it will
show in.
This patch also removes some code duplication between mounts_open() and
mountstats_open().
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Index: b/fs/namespace.c
===================================================================
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -348,8 +348,16 @@ static inline void mangle(struct seq_fil
seq_escape(m, s, " \t\n\\");
}
+/* Keep in sync with fs/proc/base.c! */
+struct proc_mounts {
+ struct seq_file m;
+ void *page;
+ int event;
+};
+
static int show_vfsmnt(struct seq_file *m, void *v)
{
+ void *page = container_of(m, struct proc_mounts, m)->page;
struct vfsmount *mnt = v;
int err = 0;
static struct proc_fs_info {
@@ -372,9 +380,13 @@ static int show_vfsmnt(struct seq_file *
};
struct proc_fs_info *fs_infop;
+ char *path = d_path(mnt->mnt_root, mnt, page, PAGE_SIZE);
+ if (IS_ERR(path) || *path != '/')
+ return err;
+
mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none");
seq_putc(m, ' ');
- seq_path(m, mnt, mnt->mnt_root, " \t\n\\");
+ mangle(m, path);
seq_putc(m, ' ');
mangle(m, mnt->mnt_sb->s_type->name);
seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? " ro" : " rw");
@@ -401,9 +413,14 @@ struct seq_operations mounts_op = {
static int show_vfsstat(struct seq_file *m, void *v)
{
+ void *page = container_of(m, struct proc_mounts, m)->page;
struct vfsmount *mnt = v;
int err = 0;
+ char *path = d_path(mnt->mnt_root, mnt, page, PAGE_SIZE);
+ if (IS_ERR(path) || *path != '/')
+ return err; /* error or path unreachable from chroot */
+
/* device */
if (mnt->mnt_devname) {
seq_puts(m, "device ");
@@ -413,7 +430,7 @@ static int show_vfsstat(struct seq_file
/* mount point */
seq_puts(m, " mounted on ");
- seq_path(m, mnt, mnt->mnt_root, " \t\n\\");
+ mangle(m, path);
seq_putc(m, ' ');
/* file system type */
Index: b/fs/proc/base.c
===================================================================
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -356,13 +356,16 @@ static const struct inode_operations pro
.setattr = proc_setattr,
};
+/* Keep in sync with fs/namespace.c! */
extern struct seq_operations mounts_op;
struct proc_mounts {
struct seq_file m;
+ void *page;
int event;
};
-static int mounts_open(struct inode *inode, struct file *file)
+static int __mounts_open(struct inode *inode, struct file *file,
+ struct seq_operations *seq_ops)
{
struct task_struct *task = get_proc_task(inode);
struct mnt_namespace *ns = NULL;
@@ -385,12 +388,16 @@ static int mounts_open(struct inode *ino
p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL);
if (p) {
file->private_data = &p->m;
- ret = seq_open(file, &mounts_op);
+ p->page = (void *)__get_free_page(GFP_KERNEL);
+ if (p->page)
+ ret = seq_open(file, seq_ops);
if (!ret) {
p->m.private = ns;
p->event = ns->event;
return 0;
}
+ if (p->page)
+ free_page((unsigned long)p->page);
kfree(p);
}
put_mnt_ns(ns);
@@ -398,17 +405,25 @@ static int mounts_open(struct inode *ino
return ret;
}
+static int mounts_open(struct inode *inode, struct file *file)
+{
+ return __mounts_open(inode, file, &mounts_op);
+}
+
static int mounts_release(struct inode *inode, struct file *file)
{
- struct seq_file *m = file->private_data;
- struct mnt_namespace *ns = m->private;
+ struct proc_mounts *p =
+ container_of(file->private_data, struct proc_mounts, m);
+ struct mnt_namespace *ns = p->m.private;
+ free_page((unsigned long)p->page);
put_mnt_ns(ns);
return seq_release(inode, file);
}
static unsigned mounts_poll(struct file *file, poll_table *wait)
{
- struct proc_mounts *p = file->private_data;
+ struct proc_mounts *p =
+ container_of(file->private_data, struct proc_mounts, m);
struct mnt_namespace *ns = p->m.private;
unsigned res = 0;
@@ -435,31 +450,7 @@ static const struct file_operations proc
extern struct seq_operations mountstats_op;
static int mountstats_open(struct inode *inode, struct file *file)
{
- int ret = seq_open(file, &mountstats_op);
-
- if (!ret) {
- struct seq_file *m = file->private_data;
- struct mnt_namespace *mnt_ns = NULL;
- struct task_struct *task = get_proc_task(inode);
-
- if (task) {
- task_lock(task);
- if (task->nsproxy)
- mnt_ns = task->nsproxy->mnt_ns;
- if (mnt_ns)
- get_mnt_ns(mnt_ns);
- task_unlock(task);
- put_task_struct(task);
- }
-
- if (mnt_ns)
- m->private = mnt_ns;
- else {
- seq_release(inode, file);
- ret = -EINVAL;
- }
- }
- return ret;
+ return __mounts_open(inode, file, &mountstats_op);
}
static const struct file_operations proc_mountstats_operations = {

View File

@@ -0,0 +1,72 @@
Reintroduce revalidation.
Index: b/security/apparmor/lsm.c
===================================================================
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -445,6 +445,55 @@ static int apparmor_inode_removexattr(st
MAY_WRITE);
}
+static int apparmor_file_permission(struct file *file, int mask)
+{
+ struct aa_profile *profile;
+ struct aa_profile *file_profile = (struct aa_profile*)file->f_security;
+ int error = 0;
+
+ if (!file_profile)
+ goto out;
+
+ /*
+ * If this file was opened under a different profile, we
+ * revalidate the access against the current profile.
+ */
+ profile = aa_get_profile(current);
+ if (profile && file_profile != profile) {
+ struct dentry *dentry = file->f_dentry;
+ struct vfsmount *mnt = file->f_vfsmnt;
+
+ /*
+ * FIXME: We should remember which profiles we revalidated
+ * against.
+ */
+ mask &= (MAY_READ | MAY_WRITE | MAY_EXEC);
+ error = aa_permission(dentry->d_inode, dentry, mnt, mask, 1);
+ }
+ aa_put_profile(profile);
+
+out:
+ return error;
+}
+
+static int apparmor_file_alloc_security(struct file *file)
+{
+ struct aa_profile *profile;
+
+ profile = aa_get_profile(current);
+ if (profile)
+ file->f_security = profile;
+
+ return 0;
+}
+
+static void apparmor_file_free_security(struct file *file)
+{
+ struct aa_profile *file_profile = (struct aa_profile*)file->f_security;
+
+ aa_put_profile(file_profile);
+}
+
static inline int aa_mmap(struct file *file, unsigned long prot,
unsigned long flags)
{
@@ -668,6 +717,9 @@ struct security_operations apparmor_ops
.inode_getxattr = apparmor_inode_getxattr,
.inode_listxattr = apparmor_inode_listxattr,
.inode_removexattr = apparmor_inode_removexattr,
+ .file_permission = apparmor_file_permission,
+ .file_alloc_security = apparmor_file_alloc_security,
+ .file_free_security = apparmor_file_free_security,
.file_mmap = apparmor_file_mmap,
.file_mprotect = apparmor_file_mprotect,

View File

@@ -0,0 +1,25 @@
Index: b/security/apparmor/module_interface.c
===================================================================
--- a/security/apparmor/module_interface.c
+++ b/security/apparmor/module_interface.c
@@ -383,7 +383,7 @@ static struct aa_profile *aa_activate_pr
error_string = "Invalid flags";
/* per profile debug flags (debug, complain, audit) */
AA_READ_X(e, AA_STRUCT, NULL, "flags");
- AA_READ_X(e, AA_U32, &(profile->flags.debug), NULL);
+ AA_READ_X(e, AA_U32, NULL, NULL);
AA_READ_X(e, AA_U32, &(profile->flags.complain), NULL);
AA_READ_X(e, AA_U32, &(profile->flags.audit), NULL);
AA_READ_X(e, AA_STRUCTEND, NULL, NULL);
Index: b/security/apparmor/apparmor.h
===================================================================
--- a/security/apparmor/apparmor.h
+++ b/security/apparmor/apparmor.h
@@ -108,7 +108,6 @@ struct aa_profile {
struct list_head list;
struct list_head sub;
struct {
- int debug;
int complain;
int audit;
} flags;

View File

@@ -0,0 +1,112 @@
Index: b/security/apparmor/list.c
===================================================================
--- a/security/apparmor/list.c
+++ b/security/apparmor/list.c
@@ -15,7 +15,7 @@
/* list of all profiles and lock */
static LIST_HEAD(profile_list);
-static rwlock_t profile_lock = RW_LOCK_UNLOCKED;
+static rwlock_t profile_list_lock = RW_LOCK_UNLOCKED;
/* list of all task_contexts and lock */
static LIST_HEAD(task_context_list);
@@ -32,9 +32,9 @@ struct aa_profile *aa_profilelist_find(c
{
struct aa_profile *p = NULL;
if (name) {
- read_lock(&profile_lock);
+ read_lock(&profile_list_lock);
p = __aa_find_profile(name, &profile_list);
- read_unlock(&profile_lock);
+ read_unlock(&profile_list_lock);
}
return p;
}
@@ -57,7 +57,7 @@ int aa_profilelist_add(struct aa_profile
if (!profile)
goto out;
- write_lock(&profile_lock);
+ write_lock(&profile_list_lock);
old_profile = __aa_find_profile(profile->name, &profile_list);
if (old_profile) {
aa_put_profile(old_profile);
@@ -67,7 +67,7 @@ int aa_profilelist_add(struct aa_profile
list_add(&profile->list, &profile_list);
ret = 1;
out:
- write_unlock(&profile_lock);
+ write_unlock(&profile_list_lock);
return ret;
}
@@ -87,7 +87,7 @@ struct aa_profile *aa_profilelist_remove
if (!name)
goto out;
- write_lock(&profile_lock);
+ write_lock(&profile_list_lock);
list_for_each_entry_safe(p, tmp, &profile_list, list) {
if (!strcmp(p->name, name)) {
list_del_init(&p->list);
@@ -97,7 +97,7 @@ struct aa_profile *aa_profilelist_remove
break;
}
}
- write_unlock(&profile_lock);
+ write_unlock(&profile_list_lock);
out:
return profile;
@@ -118,7 +118,7 @@ struct aa_profile *aa_profilelist_replac
{
struct aa_profile *oldprofile;
- write_lock(&profile_lock);
+ write_lock(&profile_list_lock);
oldprofile = __aa_find_profile(profile->name, &profile_list);
if (oldprofile) {
list_del_init(&oldprofile->list);
@@ -130,7 +130,7 @@ struct aa_profile *aa_profilelist_replac
}
list_add(&profile->list, &profile_list);
- write_unlock(&profile_lock);
+ write_unlock(&profile_list_lock);
return oldprofile;
}
@@ -142,12 +142,12 @@ void aa_profilelist_release(void)
{
struct aa_profile *p, *tmp;
- write_lock(&profile_lock);
+ write_lock(&profile_list_lock);
list_for_each_entry_safe(p, tmp, &profile_list, list) {
list_del_init(&p->list);
aa_put_profile(p);
}
- write_unlock(&profile_lock);
+ write_unlock(&profile_list_lock);
}
/**
@@ -233,7 +233,7 @@ static void *p_start(struct seq_file *f,
struct aa_profile *node;
loff_t l = *pos;
- read_lock(&profile_lock);
+ read_lock(&profile_list_lock);
list_for_each_entry(node, &profile_list, list)
if (!l--)
return node;
@@ -250,7 +250,7 @@ static void *p_next(struct seq_file *f,
static void p_stop(struct seq_file *f, void *v)
{
- read_unlock(&profile_lock);
+ read_unlock(&profile_list_lock);
}
static int seq_show_profile(struct seq_file *f, void *v)

View File

@@ -27,6 +27,7 @@ security-listxattr.diff
vfs-removexattr.diff
security-removexattr.diff
d_path-lazy-unmounts.diff
no-unreachable-paths.diff
# security_chroot.diff
apparmor-audit.diff
apparmor-intree.diff
@@ -58,5 +59,9 @@ d_namespace_path.diff
apparmor-d_namespace.diff
alloc-pathnames.diff
# fix-change_hat.diff
# apparmor-percpu_path_cache.diff
# apparmor-path_resize.diff
typo.diff
reintroduce-revalidation.diff
remove-debug-flag.diff
rename-profile-lock.diff
match-features.diff
match-changes.diff

View File

@@ -0,0 +1,13 @@
Index: b/security/apparmor/main.c
===================================================================
--- a/security/apparmor/main.c
+++ b/security/apparmor/main.c
@@ -1087,7 +1087,7 @@ void aa_release(struct task_struct *task
/**
* do_change_hat - actually switch hats
- * @hat_name: name of hat to swtich to
+ * @hat_name: name of hat to switch to
* @cxt: current aa_task_context
*
* Switch to a new hat. Return %0 on success, error otherwise.