mirror of
https://gitlab.com/apparmor/apparmor.git
synced 2025-03-05 17:01:00 +01:00
233 lines
6.8 KiB
Diff
233 lines
6.8 KiB
Diff
aa_get_name and aa_put_name are only used in main.c. Make them
|
|
static.
|
|
|
|
Use kmalloc() instead of __get_free_page(): it has per-cpu pools;
|
|
that way, we don't need to bother implementing that ourselves.
|
|
|
|
Start out with a 256-byte buffer only: that way, we don't need to
|
|
stress the memory subsystem so much.
|
|
|
|
Allow pathnames to be up to 2 * PAGE_SIZE long: this is an entirely
|
|
arbitrary limit. There is no inherent length limit on pathnames; we
|
|
could allow arbitrarily long paths. This would only allow an attacker
|
|
to cause frequent large memory allocations in the kernel though, and
|
|
this could unnecessarily slow down the system. We don't expect any
|
|
reasonable application to use paths longer than PAGE_SIZE, so twice
|
|
that much should be on the safe side.
|
|
|
|
Index: b/security/apparmor/apparmor.h
|
|
===================================================================
|
|
--- a/security/apparmor/apparmor.h
|
|
+++ b/security/apparmor/apparmor.h
|
|
@@ -41,6 +41,7 @@ extern int apparmor_complain;
|
|
extern int apparmor_debug;
|
|
extern int apparmor_audit;
|
|
extern int apparmor_logsyscall;
|
|
+extern int apparmor_path_max;
|
|
|
|
static inline int mediated_filesystem(struct inode *inode)
|
|
{
|
|
@@ -215,7 +216,6 @@ extern int aa_audit_message(struct aa_pr
|
|
extern int aa_audit_syscallreject(struct aa_profile *profile, gfp_t gfp,
|
|
const char *);
|
|
extern int aa_audit(struct aa_profile *profile, const struct aa_audit *);
|
|
-extern char *aa_get_name(struct dentry *dentry, struct vfsmount *mnt);
|
|
|
|
extern int aa_attr(struct aa_profile *profile, struct dentry *dentry,
|
|
struct vfsmount *mnt, struct iattr *iattr);
|
|
Index: b/security/apparmor/inline.h
|
|
===================================================================
|
|
--- a/security/apparmor/inline.h
|
|
+++ b/security/apparmor/inline.h
|
|
@@ -133,18 +133,6 @@ static inline struct aa_profile *alloc_a
|
|
return profile;
|
|
}
|
|
|
|
-/**
|
|
- * aa_put_name
|
|
- * @name: name to release.
|
|
- *
|
|
- * 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)
|
|
-{
|
|
- free_page((unsigned long)name);
|
|
-}
|
|
-
|
|
/** __aa_find_profile
|
|
* @name: name of profile to find
|
|
* @head: list to search
|
|
Index: b/security/apparmor/main.c
|
|
===================================================================
|
|
--- a/security/apparmor/main.c
|
|
+++ b/security/apparmor/main.c
|
|
@@ -159,12 +159,44 @@ static int aa_link_perm(struct aa_profil
|
|
return ret;
|
|
}
|
|
|
|
+static char *aa_get_pathname(struct dentry *dentry, struct vfsmount *mnt,
|
|
+ char **buffer)
|
|
+{
|
|
+ char *name;
|
|
+ int size = 256;
|
|
+
|
|
+ for (;;) {
|
|
+ char *buf = kmalloc(size, GFP_KERNEL);
|
|
+ if (!buf)
|
|
+ return ERR_PTR(-ENOMEM);
|
|
+
|
|
+ name = d_namespace_path(dentry, mnt, buf, size, 1);
|
|
+ if (!IS_ERR(name)) {
|
|
+ *buffer = buf;
|
|
+ return name;
|
|
+ }
|
|
+ if (PTR_ERR(name) != -ENAMETOOLONG)
|
|
+ return name;
|
|
+
|
|
+ kfree(buf);
|
|
+ size <<= 1;
|
|
+ if (size > apparmor_path_max)
|
|
+ return ERR_PTR(-ENAMETOOLONG);
|
|
+ }
|
|
+}
|
|
+
|
|
+static inline void aa_put_pathname_buffer(char *buffer)
|
|
+{
|
|
+ kfree(buffer);
|
|
+}
|
|
+
|
|
static int _aa_perm_vfsmount(struct aa_profile *profile, struct dentry *dentry,
|
|
struct vfsmount *mnt, struct aa_audit *sa, int mask)
|
|
{
|
|
+ char *buffer = NULL;
|
|
int permerror, error;
|
|
|
|
- sa->name = aa_get_name(dentry, mnt);
|
|
+ sa->name = aa_get_pathname(dentry, mnt, &buffer);
|
|
|
|
if (IS_ERR(sa->name)) {
|
|
permerror = PTR_ERR(sa->name);
|
|
@@ -177,7 +209,7 @@ static int _aa_perm_vfsmount(struct aa_p
|
|
|
|
error = aa_audit(profile, sa);
|
|
|
|
- aa_put_name(sa->name);
|
|
+ aa_put_pathname_buffer(buffer);
|
|
|
|
return error;
|
|
}
|
|
@@ -481,29 +513,6 @@ out:
|
|
return error;
|
|
}
|
|
|
|
-/**
|
|
- * aa_get_name - retrieve fully qualified path name
|
|
- * @dentry: relative path element
|
|
- * @mnt: where in tree
|
|
- *
|
|
- * Returns fully qualified path name on sucess, NULL on failure.
|
|
- * aa_put_name must be used to free the allocated buffer.
|
|
- */
|
|
-char *aa_get_name(struct dentry *dentry, struct vfsmount *mnt)
|
|
-{
|
|
- char *page, *name;
|
|
-
|
|
- page = (char *)__get_free_page(GFP_KERNEL);
|
|
- if (!page)
|
|
- return ERR_PTR(-ENOMEM);
|
|
-
|
|
- name = d_namespace_path(dentry, mnt, page, PAGE_SIZE, 1);
|
|
- if (IS_ERR(name))
|
|
- free_page((unsigned long)page);
|
|
-
|
|
- return name;
|
|
-}
|
|
-
|
|
/***********************************
|
|
* Global permission check functions
|
|
***********************************/
|
|
@@ -670,11 +679,12 @@ int aa_link(struct aa_profile *profile,
|
|
struct dentry *link, struct vfsmount *link_mnt,
|
|
struct dentry *target, struct vfsmount *target_mnt)
|
|
{
|
|
+ char *name_buffer = NULL, *pval_buffer = NULL;
|
|
int permerror = -EPERM, error;
|
|
struct aa_audit sa;
|
|
|
|
- sa.name = aa_get_name(link, link_mnt);
|
|
- sa.pval = aa_get_name(target, target_mnt);
|
|
+ sa.name = aa_get_pathname(link, link_mnt, &name_buffer);
|
|
+ sa.pval = aa_get_pathname(target, target_mnt, &pval_buffer);
|
|
|
|
if (IS_ERR(sa.name)) {
|
|
permerror = PTR_ERR(sa.name);
|
|
@@ -696,8 +706,8 @@ int aa_link(struct aa_profile *profile,
|
|
|
|
error = aa_audit(profile, &sa);
|
|
|
|
- aa_put_name(sa.name);
|
|
- aa_put_name(sa.pval);
|
|
+ aa_put_pathname_buffer(name_buffer);
|
|
+ aa_put_pathname_buffer(pval_buffer);
|
|
|
|
return error;
|
|
}
|
|
@@ -771,7 +781,7 @@ int aa_fork(struct task_struct *task)
|
|
*/
|
|
int aa_register(struct linux_binprm *bprm)
|
|
{
|
|
- char *filename;
|
|
+ char *filename, *filename_buffer = NULL;
|
|
struct file *filp = bprm->file;
|
|
struct aa_profile *profile;
|
|
struct aa_profile *newprofile = NULL, unconstrained_flag;
|
|
@@ -784,7 +794,8 @@ 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_pathname(filp->f_dentry, filp->f_vfsmnt,
|
|
+ &filename_buffer);
|
|
if (IS_ERR(filename)) {
|
|
AA_WARN("%s: Failed to get filename\n", __FUNCTION__);
|
|
goto out;
|
|
@@ -1036,7 +1047,7 @@ apply_profile:
|
|
}
|
|
|
|
cleanup:
|
|
- aa_put_name(filename);
|
|
+ aa_put_pathname_buffer(filename_buffer);
|
|
|
|
aa_put_profile(profile);
|
|
|
|
Index: b/security/apparmor/lsm.c
|
|
===================================================================
|
|
--- a/security/apparmor/lsm.c
|
|
+++ b/security/apparmor/lsm.c
|
|
@@ -54,6 +54,11 @@ int apparmor_logsyscall = 0;
|
|
module_param_named(logsyscall, apparmor_logsyscall, int, S_IRUSR);
|
|
MODULE_PARM_DESC(apparmor_logsyscall, "Toggle AppArmor logsyscall mode");
|
|
|
|
+/* Maximum pathname length before accesses will start getting rejected */
|
|
+int apparmor_path_max = 2 * PATH_MAX;
|
|
+module_param_named(path_max, apparmor_path_max, int, S_IRUSR);
|
|
+MODULE_PARM_DESC(apparmor_path_max, "Maximum pathname length allowed");
|
|
+
|
|
#ifndef MODULE
|
|
static int __init aa_getopt_complain(char *str)
|
|
{
|
|
@@ -82,6 +87,13 @@ static int __init aa_getopt_logsyscall(c
|
|
return 1;
|
|
}
|
|
__setup("apparmor_logsyscall=", aa_getopt_logsyscall);
|
|
+
|
|
+static int __init aa_getopt_path_max(char *str)
|
|
+{
|
|
+ get_option(&str, &apparmor_path_max);
|
|
+ return 1;
|
|
+}
|
|
+__setup("apparmor_path_max=", aa_getopt_path_max);
|
|
#endif
|
|
|
|
static int aa_reject_syscall(struct task_struct *task, gfp_t flags,
|