mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-09-03 15:55:46 +00:00
Some more minor cleanups
This commit is contained in:
@@ -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);
|
|
||||||
|
|
@@ -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;
|
|
@@ -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
|
--- a/fs/dcache.c
|
||||||
+++ linux-2.6/fs/dcache.c
|
+++ b/fs/dcache.c
|
||||||
@@ -1739,45 +1739,43 @@ shouldnt_be_hashed:
|
@@ -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
|
* @rootmnt: vfsmnt to which the root dentry belongs
|
||||||
* @buffer: buffer to return value in
|
* @buffer: buffer to return value in
|
||||||
* @buflen: buffer length
|
* @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
|
- * 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,
|
+ * 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,
|
+ * 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.
|
- * 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.
|
- * "buflen" should be positive. Caller holds the dcache_lock.
|
||||||
+ * Returns the buffer or an error code.
|
+ * Returns the buffer or an error code.
|
||||||
*/
|
*/
|
||||||
-static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
|
-static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
|
||||||
- struct dentry *root, struct vfsmount *rootmnt,
|
- struct dentry *root, struct vfsmount *rootmnt,
|
||||||
- char *buffer, int buflen)
|
- char *buffer, int buflen)
|
||||||
|
-{
|
||||||
|
- char * end = buffer+buflen;
|
||||||
|
- char * retval;
|
||||||
|
- int namelen;
|
||||||
+static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
|
+static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
|
||||||
+ struct dentry *root, struct vfsmount *rootmnt,
|
+ struct dentry *root, struct vfsmount *rootmnt,
|
||||||
+ char *buffer, int buflen, int fail_deleted)
|
+ char *buffer, int buflen, int fail_deleted)
|
||||||
{
|
+{
|
||||||
- char * end = buffer+buflen;
|
+ int namelen, is_slash;
|
||||||
- char * retval;
|
+
|
||||||
+ char *end = buffer + buflen - 1;
|
|
||||||
int namelen;
|
|
||||||
|
|
||||||
- *--end = '\0';
|
|
||||||
+ buffer = end;
|
|
||||||
+ if (buflen < 2)
|
+ if (buflen < 2)
|
||||||
+ return ERR_PTR(-ENAMETOOLONG);
|
+ return ERR_PTR(-ENAMETOOLONG);
|
||||||
+ *end = '\0';
|
+ buffer += --buflen;
|
||||||
buflen--;
|
+ *buffer = '\0';
|
||||||
+
|
|
||||||
|
- *--end = '\0';
|
||||||
|
- buflen--;
|
||||||
+ spin_lock(&dcache_lock);
|
+ spin_lock(&dcache_lock);
|
||||||
if (!IS_ROOT(dentry) && d_unhashed(dentry)) {
|
if (!IS_ROOT(dentry) && d_unhashed(dentry)) {
|
||||||
- buflen -= 10;
|
- buflen -= 10;
|
||||||
@@ -72,26 +116,26 @@ Index: linux-2.6/fs/dcache.c
|
|||||||
spin_lock(&vfsmount_lock);
|
spin_lock(&vfsmount_lock);
|
||||||
if (vfsmnt->mnt_parent == vfsmnt) {
|
if (vfsmnt->mnt_parent == vfsmnt) {
|
||||||
spin_unlock(&vfsmount_lock);
|
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;
|
parent = dentry->d_parent;
|
||||||
prefetch(parent);
|
prefetch(parent);
|
||||||
namelen = dentry->d_name.len;
|
namelen = dentry->d_name.len;
|
||||||
- buflen -= namelen + 1;
|
- buflen -= namelen + 1;
|
||||||
- if (buflen < 0)
|
- if (buflen < 0)
|
||||||
+ if (buflen <= namelen)
|
+ if (buflen < namelen + 1)
|
||||||
goto Elong;
|
goto Elong;
|
||||||
- end -= namelen;
|
- end -= namelen;
|
||||||
- memcpy(end, dentry->d_name.name, namelen);
|
- memcpy(end, dentry->d_name.name, namelen);
|
||||||
- *--end = '/';
|
- *--end = '/';
|
||||||
- retval = end;
|
- retval = end;
|
||||||
+ buflen -= namelen + 1;
|
+ buflen -= namelen + 1;
|
||||||
+ buffer -= namelen;
|
+ buffer -= namelen + 1;
|
||||||
+ memcpy(buffer, dentry->d_name.name, namelen);
|
+ memcpy(buffer, dentry->d_name.name, namelen);
|
||||||
+ *--buffer = '/';
|
+ *buffer = '/';
|
||||||
dentry = parent;
|
dentry = parent;
|
||||||
}
|
}
|
||||||
+ /* Get '/' right */
|
+ /* Get '/' right. */
|
||||||
+ if (buffer == end)
|
+ if (*buffer != '/')
|
||||||
+ *--buffer = '/';
|
+ *--buffer = '/';
|
||||||
|
|
||||||
- return retval;
|
- return retval;
|
||||||
@@ -101,27 +145,40 @@ Index: linux-2.6/fs/dcache.c
|
|||||||
|
|
||||||
global_root:
|
global_root:
|
||||||
+ /*
|
+ /*
|
||||||
+ * We went past the (vfsmount, dentry) we were loking for and have
|
+ * We went past the (vfsmount, dentry) we were looking for and have
|
||||||
+ * either hit a root dentry, a lazily unmounted dentry, or an
|
+ * either hit a root dentry, a lazily unmounted dentry, an
|
||||||
+ * unconnected dentry. Make sure we won't return a pathname rooted
|
+ * unconnected dentry, or the file is on a pseudo filesystem.
|
||||||
+ * in '/'.
|
|
||||||
+ */
|
+ */
|
||||||
namelen = dentry->d_name.len;
|
namelen = dentry->d_name.len;
|
||||||
- buflen -= namelen;
|
- buflen -= namelen;
|
||||||
- if (buflen < 0)
|
- 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 */
|
- retval -= namelen-1; /* hit the slash */
|
||||||
- memcpy(retval, dentry->d_name.name, namelen);
|
- memcpy(retval, dentry->d_name.name, namelen);
|
||||||
- return retval;
|
- return retval;
|
||||||
+ if (namelen == 1 && *dentry->d_name.name == '/') {
|
+ buffer -= namelen;
|
||||||
+ if (buffer != end)
|
+ memcpy(buffer, dentry->d_name.name, namelen);
|
||||||
+ buffer++;
|
|
||||||
+ } else {
|
|
||||||
+ if (buflen < namelen)
|
|
||||||
+ goto Elong;
|
|
||||||
+ buffer -= namelen;
|
|
||||||
+ memcpy(buffer, dentry->d_name.name, namelen);
|
|
||||||
+ }
|
|
||||||
+ goto out;
|
+ goto out;
|
||||||
+
|
+
|
||||||
Elong:
|
Elong:
|
||||||
@@ -138,7 +195,7 @@ Index: linux-2.6/fs/dcache.c
|
|||||||
{
|
{
|
||||||
char *res;
|
char *res;
|
||||||
struct vfsmount *rootmnt;
|
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);
|
rootmnt = mntget(current->fs->rootmnt);
|
||||||
root = dget(current->fs->root);
|
root = dget(current->fs->root);
|
||||||
read_unlock(¤t->fs->lock);
|
read_unlock(¤t->fs->lock);
|
||||||
@@ -149,7 +206,7 @@ Index: linux-2.6/fs/dcache.c
|
|||||||
dput(root);
|
dput(root);
|
||||||
mntput(rootmnt);
|
mntput(rootmnt);
|
||||||
return res;
|
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)
|
asmlinkage long sys_getcwd(char __user *buf, unsigned long size)
|
||||||
{
|
{
|
||||||
@@ -162,11 +219,15 @@ Index: linux-2.6/fs/dcache.c
|
|||||||
|
|
||||||
if (!page)
|
if (!page)
|
||||||
return -ENOMEM;
|
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);
|
root = dget(current->fs->root);
|
||||||
read_unlock(¤t->fs->lock);
|
read_unlock(¤t->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? */
|
- /* Has the current directory has been unlinked? */
|
||||||
- spin_lock(&dcache_lock);
|
- spin_lock(&dcache_lock);
|
||||||
- if (pwd->d_parent == pwd || !d_unhashed(pwd)) {
|
- if (pwd->d_parent == pwd || !d_unhashed(pwd)) {
|
||||||
@@ -179,7 +240,9 @@ Index: linux-2.6/fs/dcache.c
|
|||||||
- error = PTR_ERR(cwd);
|
- error = PTR_ERR(cwd);
|
||||||
- if (IS_ERR(cwd))
|
- if (IS_ERR(cwd))
|
||||||
- goto out;
|
- goto out;
|
||||||
-
|
+ if (*cwd != '/')
|
||||||
|
+ goto out;
|
||||||
|
|
||||||
- error = -ERANGE;
|
- error = -ERANGE;
|
||||||
- len = PAGE_SIZE + page - cwd;
|
- len = PAGE_SIZE + page - cwd;
|
||||||
- if (len <= size) {
|
- if (len <= size) {
|
||||||
@@ -189,11 +252,6 @@ Index: linux-2.6/fs/dcache.c
|
|||||||
- }
|
- }
|
||||||
- } else
|
- } else
|
||||||
- spin_unlock(&dcache_lock);
|
- 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;
|
+ error = -ERANGE;
|
||||||
+ len = PAGE_SIZE + page - cwd;
|
+ len = PAGE_SIZE + page - cwd;
|
||||||
+ if (len <= size) {
|
+ if (len <= size) {
|
||||||
|
92
kernel-patches/for-mainline/match-changes.diff
Normal file
92
kernel-patches/for-mainline/match-changes.diff
Normal 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;
|
||||||
|
}
|
52
kernel-patches/for-mainline/match-features.diff
Normal file
52
kernel-patches/for-mainline/match-features.diff
Normal 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
|
181
kernel-patches/for-mainline/no-unreachable-paths.diff
Normal file
181
kernel-patches/for-mainline/no-unreachable-paths.diff
Normal 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 = {
|
72
kernel-patches/for-mainline/reintroduce-revalidation.diff
Normal file
72
kernel-patches/for-mainline/reintroduce-revalidation.diff
Normal 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,
|
||||||
|
|
25
kernel-patches/for-mainline/remove-debug-flag.diff
Normal file
25
kernel-patches/for-mainline/remove-debug-flag.diff
Normal 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;
|
112
kernel-patches/for-mainline/rename-profile-lock.diff
Normal file
112
kernel-patches/for-mainline/rename-profile-lock.diff
Normal 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)
|
@@ -27,6 +27,7 @@ security-listxattr.diff
|
|||||||
vfs-removexattr.diff
|
vfs-removexattr.diff
|
||||||
security-removexattr.diff
|
security-removexattr.diff
|
||||||
d_path-lazy-unmounts.diff
|
d_path-lazy-unmounts.diff
|
||||||
|
no-unreachable-paths.diff
|
||||||
# security_chroot.diff
|
# security_chroot.diff
|
||||||
apparmor-audit.diff
|
apparmor-audit.diff
|
||||||
apparmor-intree.diff
|
apparmor-intree.diff
|
||||||
@@ -58,5 +59,9 @@ d_namespace_path.diff
|
|||||||
apparmor-d_namespace.diff
|
apparmor-d_namespace.diff
|
||||||
alloc-pathnames.diff
|
alloc-pathnames.diff
|
||||||
# fix-change_hat.diff
|
# fix-change_hat.diff
|
||||||
# apparmor-percpu_path_cache.diff
|
typo.diff
|
||||||
# apparmor-path_resize.diff
|
reintroduce-revalidation.diff
|
||||||
|
remove-debug-flag.diff
|
||||||
|
rename-profile-lock.diff
|
||||||
|
match-features.diff
|
||||||
|
match-changes.diff
|
||||||
|
13
kernel-patches/for-mainline/typo.diff
Normal file
13
kernel-patches/for-mainline/typo.diff
Normal 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.
|
Reference in New Issue
Block a user