remove for-mainline dir from kernel patches

This commit is contained in:
John Johansen 2008-05-27 12:04:33 +00:00
parent 446f3fc533
commit ffa6034243
119 changed files with 0 additions and 26841 deletions

View file

@ -1,144 +0,0 @@
From: John Johansen <jjohansen@suse.de>
Subject: Fix __d_path to allow for old and new behavior bnc#380763
Fix __d_path so that it can be told whether or not to connect
disconnect path to the root. This is easier and more efficient
than trying to reconnect these paths for d_path and get_cwd
after the fact.
Signed-off-by: John Johansen <jjohansen@suse.de>
---
fs/dcache.c | 57 ++++++++++++++++++-------------------------------
fs/namespace.c | 2 -
include/linux/dcache.h | 2 -
3 files changed, 24 insertions(+), 37 deletions(-)
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1772,6 +1772,7 @@ shouldnt_be_hashed:
* @buffer: buffer to return value in
* @buflen: buffer length
* @fail_deleted: what to return for deleted files
+ * @disconnect: don't return a path starting with / when disconnected
*
* 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,
@@ -1784,9 +1785,10 @@ shouldnt_be_hashed:
*/
char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
struct dentry *root, struct vfsmount *rootmnt,
- char *buffer, int buflen, int fail_deleted)
+ char *buffer, int buflen, int fail_deleted, int disconnect)
{
- int namelen, is_slash, vfsmount_locked = 0;
+ int namelen, vfsmount_locked = 0;
+ const unsigned char *name;
if (buflen < 2)
return ERR_PTR(-ENAMETOOLONG);
@@ -1847,27 +1849,26 @@ global_root:
* unconnected dentry, or the file is on a pseudo filesystem.
*/
namelen = dentry->d_name.len;
- 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)
- goto out;
+ name = dentry->d_name.name;
+
+ /*
+ * If this is a root dentry, then overwrite the slash. This
+ * will also DTRT with pseudo filesystems which have root
+ * dentries named "foo:".
+ */
+ if (IS_ROOT(dentry)) {
+ buffer++;
+ buflen++;
+ }
+ if (disconnect && *name == '/') {
+ /* Make sure we won't return a pathname starting with '/' */
+ name++;
+ namelen--;
}
if (buflen < namelen)
goto Elong;
buffer -= namelen;
- memcpy(buffer, dentry->d_name.name, namelen);
+ memcpy(buffer, name, namelen);
goto out;
Elong:
@@ -1875,18 +1876,6 @@ Elong:
goto out;
}
-static char *__connect_d_path(char *path, char *buffer)
-{
- if (!IS_ERR(path) && *path != '/') {
- /* Pretend that disconnected paths are hanging off the root. */
- if (path == buffer)
- path = ERR_PTR(-ENAMETOOLONG);
- else
- *--path = '/';
- }
- return path;
-}
-
/* write full pathname into buffer and return start of pathname */
char *d_path(struct dentry *dentry, struct vfsmount *vfsmnt, char *buf,
int buflen)
@@ -1909,8 +1898,7 @@ char *d_path(struct dentry *dentry, stru
rootmnt = mntget(current->fs->rootmnt);
root = dget(current->fs->root);
read_unlock(&current->fs->lock);
- res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen, 0);
- res = __connect_d_path(res, buf);
+ res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen, 0, 0);
dput(root);
mntput(rootmnt);
return res;
@@ -1972,8 +1960,7 @@ asmlinkage long sys_getcwd(char __user *
root = dget(current->fs->root);
read_unlock(&current->fs->lock);
- cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE, 1);
- cwd = __connect_d_path(cwd, page);
+ cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE, 1, 0);
error = PTR_ERR(cwd);
if (IS_ERR(cwd))
goto out;
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1901,7 +1901,7 @@ char *d_namespace_path(struct dentry *de
mntput(rootmnt);
if (nsrootmnt)
root = dget(nsrootmnt->mnt_root);
- res = __d_path(dentry, vfsmnt, root, nsrootmnt, buf, buflen, 1);
+ res = __d_path(dentry, vfsmnt, root, nsrootmnt, buf, buflen, 1, 1);
dput(root);
mntput(nsrootmnt);
/* Prevent empty path for lazily unmounted filesystems. */
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -301,7 +301,7 @@ extern int d_validate(struct dentry *, s
extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...);
extern char *__d_path(struct dentry *, struct vfsmount *, struct dentry *,
- struct vfsmount *, char *, int, int);
+ struct vfsmount *, char *, int, int, int);
extern char * d_path(struct dentry *, struct vfsmount *, char *, int);
/* Allocation counts.. */

View file

@ -1,745 +0,0 @@
---
security/apparmor/apparmor.h | 14 -
security/apparmor/apparmorfs.c | 2
security/apparmor/inline.h | 14 -
security/apparmor/main.c | 490 +++++++++++++++++++----------------
security/apparmor/match.c | 9
security/apparmor/module_interface.c | 10
6 files changed, 309 insertions(+), 230 deletions(-)
--- a/security/apparmor/apparmor.h
+++ b/security/apparmor/apparmor.h
@@ -44,8 +44,7 @@
AA_EXEC_MOD_2 | AA_EXEC_MOD_3 | \
AA_EXEC_MOD_4)
-#define AA_EXEC_TYPE (MAY_EXEC | AA_EXEC_UNSAFE | \
- AA_EXEC_MODIFIERS)
+#define AA_EXEC_TYPE (AA_EXEC_UNSAFE | AA_EXEC_MODIFIERS)
#define AA_EXEC_UNCONFINED AA_EXEC_MOD_0
#define AA_EXEC_INHERIT AA_EXEC_MOD_1
@@ -85,6 +84,10 @@
AA_AUDIT_FIELD)
#define AA_VALID_PERM_MASK (AA_FILE_PERMS | AA_SHARED_PERMS)
+
+/* audit bits for the second accept field */
+#define AUDIT_FILE_MASK 0x1fc07f
+#define AUDIT_QUIET_MASK(mask) ((mask >> 7) & AUDIT_FILE_MASK)
#define AA_VALID_PERM2_MASK 0x0fffffff
#define AA_SECURE_EXEC_NEEDED 1
@@ -179,6 +182,9 @@ struct aa_profile {
int isstale;
kernel_cap_t capabilities;
+ kernel_cap_t audit_caps;
+ kernel_cap_t quiet_caps;
+
struct kref count;
struct list_head task_contexts;
spinlock_t lock;
@@ -226,7 +232,7 @@ struct aa_audit {
const char *name;
const char *name2;
const char *name3;
- int request_mask, denied_mask;
+ int request_mask, denied_mask, audit_mask;
struct iattr *iattr;
pid_t task, parent;
int error_code;
@@ -331,7 +337,7 @@ extern struct aa_dfa *aa_match_alloc(voi
extern void aa_match_free(struct aa_dfa *dfa);
extern int unpack_dfa(struct aa_dfa *dfa, void *blob, size_t size);
extern int verify_dfa(struct aa_dfa *dfa);
-extern unsigned int aa_dfa_match(struct aa_dfa *dfa, const char *str);
+extern unsigned int aa_dfa_match(struct aa_dfa *dfa, const char *str, int *);
extern unsigned int aa_dfa_next_state(struct aa_dfa *dfa, unsigned int start,
const char *str);
extern unsigned int aa_match_state(struct aa_dfa *dfa, unsigned int start,
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -89,7 +89,7 @@ static struct file_operations apparmorfs
static ssize_t aa_matching_read(struct file *file, char __user *buf,
size_t size, loff_t *ppos)
{
- const char *matching = "pattern=aadfa perms=rwxamlk/ user::other";
+ const char *matching = "pattern=aadfa audit perms=rwxamlk/ user::other";
return simple_read_from_buffer(buf, size, ppos, matching,
strlen(matching));
--- a/security/apparmor/inline.h
+++ b/security/apparmor/inline.h
@@ -232,9 +232,19 @@ static inline void unlock_both_profiles(
}
}
-static inline unsigned int aa_match(struct aa_dfa *dfa, const char *pathname)
+static inline unsigned int aa_match(struct aa_dfa *dfa, const char *pathname,
+ int *audit_mask)
{
- return dfa ? aa_dfa_match(dfa, pathname) : 0;
+ if (dfa)
+ return aa_dfa_match(dfa, pathname, audit_mask);
+ if (audit_mask)
+ *audit_mask = 0;
+ return 0;
+}
+
+static inline int dfa_audit_mask(struct aa_dfa *dfa, unsigned int state)
+{
+ return ACCEPT_TABLE2(dfa)[state];
}
#endif /* __INLINE_H__ */
--- a/security/apparmor/main.c
+++ b/security/apparmor/main.c
@@ -36,204 +36,6 @@ static int aa_inode_mode(struct inode *i
return AA_OTHER_SHIFT;
}
-/**
- * aa_file_denied - check for @mask access on a file
- * @profile: profile to check against
- * @name: pathname of file
- * @mask: permission mask requested for file
- *
- * Return %0 on success, or else the permissions in @mask that the
- * profile denies.
- */
-static int aa_file_denied(struct aa_profile *profile, const char *name,
- int mask)
-{
- return (mask & ~aa_match(profile->file_rules, name));
-}
-
-/**
- * aa_link_denied - check for permission to link a file
- * @profile: profile to check against
- * @link: pathname of link being created
- * @target: pathname of target to be linked to
- * @target_mode: UGO shift for target inode
- * @request_mask: the permissions subset valid only if link succeeds
- * Return %0 on success, or else the permissions that the profile denies.
- */
-static int aa_link_denied(struct aa_profile *profile, const char *link,
- const char *target, int target_mode,
- int *request_mask)
-{
- unsigned int state;
- int l_mode, t_mode, denied_mask = 0;
- int link_mask = AA_MAY_LINK << target_mode;
-
- *request_mask = link_mask;
-
- l_mode = aa_match_state(profile->file_rules, DFA_START, link, &state);
- if (l_mode & link_mask) {
- int mode;
- /* test to see if target can be paired with link */
- state = aa_dfa_null_transition(profile->file_rules, state);
- mode = aa_match_state(profile->file_rules, state, target,
- NULL);
-
- if (!(mode & link_mask))
- denied_mask |= link_mask;
- /* return if link subset test is not required */
- if (!(mode & (AA_LINK_SUBSET_TEST << target_mode)))
- return denied_mask;
- }
-
- /* Do link perm subset test
- * If a subset test is required a permission subset test of the
- * perms for the link are done against the user::other of the
- * target's 'r', 'w', 'x', 'a', 'k', and 'm' permissions.
- *
- * If the link has 'x', an exact match of all the execute flags
- * must match.
- */
- denied_mask |= ~l_mode & link_mask;
-
- t_mode = aa_match(profile->file_rules, target);
-
- /* For actual subset test ignore valid-profile-transition flags,
- * and link bits
- */
- l_mode &= AA_FILE_PERMS & ~AA_LINK_BITS;
- t_mode &= AA_FILE_PERMS & ~AA_LINK_BITS;
-
- *request_mask = l_mode | link_mask;
-
- if (l_mode) {
- denied_mask |= l_mode & ~t_mode;
- if ((l_mode & AA_EXEC_BITS) &&
- (l_mode & ALL_AA_EXEC_TYPE) !=
- (t_mode & ALL_AA_EXEC_TYPE))
- denied_mask = (denied_mask & ~ALL_AA_EXEC_TYPE) |
- (l_mode & ALL_AA_EXEC_TYPE);
- }
-
- return denied_mask;
-}
-
-/**
- * aa_get_name - compute the pathname of a file
- * @dentry: dentry of the file
- * @mnt: vfsmount of the file
- * @buffer: buffer that aa_get_name() allocated
- * @check: AA_CHECK_DIR is set if the file is a directory
- *
- * Returns a pointer to the beginning of the pathname (which usually differs
- * from the beginning of the buffer), or an error code.
- *
- * We need @check to indicate whether the file is a directory or not because
- * the file may not yet exist, and so we cannot check the inode's file type.
- */
-static char *aa_get_name(struct dentry *dentry, struct vfsmount *mnt,
- char **buffer, int check)
-{
- char *name;
- int is_dir, size = 256;
-
- is_dir = (check & AA_CHECK_DIR) ? 1 : 0;
-
- for (;;) {
- char *buf = kmalloc(size, GFP_KERNEL);
- if (!buf)
- return ERR_PTR(-ENOMEM);
-
- name = d_namespace_path(dentry, mnt, buf, size - is_dir);
- if (!IS_ERR(name)) {
- if (name[0] != '/') {
- /*
- * This dentry is not connected to the
- * namespace root -- reject access.
- */
- kfree(buf);
- return ERR_PTR(-ENOENT);
- }
- if (is_dir && name[1] != '\0') {
- /*
- * Append "/" to the pathname. The root
- * directory is a special case; it already
- * ends in slash.
- */
- buf[size - 2] = '/';
- buf[size - 1] = '\0';
- }
-
- *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_name_buffer(char *buffer)
-{
- kfree(buffer);
-}
-
-/**
- * aa_perm_dentry - check if @profile allows @mask for a file
- * @profile: profile to check against
- * @dentry: dentry of the file
- * @mnt: vfsmount o the file
- * @sa: audit context
- * @mask: requested profile permissions
- * @check: kind of check to perform
- *
- * Returns 0 upon success, or else an error code.
- *
- * @check indicates the file type, and whether the file was accessed through
- * an open file descriptor (AA_CHECK_FD) or not.
- */
-static int aa_perm_dentry(struct aa_profile *profile, struct dentry *dentry,
- struct vfsmount *mnt, struct aa_audit *sa, int check)
-{
- int error;
- char *buffer = NULL;
-
- sa->name = aa_get_name(dentry, mnt, &buffer, check);
- sa->request_mask <<= aa_inode_mode(dentry->d_inode);
- if (IS_ERR(sa->name)) {
- /*
- * deleted files are given a pass on permission checks when
- * accessed through a file descriptor.
- */
- if (PTR_ERR(sa->name) == -ENOENT && (check & AA_CHECK_FD))
- sa->denied_mask = 0;
- else {
- sa->denied_mask = sa->request_mask;
- sa->error_code = PTR_ERR(sa->name);
- if (sa->error_code == -ENOENT)
- sa->info = "Failed name resolution - object not a valid entry";
- else if (sa->error_code == -ENAMETOOLONG)
- sa->info = "Failed name resolution - name too long";
- else
- sa->info = "Failed name resolution";
- }
- sa->name = NULL;
- } else
- sa->denied_mask = aa_file_denied(profile, sa->name,
- sa->request_mask);
-
- if (!sa->denied_mask)
- sa->error_code = 0;
-
- error = aa_audit(profile, sa);
- aa_put_name_buffer(buffer);
-
- return error;
-}
-
int alloc_default_namespace(void)
{
struct aa_namespace *ns;
@@ -471,20 +273,259 @@ int aa_audit(struct aa_profile *profile,
int type = AUDIT_APPARMOR_DENIED;
struct audit_context *audit_cxt;
- if (likely(!sa->error_code)) {
- if (likely(!PROFILE_AUDIT(profile)))
- /* nothing to log */
- return 0;
- else
- type = AUDIT_APPARMOR_AUDIT;
- } else if (PROFILE_COMPLAIN(profile)) {
+ if (likely(!sa->error_code))
+ type = AUDIT_APPARMOR_AUDIT;
+ else if (PROFILE_COMPLAIN(profile))
type = AUDIT_APPARMOR_ALLOWED;
- }
audit_cxt = apparmor_logsyscall ? current->audit_context : NULL;
return aa_audit_base(profile, sa, audit_cxt, type);
}
+static int aa_audit_file(struct aa_profile *profile, struct aa_audit *sa)
+{
+ if (likely(!sa->error_code)) {
+ int mask = sa->audit_mask & AUDIT_FILE_MASK;
+
+ if (unlikely(PROFILE_AUDIT(profile)))
+ mask |= AUDIT_FILE_MASK;
+
+ if (likely(!(sa->request_mask & mask)))
+ return 0;
+
+ /* mask off perms that are not being force audited */
+ sa->request_mask &= mask | ALL_AA_EXEC_TYPE;
+ } else {
+ int mask = AUDIT_QUIET_MASK(sa->audit_mask);
+
+ if (!(sa->denied_mask & ~mask))
+ return sa->error_code;
+
+ /* mask off perms whose denial is being silenced */
+ sa->denied_mask &= (~mask) | ALL_AA_EXEC_TYPE;
+ }
+
+ return aa_audit(profile, sa);
+}
+
+static int aa_audit_caps(struct aa_profile *profile, struct aa_audit *sa,
+ int cap)
+{
+ if (likely(!sa->error_code)) {
+ if (likely(!PROFILE_AUDIT(profile) &&
+ !cap_raised(profile->audit_caps, cap)))
+ return 0;
+ }
+
+ /* quieting of capabilities is handled the caps_logged cache */
+ return aa_audit(profile, sa);
+}
+
+/**
+ * aa_file_denied - check for @mask access on a file
+ * @profile: profile to check against
+ * @name: pathname of file
+ * @mask: permission mask requested for file
+ * @audit_mask: return audit mask for the match
+ *
+ * Return %0 on success, or else the permissions in @mask that the
+ * profile denies.
+ */
+static int aa_file_denied(struct aa_profile *profile, const char *name,
+ int mask, int *audit_mask)
+{
+ return (mask & ~aa_match(profile->file_rules, name, audit_mask));
+}
+
+/**
+ * aa_link_denied - check for permission to link a file
+ * @profile: profile to check against
+ * @link: pathname of link being created
+ * @target: pathname of target to be linked to
+ * @target_mode: UGO shift for target inode
+ * @request_mask: the permissions subset valid only if link succeeds
+ * @audit_mask: return the audit_mask for the link permission
+ * Return %0 on success, or else the permissions that the profile denies.
+ */
+static int aa_link_denied(struct aa_profile *profile, const char *link,
+ const char *target, int target_mode,
+ int *request_mask, int *audit_mask)
+{
+ unsigned int state;
+ int l_mode, t_mode, denied_mask = 0;
+ int link_mask = AA_MAY_LINK << target_mode;
+
+ *request_mask = link_mask;
+
+ l_mode = aa_match_state(profile->file_rules, DFA_START, link, &state);
+
+ if (l_mode & link_mask) {
+ int mode;
+ /* test to see if target can be paired with link */
+ state = aa_dfa_null_transition(profile->file_rules, state);
+ mode = aa_match_state(profile->file_rules, state, target,
+ &state);
+
+ if (!(mode & link_mask))
+ denied_mask |= link_mask;
+
+ *audit_mask = dfa_audit_mask(profile->file_rules, state);
+
+ /* return if link subset test is not required */
+ if (!(mode & (AA_LINK_SUBSET_TEST << target_mode)))
+ return denied_mask;
+ }
+
+ /* Do link perm subset test
+ * If a subset test is required a permission subset test of the
+ * perms for the link are done against the user::other of the
+ * target's 'r', 'w', 'x', 'a', 'k', and 'm' permissions.
+ *
+ * If the link has 'x', an exact match of all the execute flags
+ * must match.
+ */
+ denied_mask |= ~l_mode & link_mask;
+
+ t_mode = aa_match(profile->file_rules, target, NULL);
+
+ /* For actual subset test ignore valid-profile-transition flags,
+ * and link bits
+ */
+ l_mode &= AA_FILE_PERMS & ~AA_LINK_BITS;
+ t_mode &= AA_FILE_PERMS & ~AA_LINK_BITS;
+
+ *request_mask = l_mode | link_mask;
+
+ if (l_mode) {
+ denied_mask |= l_mode & ~t_mode;
+ if ((l_mode & AA_EXEC_BITS) &&
+ (l_mode & ALL_AA_EXEC_TYPE) !=
+ (t_mode & ALL_AA_EXEC_TYPE))
+ denied_mask = (denied_mask & ~ALL_AA_EXEC_TYPE) |
+ (l_mode & (ALL_AA_EXEC_TYPE | AA_EXEC_BITS));
+ }
+
+ return denied_mask;
+}
+
+/**
+ * aa_get_name - compute the pathname of a file
+ * @dentry: dentry of the file
+ * @mnt: vfsmount of the file
+ * @buffer: buffer that aa_get_name() allocated
+ * @check: AA_CHECK_DIR is set if the file is a directory
+ *
+ * Returns a pointer to the beginning of the pathname (which usually differs
+ * from the beginning of the buffer), or an error code.
+ *
+ * We need @check to indicate whether the file is a directory or not because
+ * the file may not yet exist, and so we cannot check the inode's file type.
+ */
+static char *aa_get_name(struct dentry *dentry, struct vfsmount *mnt,
+ char **buffer, int check)
+{
+ char *name;
+ int is_dir, size = 256;
+
+ is_dir = (check & AA_CHECK_DIR) ? 1 : 0;
+
+ for (;;) {
+ char *buf = kmalloc(size, GFP_KERNEL);
+ if (!buf)
+ return ERR_PTR(-ENOMEM);
+
+ name = d_namespace_path(dentry, mnt, buf, size - is_dir);
+ if (!IS_ERR(name)) {
+ if (name[0] != '/') {
+ /*
+ * This dentry is not connected to the
+ * namespace root -- reject access.
+ */
+ kfree(buf);
+ return ERR_PTR(-ENOENT);
+ }
+ if (is_dir && name[1] != '\0') {
+ /*
+ * Append "/" to the pathname. The root
+ * directory is a special case; it already
+ * ends in slash.
+ */
+ buf[size - 2] = '/';
+ buf[size - 1] = '\0';
+ }
+
+ *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_name_buffer(char *buffer)
+{
+ kfree(buffer);
+}
+
+/**
+ * aa_perm_dentry - check if @profile allows @mask for a file
+ * @profile: profile to check against
+ * @dentry: dentry of the file
+ * @mnt: vfsmount o the file
+ * @sa: audit context
+ * @mask: requested profile permissions
+ * @check: kind of check to perform
+ *
+ * Returns 0 upon success, or else an error code.
+ *
+ * @check indicates the file type, and whether the file was accessed through
+ * an open file descriptor (AA_CHECK_FD) or not.
+ */
+static int aa_perm_dentry(struct aa_profile *profile, struct dentry *dentry,
+ struct vfsmount *mnt, struct aa_audit *sa, int check)
+{
+ int error;
+ char *buffer = NULL;
+
+ sa->name = aa_get_name(dentry, mnt, &buffer, check);
+ sa->request_mask <<= aa_inode_mode(dentry->d_inode);
+ if (IS_ERR(sa->name)) {
+ /*
+ * deleted files are given a pass on permission checks when
+ * accessed through a file descriptor.
+ */
+ if (PTR_ERR(sa->name) == -ENOENT && (check & AA_CHECK_FD))
+ sa->denied_mask = 0;
+ else {
+ sa->denied_mask = sa->request_mask;
+ sa->error_code = PTR_ERR(sa->name);
+ if (sa->error_code == -ENOENT)
+ sa->info = "Failed name resolution - object not a valid entry";
+ else if (sa->error_code == -ENAMETOOLONG)
+ sa->info = "Failed name resolution - name too long";
+ else
+ sa->info = "Failed name resolution";
+ }
+ sa->name = NULL;
+ } else
+ sa->denied_mask = aa_file_denied(profile, sa->name,
+ sa->request_mask,
+ &sa->audit_mask);
+
+ if (!sa->denied_mask)
+ sa->error_code = 0;
+
+ error = aa_audit_file(profile, sa);
+ aa_put_name_buffer(buffer);
+
+ return error;
+}
+
/**
* aa_attr - check if attribute change is allowed
* @profile: profile to check against
@@ -621,10 +662,11 @@ int aa_perm_path(struct aa_profile *prof
else
sa.request_mask = mask << AA_OTHER_SHIFT;
- sa.denied_mask = aa_file_denied(profile, name, sa.request_mask) ;
+ sa.denied_mask = aa_file_denied(profile, name, sa.request_mask,
+ &sa.audit_mask) ;
sa.error_code = sa.denied_mask ? -EACCES : 0;
- return aa_audit(profile, &sa);
+ return aa_audit_file(profile, &sa);
}
/**
@@ -660,7 +702,7 @@ int aa_capability(struct aa_task_context
sa.name = capability_names[cap];
sa.error_code = error;
- error = aa_audit(cxt->profile, &sa);
+ error = aa_audit_caps(cxt->profile, &sa, cap);
return error;
}
@@ -709,11 +751,12 @@ int aa_link(struct aa_profile *profile,
if (sa.name && sa.name2) {
sa.denied_mask = aa_link_denied(profile, sa.name, sa.name2,
aa_inode_mode(target->d_inode),
- &sa.request_mask);
+ &sa.request_mask,
+ &sa.audit_mask);
sa.error_code = sa.denied_mask ? -EACCES : 0;
}
- error = aa_audit(profile, &sa);
+ error = aa_audit_file(profile, &sa);
aa_put_name_buffer(buffer);
aa_put_name_buffer(buffer2);
@@ -802,8 +845,8 @@ aa_register_find(struct aa_profile *prof
new_profile =
aa_dup_profile(profile->ns->null_complain_profile);
} else {
- aa_audit_reject(profile, sa);
- return ERR_PTR(-EACCES); /* was -EPERM */
+ sa->error_code = -EACCES;
+ return ERR_PTR(aa_audit_file(profile, sa));
}
} else {
/* Only way we can get into this code is if task
@@ -863,7 +906,8 @@ repeat:
/* Confined task, determine what mode inherit, unconfined or
* mandatory to load new profile
*/
- exec_mode = aa_match(profile->file_rules, filename);
+ exec_mode = aa_match(profile->file_rules, filename,
+ &sa.audit_mask);
if (exec_mode & sa.request_mask) {
switch ((exec_mode >> shift) & AA_EXEC_MODIFIERS) {
@@ -906,6 +950,9 @@ repeat:
break;
}
+ } else if (sa.request_mask & AUDIT_QUIET_MASK(sa.audit_mask)) {
+ /* quiet failed exit */
+ new_profile = ERR_PTR(-EACCES);
} else if (complain) {
/* There was no entry in calling profile
* describing mode to execute image in.
@@ -916,8 +963,8 @@ repeat:
exec_mode |= AA_EXEC_UNSAFE << shift;
} else {
sa.denied_mask = sa.request_mask;
- aa_audit_reject(profile, &sa);
- new_profile = ERR_PTR(-EPERM);
+ sa.error_code = -EACCES;
+ new_profile = ERR_PTR(aa_audit_file(profile, &sa));
}
} else {
/* Unconfined task, load profile if it exists */
@@ -973,6 +1020,7 @@ repeat:
sa.info = "set profile";
aa_audit_hint(new_profile, &sa);
}
+
cleanup:
aa_put_name_buffer(buffer);
if (IS_ERR(new_profile))
@@ -1149,7 +1197,7 @@ repeat:
if (PROFILE_COMPLAIN(profile) ||
(ns == profile->ns &&
- (aa_match(profile->file_rules, name) & AA_CHANGE_PROFILE)))
+ (aa_match(profile->file_rules, name, NULL) & AA_CHANGE_PROFILE)))
error = do_change_profile(profile, ns, name, 0, 0, &sa);
else {
/* check for a rule with a namespace prepended */
@@ -1356,9 +1404,11 @@ void aa_change_task_context(struct task_
call_rcu(&old_cxt->rcu, free_aa_task_context_rcu_callback);
}
if (new_cxt) {
- /* clear the caps_logged cache, so that new profile/hat has
- * chance to emit its own set of cap messages */
- new_cxt->caps_logged = CAP_EMPTY_SET;
+ /* set the caps_logged cache to the quiet_caps mask
+ * this has the effect of quieting caps that are not
+ * supposed to be logged
+ */
+ new_cxt->caps_logged = profile->quiet_caps;
new_cxt->cookie = cookie;
new_cxt->task = task;
new_cxt->profile = aa_dup_profile(profile);
--- a/security/apparmor/match.c
+++ b/security/apparmor/match.c
@@ -14,6 +14,7 @@
#include <linux/errno.h>
#include "apparmor.h"
#include "match.h"
+#include "inline.h"
static struct table_header *unpack_table(void *blob, size_t bsize)
{
@@ -295,13 +296,17 @@ unsigned int aa_dfa_null_transition(stru
* aa_dfa_match - find accept perm for @str in @dfa
* @dfa: the dfa to match @str against
* @str: the string to match against the dfa
+ * @audit_mask: the audit_mask for the final state
*
* aa_dfa_match will match @str and return the accept perms for the
* final state.
*/
-unsigned int aa_dfa_match(struct aa_dfa *dfa, const char *str)
+unsigned int aa_dfa_match(struct aa_dfa *dfa, const char *str, int *audit_mask)
{
- return ACCEPT_TABLE(dfa)[aa_dfa_next_state(dfa, DFA_START, str)];
+ int state = aa_dfa_next_state(dfa, DFA_START, str);
+ if (audit_mask)
+ *audit_mask = dfa_audit_mask(dfa, state);
+ return ACCEPT_TABLE(dfa)[state];
}
/**
--- a/security/apparmor/module_interface.c
+++ b/security/apparmor/module_interface.c
@@ -310,6 +310,10 @@ static struct aa_profile *aa_unpack_prof
if (!aa_is_u32(e, &(profile->capabilities), NULL))
goto fail;
+ if (!aa_is_u32(e, &(profile->audit_caps), NULL))
+ goto fail;
+ if (!aa_is_u32(e, &(profile->quiet_caps), NULL))
+ goto fail;
/* get file rules */
profile->file_rules = aa_unpack_dfa(e);
@@ -317,6 +321,10 @@ static struct aa_profile *aa_unpack_prof
error = PTR_ERR(profile->file_rules);
profile->file_rules = NULL;
goto fail;
+ if (!aa_is_u16(e, &profile->audit_network[i], NULL))
+ goto fail;
+ if (!aa_is_u16(e, &profile->quiet_network[i], NULL))
+ goto fail;
}
if (!aa_is_nameX(e, AA_STRUCTEND, NULL))
@@ -360,7 +368,7 @@ static int aa_verify_header(struct aa_ex
}
/* check that the interface version is currently supported */
- if (e->version != 3) {
+ if (e->version != 4) {
struct aa_audit sa;
memset(&sa, 0, sizeof(sa));
sa.operation = operation;

View file

@ -1,72 +0,0 @@
From: Tony Jones <tonyj@suse.de>
Subject: Export audit subsystem for use by modules
Update kenel audit range comments to show AppArmor's registered range of
1500-1599. This range used to be reserved for LSPP but LSPP uses the
SE Linux range and the range was given to AppArmor.
Adds necessary export symbols for audit subsystem routines.
Changes audit_log_vformat to be externally visible (analagous to vprintf)
Patch is not in mainline -- pending AppArmor code submission to lkml
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
include/linux/audit.h | 12 +++++++++++-
kernel/audit.c | 6 ++++--
2 files changed, 15 insertions(+), 3 deletions(-)
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -33,7 +33,7 @@
* 1200 - 1299 messages internal to the audit daemon
* 1300 - 1399 audit event messages
* 1400 - 1499 SE Linux use
- * 1500 - 1599 kernel LSPP events
+ * 1500 - 1599 AppArmor use
* 1600 - 1699 kernel crypto events
* 1700 - 1799 kernel anomaly records
* 1800 - 1999 future kernel use (maybe integrity labels and related events)
@@ -116,6 +116,13 @@
#define AUDIT_MAC_IPSEC_DELSPD 1414 /* Not used */
#define AUDIT_MAC_IPSEC_EVENT 1415 /* Audit an IPSec event */
+#define AUDIT_APPARMOR_AUDIT 1501 /* AppArmor audited grants */
+#define AUDIT_APPARMOR_ALLOWED 1502 /* Allowed Access for learning */
+#define AUDIT_APPARMOR_DENIED 1503
+#define AUDIT_APPARMOR_HINT 1504 /* Process Tracking information */
+#define AUDIT_APPARMOR_STATUS 1505 /* Changes in config */
+#define AUDIT_APPARMOR_ERROR 1506 /* Internal AppArmor Errors */
+
#define AUDIT_FIRST_KERN_ANOM_MSG 1700
#define AUDIT_LAST_KERN_ANOM_MSG 1799
#define AUDIT_ANOM_PROMISCUOUS 1700 /* Device changed promiscuous mode */
@@ -513,6 +520,9 @@ extern void audit_log(struct audit_
__attribute__((format(printf,4,5)));
extern struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, int type);
+extern void audit_log_vformat(struct audit_buffer *ab,
+ const char *fmt, va_list args)
+ __attribute__((format(printf,2,0)));
extern void audit_log_format(struct audit_buffer *ab,
const char *fmt, ...)
__attribute__((format(printf,2,3)));
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -1215,8 +1215,7 @@ static inline int audit_expand(struct au
* will be called a second time. Currently, we assume that a printk
* can't format message larger than 1024 bytes, so we don't either.
*/
-static void audit_log_vformat(struct audit_buffer *ab, const char *fmt,
- va_list args)
+void audit_log_vformat(struct audit_buffer *ab, const char *fmt, va_list args)
{
int len, avail;
struct sk_buff *skb;
@@ -1471,3 +1470,6 @@ EXPORT_SYMBOL(audit_log_start);
EXPORT_SYMBOL(audit_log_end);
EXPORT_SYMBOL(audit_log_format);
EXPORT_SYMBOL(audit_log);
+EXPORT_SYMBOL_GPL(audit_log_vformat);
+EXPORT_SYMBOL_GPL(audit_log_untrustedstring);
+EXPORT_SYMBOL_GPL(audit_log_d_path);

View file

@ -1,61 +0,0 @@
---
security/apparmor/Kconfig | 17 +++++++++++++++++
security/apparmor/lsm.c | 16 ++++++++++++++++
2 files changed, 33 insertions(+)
--- a/security/apparmor/Kconfig
+++ b/security/apparmor/Kconfig
@@ -7,4 +7,21 @@ config SECURITY_APPARMOR
Required userspace tools (if they are not included in your
distribution) and further information may be found at
<http://forge.novell.com/modules/xfmod/project/?apparmor>
+
If you are unsure how to answer this question, answer N.
+
+config SECURITY_APPARMOR_BOOTPARAM_VALUE
+ int "AppArmor boot parameter default value"
+ depends on SECURITY_APPARMOR
+ range 0 1
+ default 1
+ help
+ This option sets the default value for the kernel parameter
+ 'apparmor', which allows AppArmor to be enabled or disabled
+ at boot. If this option is set to 0 (zero), the AppArmor
+ kernel parameter will default to 0, disabling AppArmor at
+ bootup. If this option is set to 1 (one), the AppArmor
+ kernel parameter will default to 1, enabling AppArmor at
+ bootup.
+
+ If you are unsure how to answer this question, answer 1.
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -23,6 +23,17 @@
#include "apparmor.h"
#include "inline.h"
+/* Boot time disable flag */
+int apparmor_enabled = CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE;
+
+static int __init apparmor_enabled_setup(char *str)
+{
+ apparmor_enabled = simple_strtol(str, NULL, 0);
+ return 1;
+}
+__setup("apparmor=", apparmor_enabled_setup);
+
+
static int param_set_aabool(const char *val, struct kernel_param *kp);
static int param_get_aabool(char *buffer, struct kernel_param *kp);
#define param_check_aabool(name, p) __param_check(name, p, int)
@@ -882,6 +893,11 @@ static int __init apparmor_init(void)
{
int error;
+ if (!apparmor_enabled) {
+ info_message("AppArmor disabled by boottime parameter\n");
+ return 0;
+ }
+
if ((error = create_apparmorfs())) {
AA_ERROR("Unable to activate AppArmor filesystem\n");
goto createfs_out;

View file

@ -1,50 +0,0 @@
---
security/apparmor/Kconfig | 2 +-
security/apparmor/lsm.c | 26 --------------------------
2 files changed, 1 insertion(+), 27 deletions(-)
--- a/security/apparmor/Kconfig
+++ b/security/apparmor/Kconfig
@@ -1,5 +1,5 @@
config SECURITY_APPARMOR
- tristate "AppArmor support"
+ bool "AppArmor support"
depends on SECURITY
select AUDIT
help
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -931,33 +931,7 @@ createfs_out:
}
-static void __exit apparmor_exit(void)
-{
- /* Remove and release all the profiles on the profile list. */
- mutex_lock(&aa_interface_lock);
- aa_profile_ns_list_release();
-
- /* FIXME: cleanup profiles references on files */
- free_default_namespace();
-
- /*
- * Delay for an rcu cycle to make sure that all active task
- * context readers have finished, and all profiles have been
- * freed by their rcu callbacks.
- */
- synchronize_rcu();
-
- destroy_apparmorfs();
- mutex_unlock(&aa_interface_lock);
-
- if (unregister_security(&apparmor_ops))
- info_message("Unable to properly unregister AppArmor");
-
- info_message("AppArmor protection removed");
-}
-
module_init(apparmor_init);
-module_exit(apparmor_exit);
MODULE_DESCRIPTION("AppArmor process confinement");
MODULE_AUTHOR("Novell/Immunix, http://bugs.opensuse.org");

View file

@ -1,16 +0,0 @@
---
security/apparmor/lsm.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -366,8 +366,7 @@ static inline int aa_mask_permissions(in
static int apparmor_inode_create(struct inode *dir, struct dentry *dentry,
struct vfsmount *mnt, int mask)
{
- /* FIXME: may move to MAY_APPEND later */
- return aa_permission("inode_create", dir, dentry, mnt, MAY_WRITE, 0);
+ return aa_permission("inode_create", dir, dentry, mnt, MAY_APPEND, 0);
}
static int apparmor_inode_link(struct dentry *old_dentry,

View file

@ -1,83 +0,0 @@
---
security/apparmor/main.c | 39 ++++++++++++++++++++++++++++-----------
1 file changed, 28 insertions(+), 11 deletions(-)
--- a/security/apparmor/main.c
+++ b/security/apparmor/main.c
@@ -216,6 +216,12 @@ static int aa_perm_dentry(struct aa_prof
else {
sa->denied_mask = sa->request_mask;
sa->error_code = PTR_ERR(sa->name);
+ if (sa->error_code == -ENOENT)
+ sa->info = "Failed name resolution - object not a valid entry";
+ else if (sa->error_code == -ENAMETOOLONG)
+ sa->info = "Failed name resolution - name too long";
+ else
+ sa->info = "Failed name resolution";
}
sa->name = NULL;
} else
@@ -371,8 +377,11 @@ static int aa_audit_base(struct aa_profi
if (sa->operation)
audit_log_format(ab, "operation=\"%s\"", sa->operation);
- if (sa->info)
+ if (sa->info) {
audit_log_format(ab, " info=\"%s\"", sa->info);
+ if (sa->error_code)
+ audit_log_format(ab, " error=%d", sa->error_code);
+ }
if (sa->request_mask)
aa_audit_file_mask(ab, "requested_mask", sa->request_mask);
@@ -918,23 +927,29 @@ int aa_register(struct linux_binprm *bpr
AA_DEBUG("%s\n", __FUNCTION__);
- filename = aa_get_name(filp->f_dentry, filp->f_vfsmnt, &buffer, 0);
- if (IS_ERR(filename)) {
- AA_ERROR("%s: Failed to get filename", __FUNCTION__);
- return -ENOENT;
- }
+ profile = aa_get_profile(current);
shift = aa_inode_mode(filp->f_dentry->d_inode);
- exec_mode = AA_EXEC_UNSAFE << shift;
-
memset(&sa, 0, sizeof(sa));
sa.operation = "exec";
sa.gfp_mask = GFP_KERNEL;
- sa.name = filename;
sa.request_mask = MAY_EXEC << shift;
+ filename = aa_get_name(filp->f_dentry, filp->f_vfsmnt, &buffer, 0);
+ if (IS_ERR(filename)) {
+ if (profile) {
+ sa.info = "Failed name resolution - exec failed";
+ sa.error_code = PTR_ERR(filename);
+ aa_audit_reject(profile, &sa);
+ return sa.error_code;
+ } else
+ return 0;
+ }
+ sa.name = filename;
+
+ exec_mode = AA_EXEC_UNSAFE << shift;
+
repeat:
- profile = aa_get_profile(current);
if (profile) {
complain = PROFILE_COMPLAIN(profile);
@@ -1011,8 +1026,10 @@ repeat:
if (IS_ERR(old_profile)) {
aa_put_profile(new_profile);
aa_put_profile(profile);
- if (PTR_ERR(old_profile) == -ESTALE)
+ if (PTR_ERR(old_profile) == -ESTALE) {
+ profile = aa_get_profile(current);
goto repeat;
+ }
if (PTR_ERR(old_profile) == -EPERM) {
sa.denied_mask = sa.request_mask;
sa.info = "unable to set profile due to ptrace";

View file

@ -1,47 +0,0 @@
---
security/apparmor/apparmorfs.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -99,6 +99,22 @@ static struct file_operations apparmorfs
.read = aa_matching_read,
};
+/* apparmor/features */
+static ssize_t aa_features_read(struct file *file, char __user *buf,
+ size_t size, loff_t *ppos)
+{
+ const char *features = "file=3.0 capability=1.0 network=1.0 "
+ "change_hat=1.3 change_profile=1.0 "
+ "aanamespaces=1.0";
+
+ return simple_read_from_buffer(buf, size, ppos, features,
+ strlen(features));
+}
+
+static struct file_operations apparmorfs_features_fops = {
+ .read = aa_features_read,
+};
+
/* apparmor/.load */
static ssize_t aa_profile_load(struct file *f, const char __user *buf,
size_t size, loff_t *pos)
@@ -204,6 +220,7 @@ void destroy_apparmorfs(void)
aafs_remove(".replace");
aafs_remove(".load");
aafs_remove("matching");
+ aafs_remove("features");
aafs_remove("profiles");
securityfs_remove(apparmor_dentry);
apparmor_dentry = NULL;
@@ -232,6 +249,9 @@ int create_apparmorfs(void)
error = aafs_create("matching", 0444, &apparmorfs_matching_fops);
if (error)
goto error;
+ error = aafs_create("features", 0444, &apparmorfs_features_fops);
+ if (error)
+ goto error;
error = aafs_create(".load", 0640, &apparmorfs_profile_load);
if (error)
goto error;

View file

@ -1,36 +0,0 @@
---
security/apparmor/apparmorfs.c | 2 +-
security/apparmor/main.c | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -89,7 +89,7 @@ static struct file_operations apparmorfs
static ssize_t aa_matching_read(struct file *file, char __user *buf,
size_t size, loff_t *ppos)
{
- const char *matching = "pattern=aadfa perms=rwxamlz user:other";
+ const char *matching = "pattern=aadfa perms=rwxamlk/ user::other";
return simple_read_from_buffer(buf, size, ppos, matching,
strlen(matching));
--- a/security/apparmor/main.c
+++ b/security/apparmor/main.c
@@ -99,7 +99,7 @@ static int aa_link_denied(struct aa_prof
/* Link always requires 'l' on the link for both parts of the pair.
* If a subset test is required a permission subset test of the
* perms for the link are done against the user:group:other of the
- * target's 'r', 'w', 'x', 'a', 'z', and 'm' permissions.
+ * target's 'r', 'w', 'x', 'a', 'k', and 'm' permissions.
*
* If the link has 'x', an exact match of all the execute flags
* ('i', 'u', 'p'). safe exec is treated as a subset of unsafe exec
@@ -388,7 +388,7 @@ static int aa_audit_base(struct aa_profi
audit_log_format(ab, " info=\"%s\"", sa->info);
if (sa->request_mask)
- aa_audit_file_mask(ab, "request_mask", sa->request_mask);
+ aa_audit_file_mask(ab, "requested_mask", sa->request_mask);
if (sa->denied_mask)
aa_audit_file_mask(ab, "denied_mask", sa->denied_mask);

View file

@ -1,14 +0,0 @@
---
security/apparmor/lsm.c | 1 +
1 file changed, 1 insertion(+)
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -249,6 +249,7 @@ static int apparmor_sysctl(struct ctl_ta
}
out:
+ aa_put_profile(profile);
return error;
}

View file

@ -1,30 +0,0 @@
From: John Johansen <jjohansen@suse.de>
Subject: Add AppArmor LSM to security/Makefile
Signed-off-by: John Johansen <jjohansen@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
---
security/Kconfig | 1 +
security/Makefile | 1 +
2 files changed, 2 insertions(+)
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -104,6 +104,7 @@ config SECURITY_ROOTPLUG
If you are unsure how to answer this question, answer N.
source security/selinux/Kconfig
+source security/apparmor/Kconfig
endmenu
--- a/security/Makefile
+++ b/security/Makefile
@@ -14,5 +14,6 @@ endif
obj-$(CONFIG_SECURITY) += security.o dummy.o inode.o
# Must precede capability.o in order to stack properly.
obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
+obj-$(CONFIG_SECURITY_APPARMOR) += commoncap.o apparmor/
obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o

View file

@ -1,162 +0,0 @@
Change link to use pairs to provide tighter control of how links
can be made. The permission subset test is controled by an
extra flag of the link perm, this allows for compatibility with
old style links which have a broad pair, but also allows for
pairs to not require the subset test when needed.
The pairs are stored as two matches in the dfa seperated by the
null transition. Both matches must be made and have the link
perm set. If the second match has the AA_LINK_SUBSET_TEST perm
set, then the subset test is done.
The link keyword can be used or just the link mask
User side these pairs are expressed as follows
link [link_mask] linkname -> [subset_mask] targetname,
[link_mask] linkname -> [subset_mask] targetname,
link /linkname -> /targetname, #link to targetname, link is perm subset
if user:group:other link specification is desired then a user:group:other
mask containing only the link perm in the appropriate positions can be
specified
eg.
link l:: /linkname -> /targetname, # links to targetname if owned by
or
l:: /linkname -> /targetname,
Both the linkname and the target support full AppArmor globbing.
link l:: /** -> /**, # allow any link to target owned by user
to override the default subset test
l:: /linkname -> px /targetname,
Traditional AA style links are still supported and are mapped by the
parser into the newer link pair for the kernel, with the LINK_SUBSET_TEST
bits set.
/linkname rwl,
is mapped to
link /linkname -> /**,
/linkname rw,
---
security/apparmor/apparmor.h | 4 +++
security/apparmor/main.c | 45 ++++++++++++++++++++++++++++++++-----------
2 files changed, 38 insertions(+), 11 deletions(-)
--- a/security/apparmor/apparmor.h
+++ b/security/apparmor/apparmor.h
@@ -34,6 +34,7 @@
AA_MAY_LOCK | AA_EXEC_MMAP | \
AA_EXEC_UNSAFE | AA_EXEC_MOD_0 | \
AA_EXEC_MOD_1)
+#define AA_LINK_SUBSET_TEST 0x0020
#define AA_EXEC_UNCONFINED 0
#define AA_EXEC_INHERIT AA_EXEC_MOD_0
@@ -59,6 +60,9 @@
#define AA_USER_EXEC_MODS (AA_EXEC_MODIFIERS << AA_USER_SHIFT)
#define AA_OTHER_EXEC_MODS (AA_EXEC_MODIFIERS << AA_OTHER_SHIFT)
+#define AA_USER_EXEC_UNSAFE (AA_EXEC_UNSAFE << AA_USER_SHIFT)
+#define AA_OTHER_EXEC_UNSAFE (AA_EXEC_UNSAFE << AA_OTHER_SHIFT)
+
#define AA_EXEC_BITS (AA_USER_EXEC | AA_OTHER_EXEC)
#define AA_ALL_EXEC_MODS (AA_USER_EXEC_MODS | \
--- a/security/apparmor/main.c
+++ b/security/apparmor/main.c
@@ -67,10 +67,27 @@ static int aa_link_denied(struct aa_prof
const char *target, int target_mode,
int *request_mask)
{
- int l_mode, t_mode, denied_mask;
+ unsigned int state;
+ int l_mode, t_mode, denied_mask = 0;
int link_mask = AA_MAY_LINK << target_mode;
- l_mode = aa_match(profile->file_rules, link);
+ *request_mask = link_mask;
+
+ l_mode = aa_match_state(profile->file_rules, DFA_START, link, &state);
+ if (l_mode & link_mask) {
+ int mode;
+ /* test to see if target can be paired with link */
+ state = aa_dfa_null_transition(profile->file_rules, state);
+ mode = aa_match_state(profile->file_rules, state, target,
+ NULL);
+
+ if (!(mode & link_mask))
+ denied_mask |= link_mask;
+ if (!(mode & (AA_LINK_SUBSET_TEST << target_mode)))
+ return denied_mask;
+ }
+
+ /* do link perm subset test */
t_mode = aa_match(profile->file_rules, target);
/* Ignore valid-profile-transition flags. */
@@ -79,23 +96,30 @@ static int aa_link_denied(struct aa_prof
*request_mask = l_mode | link_mask;
- /* Link always requires 'l' on the link, a subset for user:other
- * of the target's 'r', 'w', 'x', 'a', 'z', and 'm' permissions on
- * the link, and if the link has 'x', an exact match of all the
- * execute flags ('i', 'u', 'U', 'p', 'P').
+ /* Link always requires 'l' on the link for both parts of the pair.
+ * If a subset test is required a permission subset test of the
+ * perms for the link are done against the user:group:other of the
+ * target's 'r', 'w', 'x', 'a', 'z', and 'm' permissions.
+ *
+ * If the link has 'x', an exact match of all the execute flags
+ * ('i', 'u', 'p'). safe exec is treated as a subset of unsafe exec
*/
#define SUBSET_PERMS (AA_FILE_PERMS & ~AA_LINK_BITS)
- denied_mask = ~l_mode & link_mask;
+ denied_mask |= ~l_mode & link_mask;
if (l_mode & SUBSET_PERMS) {
denied_mask |= (l_mode & SUBSET_PERMS) & ~t_mode;
if (denied_mask & AA_EXEC_BITS)
denied_mask |= l_mode & AA_ALL_EXEC_MODS;
else if (l_mode & AA_EXEC_BITS) {
+ if (!(l_mode & AA_USER_EXEC_UNSAFE))
+ l_mode |= t_mode & AA_USER_EXEC_UNSAFE;
if (l_mode & AA_USER_EXEC &&
(l_mode & AA_USER_EXEC_MODS) !=
(t_mode & AA_USER_EXEC_MODS))
denied_mask |= AA_USER_EXEC |
(l_mode & AA_USER_EXEC_MODS);
+ if (!(l_mode & AA_OTHER_EXEC_UNSAFE))
+ l_mode |= t_mode & AA_OTHER_EXEC_UNSAFE;
if (l_mode & AA_OTHER_EXEC &&
(l_mode & AA_OTHER_EXEC_MODS) !=
(t_mode & AA_OTHER_EXEC_MODS))
@@ -703,15 +727,15 @@ int aa_link(struct aa_profile *profile,
struct dentry *link, struct vfsmount *link_mnt,
struct dentry *target, struct vfsmount *target_mnt)
{
- int error, check = 0;
+ int error;
struct aa_audit sa;
char *buffer = NULL, *buffer2 = NULL;
memset(&sa, 0, sizeof(sa));
sa.operation = "inode_link";
sa.gfp_mask = GFP_KERNEL;
- sa.name = aa_get_name(link, link_mnt, &buffer, check);
- sa.name2 = aa_get_name(target, target_mnt, &buffer2, check);
+ sa.name = aa_get_name(link, link_mnt, &buffer, 0);
+ sa.name2 = aa_get_name(target, target_mnt, &buffer2, 0);
if (IS_ERR(sa.name)) {
sa.error_code = PTR_ERR(sa.name);
@@ -723,7 +747,6 @@ int aa_link(struct aa_profile *profile,
}
if (sa.name && sa.name2) {
- sa.request_mask = AA_MAY_LINK;
sa.denied_mask = aa_link_denied(profile, sa.name, sa.name2,
aa_inode_mode(target->d_inode),
&sa.request_mask);

View file

@ -1,904 +0,0 @@
From: John Johansen <jjohansen@suse.de>
Subject: AppArmor: Module and LSM hooks
Module parameters, LSM hooks, initialization and teardown.
Signed-off-by: John Johansen <jjohansen@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
---
security/apparmor/lsm.c | 889 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 889 insertions(+)
--- /dev/null
+++ b/security/apparmor/lsm.c
@@ -0,0 +1,889 @@
+/*
+ * Copyright (C) 1998-2007 Novell/SUSE
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * AppArmor LSM interface
+ */
+
+#include <linux/security.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/ctype.h>
+#include <linux/sysctl.h>
+#include <linux/audit.h>
+
+#include "apparmor.h"
+#include "inline.h"
+
+/* Flag indicating whether initialization completed */
+int apparmor_initialized = 0;
+
+static int param_set_aabool(const char *val, struct kernel_param *kp);
+static int param_get_aabool(char *buffer, struct kernel_param *kp);
+#define param_check_aabool(name, p) __param_check(name, p, int)
+
+static int param_set_aauint(const char *val, struct kernel_param *kp);
+static int param_get_aauint(char *buffer, struct kernel_param *kp);
+#define param_check_aauint(name, p) __param_check(name, p, int)
+
+/* Flag values, also controllable via /sys/module/apparmor/parameters
+ * We define special types as we want to do additional mediation.
+ *
+ * Complain mode -- in complain mode access failures result in auditing only
+ * and task is allowed access. audit events are processed by userspace to
+ * generate policy. Default is 'enforce' (0).
+ * Value is also togglable per profile and referenced when global value is
+ * enforce.
+ */
+int apparmor_complain = 0;
+module_param_named(complain, apparmor_complain, aabool, S_IRUSR | S_IWUSR);
+MODULE_PARM_DESC(apparmor_complain, "Toggle AppArmor complain mode");
+
+/* Debug mode */
+int apparmor_debug = 0;
+module_param_named(debug, apparmor_debug, aabool, S_IRUSR | S_IWUSR);
+MODULE_PARM_DESC(apparmor_debug, "Toggle AppArmor debug mode");
+
+/* Audit mode */
+int apparmor_audit = 0;
+module_param_named(audit, apparmor_audit, aabool, S_IRUSR | S_IWUSR);
+MODULE_PARM_DESC(apparmor_audit, "Toggle AppArmor audit mode");
+
+/* Syscall logging mode */
+int apparmor_logsyscall = 0;
+module_param_named(logsyscall, apparmor_logsyscall, aabool, S_IRUSR | S_IWUSR);
+MODULE_PARM_DESC(apparmor_logsyscall, "Toggle AppArmor logsyscall mode");
+
+/* Maximum pathname length before accesses will start getting rejected */
+unsigned int apparmor_path_max = 2 * PATH_MAX;
+module_param_named(path_max, apparmor_path_max, aauint, S_IRUSR | S_IWUSR);
+MODULE_PARM_DESC(apparmor_path_max, "Maximum pathname length allowed");
+
+/* Boot time disable flag */
+#ifdef CONFIG_SECURITY_APPARMOR_DISABLE
+#define AA_ENABLED_PERMS 0600
+#else
+#define AA_ENABLED_PERMS 0400
+#endif
+static int param_set_aa_enabled(const char *val, struct kernel_param *kp);
+unsigned int apparmor_enabled = CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE;
+module_param_call(enabled, param_set_aa_enabled, param_get_aauint,
+ &apparmor_enabled, AA_ENABLED_PERMS);
+MODULE_PARM_DESC(apparmor_enabled, "Enable/Disable Apparmor on boot");
+
+static int __init apparmor_enabled_setup(char *str)
+{
+ apparmor_enabled = simple_strtol(str, NULL, 0);
+ return 1;
+}
+__setup("apparmor=", apparmor_enabled_setup);
+
+static int param_set_aabool(const char *val, struct kernel_param *kp)
+{
+ if (aa_task_context(current))
+ return -EPERM;
+ return param_set_bool(val, kp);
+}
+
+static int param_get_aabool(char *buffer, struct kernel_param *kp)
+{
+ if (aa_task_context(current))
+ return -EPERM;
+ return param_get_bool(buffer, kp);
+}
+
+static int param_set_aauint(const char *val, struct kernel_param *kp)
+{
+ if (aa_task_context(current))
+ return -EPERM;
+ return param_set_uint(val, kp);
+}
+
+static int param_get_aauint(char *buffer, struct kernel_param *kp)
+{
+ if (aa_task_context(current))
+ return -EPERM;
+ return param_get_uint(buffer, kp);
+}
+
+/* allow run time disabling of apparmor */
+static int param_set_aa_enabled(const char *val, struct kernel_param *kp)
+{
+ char *endp;
+ unsigned long l;
+
+ if (!apparmor_initialized) {
+ apparmor_enabled = 0;
+ return 0;
+ }
+
+ if (aa_task_context(current))
+ return -EPERM;
+
+ if (!apparmor_enabled)
+ return -EINVAL;
+
+ if (!val)
+ return -EINVAL;
+
+ l = simple_strtoul(val, &endp, 0);
+ if (endp == val || l != 0)
+ return -EINVAL;
+
+ apparmor_enabled = 0;
+ apparmor_disable();
+ return 0;
+}
+
+static int aa_reject_syscall(struct task_struct *task, gfp_t flags,
+ const char *name)
+{
+ struct aa_profile *profile = aa_get_profile(task);
+ int error = 0;
+
+ if (profile) {
+ error = aa_audit_syscallreject(profile, flags, name);
+ aa_put_profile(profile);
+ }
+
+ return error;
+}
+
+static int apparmor_ptrace(struct task_struct *parent,
+ struct task_struct *child)
+{
+ struct aa_task_context *cxt;
+ int error = 0;
+
+ /*
+ * parent can ptrace child when
+ * - parent is unconfined
+ * - parent & child are in the same namespace &&
+ * - parent is in complain mode
+ * - parent and child are confined by the same profile
+ * - parent profile has CAP_SYS_PTRACE
+ */
+
+ rcu_read_lock();
+ cxt = aa_task_context(parent);
+ if (cxt) {
+ if (parent->nsproxy != child->nsproxy) {
+ struct aa_audit sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.operation = "ptrace";
+ sa.gfp_mask = GFP_ATOMIC;
+ sa.parent = parent->pid;
+ sa.task = child->pid;
+ sa.info = "different namespaces";
+ aa_audit_reject(cxt->profile, &sa);
+ error = -EPERM;
+ } else {
+ struct aa_task_context *child_cxt =
+ aa_task_context(child);
+
+ error = aa_may_ptrace(cxt, child_cxt ?
+ child_cxt->profile : NULL);
+ if (PROFILE_COMPLAIN(cxt->profile)) {
+ struct aa_audit sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.operation = "ptrace";
+ sa.gfp_mask = GFP_ATOMIC;
+ sa.parent = parent->pid;
+ sa.task = child->pid;
+ aa_audit_hint(cxt->profile, &sa);
+ }
+ }
+ }
+ rcu_read_unlock();
+
+ return error;
+}
+
+static int apparmor_capable(struct task_struct *task, int cap)
+{
+ int error;
+ struct aa_task_context *cxt;
+
+ /* cap_capable returns 0 on success, else -EPERM */
+ error = cap_capable(task, cap);
+
+ rcu_read_lock();
+ cxt = aa_task_context(task);
+ if (cxt && (!error || cap_raised(cxt->profile->set_caps, cap)))
+ error = aa_capability(cxt, cap);
+ rcu_read_unlock();
+
+ return error;
+}
+
+static int apparmor_sysctl(struct ctl_table *table, int op)
+{
+ struct aa_profile *profile = aa_get_profile(current);
+ int error = 0;
+
+ if (profile) {
+ char *buffer, *name;
+ int mask;
+
+ mask = 0;
+ if (op & 4)
+ mask |= MAY_READ;
+ if (op & 2)
+ mask |= MAY_WRITE;
+
+ error = -ENOMEM;
+ buffer = (char*)__get_free_page(GFP_KERNEL);
+ if (!buffer)
+ goto out;
+ name = sysctl_pathname(table, buffer, PAGE_SIZE);
+ if (name && name - buffer >= 5) {
+ name -= 5;
+ memcpy(name, "/proc", 5);
+ error = aa_perm_path(profile, "sysctl", name, mask, 0);
+ }
+ free_page((unsigned long)buffer);
+ }
+
+out:
+ aa_put_profile(profile);
+ return error;
+}
+
+static int apparmor_bprm_set_security(struct linux_binprm *bprm)
+{
+ /* handle capability bits with setuid, etc */
+ cap_bprm_set_security(bprm);
+ /* already set based on script name */
+ if (bprm->sh_bang)
+ return 0;
+ return aa_register(bprm);
+}
+
+static int apparmor_bprm_secureexec(struct linux_binprm *bprm)
+{
+ int ret = cap_bprm_secureexec(bprm);
+
+ if (!ret && (unsigned long)bprm->security & AA_SECURE_EXEC_NEEDED) {
+ AA_DEBUG("%s: secureexec required for %s\n",
+ __FUNCTION__, bprm->filename);
+ ret = 1;
+ }
+
+ return ret;
+}
+
+static int apparmor_sb_mount(char *dev_name, struct nameidata *nd, char *type,
+ unsigned long flags, void *data)
+{
+ return aa_reject_syscall(current, GFP_KERNEL, "mount");
+}
+
+static int apparmor_umount(struct vfsmount *mnt, int flags)
+{
+ return aa_reject_syscall(current, GFP_KERNEL, "umount");
+}
+
+static int apparmor_inode_mkdir(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt, int mask)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ if (!mnt || !mediated_filesystem(dir))
+ goto out;
+
+ profile = aa_get_profile(current);
+
+ if (profile)
+ error = aa_perm_dir(profile, "inode_mkdir", dentry, mnt,
+ MAY_WRITE);
+
+ aa_put_profile(profile);
+
+out:
+ return error;
+}
+
+static int apparmor_inode_rmdir(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ if (!mnt || !mediated_filesystem(dir))
+ goto out;
+
+ profile = aa_get_profile(current);
+
+ if (profile)
+ error = aa_perm_dir(profile, "inode_rmdir", dentry, mnt,
+ MAY_WRITE);
+
+ aa_put_profile(profile);
+
+out:
+ return error;
+}
+
+static int aa_permission(const char *operation, struct inode *inode,
+ struct dentry *dentry, struct vfsmount *mnt,
+ int mask, int check)
+{
+ int error = 0;
+
+ if (mnt && mediated_filesystem(inode)) {
+ struct aa_profile *profile;
+
+ profile = aa_get_profile(current);
+ if (profile)
+ error = aa_perm(profile, operation, dentry, mnt, mask,
+ check);
+ aa_put_profile(profile);
+ }
+ return error;
+}
+
+static inline int aa_mask_permissions(int mask)
+{
+ if (mask & MAY_APPEND)
+ mask &= (MAY_READ | MAY_APPEND | MAY_EXEC);
+ else
+ mask &= (MAY_READ | MAY_WRITE | MAY_EXEC);
+ return mask;
+}
+
+static int apparmor_inode_create(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt, int mask)
+{
+ return aa_permission("inode_create", dir, dentry, mnt, MAY_APPEND, 0);
+}
+
+static int apparmor_inode_link(struct dentry *old_dentry,
+ struct vfsmount *old_mnt, struct inode *dir,
+ struct dentry *new_dentry,
+ struct vfsmount *new_mnt)
+{
+ int error = 0;
+ struct aa_profile *profile;
+
+ if (!old_mnt || !new_mnt || !mediated_filesystem(dir))
+ goto out;
+
+ profile = aa_get_profile(current);
+
+ if (profile)
+ error = aa_link(profile, new_dentry, new_mnt,
+ old_dentry, old_mnt);
+
+ aa_put_profile(profile);
+
+out:
+ return error;
+}
+
+static int apparmor_inode_unlink(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt)
+{
+ int check = 0;
+
+ if (S_ISDIR(dentry->d_inode->i_mode))
+ check |= AA_CHECK_DIR;
+ return aa_permission("inode_unlink", dir, dentry, mnt, MAY_WRITE,
+ check);
+}
+
+static int apparmor_inode_symlink(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt, const char *old_name)
+{
+ return aa_permission("inode_symlink", dir, dentry, mnt, MAY_WRITE, 0);
+}
+
+static int apparmor_inode_mknod(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt, int mode, dev_t dev)
+{
+ return aa_permission("inode_mknod", dir, dentry, mnt, MAY_WRITE, 0);
+}
+
+static int apparmor_inode_rename(struct inode *old_dir,
+ struct dentry *old_dentry,
+ struct vfsmount *old_mnt,
+ struct inode *new_dir,
+ struct dentry *new_dentry,
+ struct vfsmount *new_mnt)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ if ((!old_mnt && !new_mnt) || !mediated_filesystem(old_dir))
+ goto out;
+
+ profile = aa_get_profile(current);
+
+ if (profile) {
+ struct inode *inode = old_dentry->d_inode;
+ int check = 0;
+
+ if (inode && S_ISDIR(inode->i_mode))
+ check |= AA_CHECK_DIR;
+ if (old_mnt)
+ error = aa_perm(profile, "inode_rename", old_dentry,
+ old_mnt, MAY_READ | MAY_WRITE, check);
+
+ if (!error && new_mnt) {
+ error = aa_perm(profile, "inode_rename", new_dentry,
+ new_mnt, MAY_WRITE, check);
+ }
+ }
+
+ aa_put_profile(profile);
+
+out:
+ return error;
+}
+
+static int apparmor_inode_permission(struct inode *inode, int mask,
+ struct nameidata *nd)
+{
+ int check = 0;
+
+ if (!nd || nd->flags & (LOOKUP_PARENT | LOOKUP_CONTINUE))
+ return 0;
+ mask = aa_mask_permissions(mask);
+ if (S_ISDIR(inode->i_mode)) {
+ check |= AA_CHECK_DIR;
+ /* allow traverse accesses to directories */
+ mask &= ~MAY_EXEC;
+ }
+ return aa_permission("inode_permission", inode, nd->dentry, nd->mnt,
+ mask, check);
+}
+
+static int apparmor_inode_setattr(struct dentry *dentry, struct vfsmount *mnt,
+ struct iattr *iattr)
+{
+ int error = 0;
+
+ if (!mnt)
+ goto out;
+
+ if (mediated_filesystem(dentry->d_inode)) {
+ struct aa_profile *profile;
+
+ profile = aa_get_profile(current);
+ /*
+ * Mediate any attempt to change attributes of a file
+ * (chmod, chown, chgrp, etc)
+ */
+ if (profile)
+ error = aa_attr(profile, dentry, mnt, iattr);
+
+ aa_put_profile(profile);
+ }
+
+out:
+ return error;
+}
+
+static int aa_xattr_permission(struct dentry *dentry, struct vfsmount *mnt,
+ const char *operation, int mask,
+ struct file *file)
+{
+ int error = 0;
+
+ if (mnt && mediated_filesystem(dentry->d_inode)) {
+ struct aa_profile *profile = aa_get_profile(current);
+ int check = file ? AA_CHECK_FD : 0;
+
+ if (profile)
+ error = aa_perm_xattr(profile, operation, dentry, mnt,
+ mask, check);
+ aa_put_profile(profile);
+ }
+
+ return error;
+}
+
+static int apparmor_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
+ char *name, void *value, size_t size,
+ int flags, struct file *file)
+{
+ return aa_xattr_permission(dentry, mnt, "xattr set", MAY_WRITE, file);
+}
+
+static int apparmor_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
+ char *name, struct file *file)
+{
+ return aa_xattr_permission(dentry, mnt, "xattr get", MAY_READ, file);
+}
+
+static int apparmor_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt,
+ struct file *file)
+{
+ return aa_xattr_permission(dentry, mnt, "xattr list", MAY_READ, file);
+}
+
+static int apparmor_inode_removexattr(struct dentry *dentry,
+ struct vfsmount *mnt, char *name,
+ struct file *file)
+{
+ return aa_xattr_permission(dentry, mnt, "xattr remove", MAY_WRITE,
+ file);
+}
+
+static int aa_file_permission(const char *op, 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 || mask & AA_MAY_LOCK)) {
+ struct dentry *dentry = file->f_dentry;
+ struct vfsmount *mnt = file->f_vfsmnt;
+ struct inode *inode = dentry->d_inode;
+ int check = AA_CHECK_FD;
+
+ /*
+ * FIXME: We should remember which profiles we revalidated
+ * against.
+ */
+ if (S_ISDIR(inode->i_mode))
+ check |= AA_CHECK_DIR;
+ error = aa_permission(op, inode, dentry, mnt, mask, check);
+ }
+ aa_put_profile(profile);
+
+out:
+ return error;
+}
+
+static int apparmor_file_permission(struct file *file, int mask)
+{
+ return aa_file_permission("file_permission", file,
+ aa_mask_permissions(mask));
+}
+
+static inline int apparmor_file_lock (struct file *file, unsigned int cmd)
+{
+ int mask = AA_MAY_LOCK;
+ if (cmd == F_WRLCK)
+ mask |= MAY_WRITE;
+ return aa_file_permission("file_lock", file, mask);
+}
+
+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, const char *operation,
+ unsigned long prot, unsigned long flags)
+{
+ struct dentry *dentry;
+ int mask = 0;
+
+ if (!file || !file->f_security)
+ return 0;
+
+ if (prot & PROT_READ)
+ mask |= MAY_READ;
+ /* Private mappings don't require write perms since they don't
+ * write back to the files */
+ if ((prot & PROT_WRITE) && !(flags & MAP_PRIVATE))
+ mask |= MAY_WRITE;
+ if (prot & PROT_EXEC)
+ mask |= AA_EXEC_MMAP;
+
+ dentry = file->f_dentry;
+ return aa_permission(operation, dentry->d_inode, dentry,
+ file->f_vfsmnt, mask, AA_CHECK_FD);
+}
+
+static int apparmor_file_mmap(struct file *file, unsigned long reqprot,
+ unsigned long prot, unsigned long flags,
+ unsigned long addr, unsigned long addr_only)
+{
+ if ((addr < mmap_min_addr) && !capable(CAP_SYS_RAWIO)) {
+ struct aa_profile *profile = aa_get_profile(current);
+ if (profile)
+ /* future control check here */
+ return -EACCES;
+ else
+ return -EACCES;
+ aa_put_profile(profile);
+ }
+
+ return aa_mmap(file, "file_mmap", prot, flags);
+}
+
+static int apparmor_file_mprotect(struct vm_area_struct *vma,
+ unsigned long reqprot, unsigned long prot)
+{
+ return aa_mmap(vma->vm_file, "file_mprotect", prot,
+ !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
+}
+
+static int apparmor_task_alloc_security(struct task_struct *task)
+{
+ return aa_clone(task);
+}
+
+/*
+ * Called from IRQ context from RCU callback.
+ */
+static void apparmor_task_free_security(struct task_struct *task)
+{
+ aa_release(task);
+}
+
+static int apparmor_getprocattr(struct task_struct *task, char *name,
+ char **value)
+{
+ unsigned len;
+ int error;
+ struct aa_profile *profile;
+
+ /* AppArmor only supports the "current" process attribute */
+ if (strcmp(name, "current") != 0)
+ return -EINVAL;
+
+ /* must be task querying itself or admin */
+ if (current != task && !capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ profile = aa_get_profile(task);
+ error = aa_getprocattr(profile, value, &len);
+ aa_put_profile(profile);
+ if (!error)
+ error = len;
+
+ return error;
+}
+
+static int apparmor_setprocattr(struct task_struct *task, char *name,
+ void *value, size_t size)
+{
+ char *command, *args;
+ int error;
+
+ if (strcmp(name, "current") != 0 || size == 0 || size >= PAGE_SIZE)
+ return -EINVAL;
+ args = value;
+ args[size] = '\0';
+ args = strstrip(args);
+ command = strsep(&args, " ");
+ if (!args)
+ return -EINVAL;
+ while (isspace(*args))
+ args++;
+ if (!*args)
+ return -EINVAL;
+
+ if (strcmp(command, "changehat") == 0) {
+ if (current != task)
+ return -EACCES;
+ error = aa_setprocattr_changehat(args);
+ } else if (strcmp(command, "changeprofile") == 0) {
+ if (current != task)
+ return -EACCES;
+ error = aa_setprocattr_changeprofile(args);
+ } else if (strcmp(command, "setprofile") == 0) {
+ struct aa_profile *profile;
+
+ /* Only an unconfined process with admin capabilities
+ * may change the profile of another task.
+ */
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ profile = aa_get_profile(current);
+ if (profile) {
+ struct aa_audit sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.operation = "profile_set";
+ sa.gfp_mask = GFP_KERNEL;
+ sa.task = task->pid;
+ sa.info = "from confined process";
+ aa_audit_reject(profile, &sa);
+ aa_put_profile(profile);
+ return -EACCES;
+ }
+ error = aa_setprocattr_setprofile(task, args);
+ } else {
+ struct aa_audit sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.operation = "setprocattr";
+ sa.gfp_mask = GFP_KERNEL;
+ sa.info = "invalid command";
+ sa.name = command;
+ sa.task = task->pid;
+ aa_audit_reject(NULL, &sa);
+ return -EINVAL;
+ }
+
+ if (!error)
+ error = size;
+ return error;
+}
+
+struct security_operations apparmor_ops = {
+ .ptrace = apparmor_ptrace,
+ .capget = cap_capget,
+ .capset_check = cap_capset_check,
+ .capset_set = cap_capset_set,
+ .sysctl = apparmor_sysctl,
+ .capable = apparmor_capable,
+ .syslog = cap_syslog,
+
+ .netlink_send = cap_netlink_send,
+ .netlink_recv = cap_netlink_recv,
+
+ .bprm_apply_creds = cap_bprm_apply_creds,
+ .bprm_set_security = apparmor_bprm_set_security,
+ .bprm_secureexec = apparmor_bprm_secureexec,
+
+ .sb_mount = apparmor_sb_mount,
+ .sb_umount = apparmor_umount,
+
+ .inode_mkdir = apparmor_inode_mkdir,
+ .inode_rmdir = apparmor_inode_rmdir,
+ .inode_create = apparmor_inode_create,
+ .inode_link = apparmor_inode_link,
+ .inode_unlink = apparmor_inode_unlink,
+ .inode_symlink = apparmor_inode_symlink,
+ .inode_mknod = apparmor_inode_mknod,
+ .inode_rename = apparmor_inode_rename,
+ .inode_permission = apparmor_inode_permission,
+ .inode_setattr = apparmor_inode_setattr,
+ .inode_setxattr = apparmor_inode_setxattr,
+ .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,
+ .file_lock = apparmor_file_lock,
+
+ .task_alloc_security = apparmor_task_alloc_security,
+ .task_free_security = apparmor_task_free_security,
+ .task_post_setuid = cap_task_post_setuid,
+ .task_reparent_to_init = cap_task_reparent_to_init,
+
+ .getprocattr = apparmor_getprocattr,
+ .setprocattr = apparmor_setprocattr,
+};
+
+void info_message(const char *str)
+{
+ struct aa_audit sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.gfp_mask = GFP_KERNEL;
+ sa.info = str;
+ printk(KERN_INFO "AppArmor: %s\n", str);
+ if (audit_enabled)
+ aa_audit_message(NULL, &sa, AUDIT_APPARMOR_STATUS);
+}
+
+static int __init apparmor_init(void)
+{
+ int error;
+
+ if (!apparmor_enabled) {
+ info_message("AppArmor disabled by boottime parameter\n");
+ return 0;
+ }
+
+ if ((error = create_apparmorfs())) {
+ AA_ERROR("Unable to activate AppArmor filesystem\n");
+ goto createfs_out;
+ }
+
+ if ((error = alloc_default_namespace())){
+ AA_ERROR("Unable to allocate default profile namespace\n");
+ goto alloc_out;
+ }
+
+ if ((error = register_security(&apparmor_ops))) {
+ AA_ERROR("Unable to register AppArmor\n");
+ goto register_security_out;
+ }
+
+ /* Report that AppArmor successfully initialized */
+ apparmor_initialized = 1;
+ if (apparmor_complain)
+ info_message("AppArmor initialized: complainmode enabled");
+ else
+ info_message("AppArmor initialized");
+
+ return error;
+
+register_security_out:
+ free_default_namespace();
+
+alloc_out:
+ destroy_apparmorfs();
+
+createfs_out:
+ return error;
+
+}
+
+security_initcall(apparmor_init);
+
+void apparmor_disable(void)
+{
+ /* Remove and release all the profiles on the profile list. */
+ mutex_lock(&aa_interface_lock);
+ aa_profile_ns_list_release();
+
+ /* FIXME: cleanup profiles references on files */
+ free_default_namespace();
+
+ /*
+ * Delay for an rcu cycle to make sure that all active task
+ * context readers have finished, and all profiles have been
+ * freed by their rcu callbacks.
+ */
+ synchronize_rcu();
+
+ destroy_apparmorfs();
+ mutex_unlock(&aa_interface_lock);
+
+ apparmor_initialized = 0;
+
+ info_message("AppArmor protection removed");
+}
+
+MODULE_DESCRIPTION("AppArmor process confinement");
+MODULE_AUTHOR("Novell/Immunix, http://bugs.opensuse.org");
+MODULE_LICENSE("GPL");

View file

@ -1,59 +0,0 @@
---
security/apparmor/main.c | 23 ++++++++++++++---------
1 file changed, 14 insertions(+), 9 deletions(-)
--- a/security/apparmor/main.c
+++ b/security/apparmor/main.c
@@ -172,15 +172,18 @@ escape:
static char *aa_get_name(struct dentry *dentry, struct vfsmount *mnt,
char **buffer, int check)
{
- char *name;
+ char *buf = NULL, *name;
int is_dir, size = 256;
is_dir = (check & AA_CHECK_DIR) ? 1 : 0;
for (;;) {
- char *buf = kmalloc(size, GFP_KERNEL);
- if (!buf)
- return ERR_PTR(-ENOMEM);
+ char *b = krealloc(buf, size, GFP_KERNEL);
+
+ name = ERR_PTR(-ENOMEM);
+ if (!b)
+ break;
+ buf = b;
name = d_namespace_path(dentry, mnt, buf, size - is_dir);
@@ -195,8 +198,8 @@ static char *aa_get_name(struct dentry *
* This dentry is not connected to the
* namespace root -- reject access.
*/
- kfree(buf);
- return ERR_PTR(-ENOENT);
+ name = ERR_PTR(-ENOENT);
+ break;
}
if (is_dir && name[1] != '\0') {
/*
@@ -212,13 +215,15 @@ static char *aa_get_name(struct dentry *
return name;
}
if (PTR_ERR(name) != -ENAMETOOLONG)
- return name;
+ break;
- kfree(buf);
size <<= 1;
+ name = ERR_PTR(-ENAMETOOLONG);
if (size > apparmor_path_max)
- return ERR_PTR(-ENAMETOOLONG);
+ break;
}
+ kfree(buf);
+ return name;
}
static inline void aa_put_name_buffer(char *buffer)

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,408 +0,0 @@
From: John Johansen <jjohansen@suse.de>
Subject: AppArmor: Simplified network controls for AppArmor
Simple network control determining which network families a confined
application has access to.
Signed-off-by: John Johansen <jjohansen@suse.de>
---
security/apparmor/Makefile | 7 +
security/apparmor/apparmor.h | 9 ++
security/apparmor/lsm.c | 129 ++++++++++++++++++++++++++++++++++-
security/apparmor/main.c | 107 ++++++++++++++++++++++++++++-
security/apparmor/module_interface.c | 26 ++++++-
5 files changed, 271 insertions(+), 7 deletions(-)
--- a/security/apparmor/Makefile
+++ b/security/apparmor/Makefile
@@ -8,6 +8,11 @@ apparmor-y := main.o list.o procattr.o l
quiet_cmd_make-caps = GEN $@
cmd_make-caps = sed -n -e "/CAP_FS_MASK/d" -e "s/^\#define[ \\t]\\+CAP_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\$$/[\\2] = \"\\1\",/p" $< | tr A-Z a-z > $@
-$(obj)/main.o : $(obj)/capability_names.h
+quiet_cmd_make-af = GEN $@
+cmd_make-af = sed -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e "s/^\#define[ \\t]\\+AF_\\([A-Z0-9_]\\+\\)[ \\t]\\+\\([0-9]\\+\\)\\(.*\\)\$$/[\\2] = \"\\1\",/p" $< | tr A-Z a-z > $@
+
+$(obj)/main.o : $(obj)/capability_names.h $(obj)/af_names.h
$(obj)/capability_names.h : $(srctree)/include/linux/capability.h
$(call cmd,make-caps)
+$(obj)/af_names.h : $(srctree)/include/linux/socket.h
+ $(call cmd,make-af)
--- a/security/apparmor/apparmor.h
+++ b/security/apparmor/apparmor.h
@@ -16,6 +16,8 @@
#include <linux/fs.h>
#include <linux/binfmts.h>
#include <linux/rcupdate.h>
+#include <linux/socket.h>
+#include <net/sock.h>
/*
* We use MAY_READ, MAY_WRITE, MAY_EXEC, MAY_APPEND and the following flags
@@ -208,6 +210,9 @@ struct aa_profile {
struct list_head task_contexts;
spinlock_t lock;
unsigned long int_flags;
+ u16 network_families[AF_MAX];
+ u16 audit_network[AF_MAX];
+ u16 quiet_network[AF_MAX];
};
extern struct list_head profile_ns_list;
@@ -254,6 +259,7 @@ struct aa_audit {
int request_mask, denied_mask, audit_mask;
struct iattr *iattr;
pid_t task, parent;
+ int family, type, protocol;
int error_code;
};
@@ -315,6 +321,9 @@ extern void aa_change_task_context(struc
struct aa_profile *previous_profile);
extern int aa_may_ptrace(struct aa_task_context *cxt,
struct aa_profile *tracee);
+extern int aa_net_perm(struct aa_profile *profile, char *operation,
+ int family, int type, int protocol);
+extern int aa_revalidate_sk(struct sock *sk, char *operation);
/* lsm.c */
extern int apparmor_initialized;
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -18,6 +18,7 @@
#include <linux/ctype.h>
#include <linux/sysctl.h>
#include <linux/audit.h>
+#include <net/sock.h>
#include "apparmor.h"
#include "inline.h"
@@ -663,6 +664,117 @@ static void apparmor_task_free_security(
aa_release(task);
}
+static int apparmor_socket_create(int family, int type, int protocol, int kern)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ if (kern)
+ return 0;
+
+ profile = aa_get_profile(current);
+ if (profile)
+ error = aa_net_perm(profile, "socket_create", family,
+ type, protocol);
+ aa_put_profile(profile);
+
+ return error;
+}
+
+static int apparmor_socket_post_create(struct socket *sock, int family,
+ int type, int protocol, int kern)
+{
+ struct sock *sk = sock->sk;
+
+ if (kern)
+ return 0;
+
+ return aa_revalidate_sk(sk, "socket_post_create");
+}
+
+static int apparmor_socket_bind(struct socket *sock,
+ struct sockaddr *address, int addrlen)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(sk, "socket_bind");
+}
+
+static int apparmor_socket_connect(struct socket *sock,
+ struct sockaddr *address, int addrlen)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(sk, "socket_connect");
+}
+
+static int apparmor_socket_listen(struct socket *sock, int backlog)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(sk, "socket_listen");
+}
+
+static int apparmor_socket_accept(struct socket *sock, struct socket *newsock)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(sk, "socket_accept");
+}
+
+static int apparmor_socket_sendmsg(struct socket *sock,
+ struct msghdr *msg, int size)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(sk, "socket_sendmsg");
+}
+
+static int apparmor_socket_recvmsg(struct socket *sock,
+ struct msghdr *msg, int size, int flags)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(sk, "socket_recvmsg");
+}
+
+static int apparmor_socket_getsockname(struct socket *sock)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(sk, "socket_getsockname");
+}
+
+static int apparmor_socket_getpeername(struct socket *sock)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(sk, "socket_getpeername");
+}
+
+static int apparmor_socket_getsockopt(struct socket *sock, int level,
+ int optname)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(sk, "socket_getsockopt");
+}
+
+static int apparmor_socket_setsockopt(struct socket *sock, int level,
+ int optname)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(sk, "socket_setsockopt");
+}
+
+static int apparmor_socket_shutdown(struct socket *sock, int how)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(sk, "socket_shutdown");
+}
+
static int apparmor_getprocattr(struct task_struct *task, char *name,
char **value)
{
@@ -763,9 +875,6 @@ struct security_operations apparmor_ops
.capable = apparmor_capable,
.syslog = cap_syslog,
- .netlink_send = cap_netlink_send,
- .netlink_recv = cap_netlink_recv,
-
.bprm_apply_creds = cap_bprm_apply_creds,
.bprm_set_security = apparmor_bprm_set_security,
.bprm_secureexec = apparmor_bprm_secureexec,
@@ -801,6 +910,20 @@ struct security_operations apparmor_ops
.getprocattr = apparmor_getprocattr,
.setprocattr = apparmor_setprocattr,
+
+ .socket_create = apparmor_socket_create,
+ .socket_post_create = apparmor_socket_post_create,
+ .socket_bind = apparmor_socket_bind,
+ .socket_connect = apparmor_socket_connect,
+ .socket_listen = apparmor_socket_listen,
+ .socket_accept = apparmor_socket_accept,
+ .socket_sendmsg = apparmor_socket_sendmsg,
+ .socket_recvmsg = apparmor_socket_recvmsg,
+ .socket_getsockname = apparmor_socket_getsockname,
+ .socket_getpeername = apparmor_socket_getpeername,
+ .socket_getsockopt = apparmor_socket_getsockopt,
+ .socket_setsockopt = apparmor_socket_setsockopt,
+ .socket_shutdown = apparmor_socket_shutdown,
};
void info_message(const char *str)
--- a/security/apparmor/main.c
+++ b/security/apparmor/main.c
@@ -14,6 +14,9 @@
#include <linux/audit.h>
#include <linux/mount.h>
#include <linux/ptrace.h>
+#include <linux/socket.h>
+#include <linux/net.h>
+#include <net/sock.h>
#include "apparmor.h"
@@ -116,6 +119,24 @@ static void aa_audit_file_mask(struct au
audit_log_format(ab, " %s=\"%s::%s\"", name, user, other);
}
+static const char *address_families[] = {
+#include "af_names.h"
+};
+
+static const char *sock_types[] = {
+ "unknown(0)",
+ "stream",
+ "dgram",
+ "raw",
+ "rdm",
+ "seqpacket",
+ "dccp",
+ "unknown(7)",
+ "unknown(8)",
+ "unknown(9)",
+ "packet",
+};
+
/**
* aa_audit - Log an audit event to the audit subsystem
* @profile: profile to check against
@@ -187,7 +208,25 @@ static int aa_audit_base(struct aa_profi
audit_log_untrustedstring(ab, sa->name2);
}
- audit_log_format(ab, " pid=%d", current->pid);
+ if (sa->family || sa->type) {
+ if (address_families[sa->family])
+ audit_log_format(ab, " family=\"%s\"",
+ address_families[sa->family]);
+ else
+ audit_log_format(ab, " family=\"unknown(%d)\"",
+ sa->family);
+
+ if (sock_types[sa->type])
+ audit_log_format(ab, " sock_type=\"%s\"",
+ sock_types[sa->type]);
+ else
+ audit_log_format(ab, " sock_type=\"unknown(%d)\"",
+ sa->type);
+
+ audit_log_format(ab, " protocol=%d", sa->protocol);
+ }
+
+ audit_log_format(ab, " pid=%d", current->pid);
if (profile) {
audit_log_format(ab, " profile=");
@@ -768,6 +807,72 @@ int aa_link(struct aa_profile *profile,
return error;
}
+int aa_net_perm(struct aa_profile *profile, char *operation,
+ int family, int type, int protocol)
+{
+ struct aa_audit sa;
+ int error = 0;
+ u16 family_mask, audit_mask, quiet_mask;
+
+ if ((family < 0) || (family >= AF_MAX))
+ return -EINVAL;
+
+ if ((type < 0) || (type >= SOCK_MAX))
+ return -EINVAL;
+
+ /* unix domain and netlink sockets are handled by ipc */
+ if (family == AF_UNIX || family == AF_NETLINK)
+ return 0;
+
+ family_mask = profile->network_families[family];
+ audit_mask = profile->audit_network[family];
+ quiet_mask = profile->quiet_network[family];
+
+ error = (family_mask & (1 << type)) ? 0 : -EACCES;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.operation = operation;
+ sa.gfp_mask = GFP_KERNEL;
+ sa.family = family;
+ sa.type = type;
+ sa.protocol = protocol;
+ sa.error_code = error;
+
+ if (likely(!error)) {
+ if (!PROFILE_AUDIT(profile) && !(family_mask & audit_mask))
+ return 0;
+ } else if (!((1 << type) & ~quiet_mask)) {
+ return error;
+ }
+
+ error = aa_audit(profile, &sa);
+
+ return error;
+}
+
+int aa_revalidate_sk(struct sock *sk, char *operation)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ /* this is some debugging code to flush out the network hooks that
+ that are called in interrupt context */
+ if (in_interrupt()) {
+ printk("AppArmor Debug: Hook being called from interrupt context\n");
+ dump_stack();
+ return 0;
+ }
+
+ profile = aa_get_profile(current);
+ if (profile)
+ error = aa_net_perm(profile, operation,
+ sk->sk_family, sk->sk_type,
+ sk->sk_protocol);
+ aa_put_profile(profile);
+
+ return error;
+}
+
/*******************************
* Global task related functions
*******************************/
--- a/security/apparmor/module_interface.c
+++ b/security/apparmor/module_interface.c
@@ -320,8 +320,8 @@ static struct aa_profile *aa_unpack_prof
struct aa_audit *sa)
{
struct aa_profile *profile = NULL;
-
- int error = -EPROTO;
+ size_t size = 0;
+ int i, error = -EPROTO;
profile = alloc_aa_profile();
if (!profile)
@@ -354,6 +354,28 @@ static struct aa_profile *aa_unpack_prof
if (!aa_is_u32(e, &(profile->set_caps), NULL))
goto fail;
+ size = aa_is_array(e, "net_allowed_af");
+ if (size) {
+ if (size > AF_MAX)
+ goto fail;
+
+ for (i = 0; i < size; i++) {
+ if (!aa_is_u16(e, &profile->network_families[i], NULL))
+ goto fail;
+ if (!aa_is_u16(e, &profile->audit_network[i], NULL))
+ goto fail;
+ if (!aa_is_u16(e, &profile->quiet_network[i], NULL))
+ goto fail;
+ }
+ if (!aa_is_nameX(e, AA_ARRAYEND, NULL))
+ goto fail;
+ /* allow unix domain and netlink sockets they are handled
+ * by IPC
+ */
+ }
+ profile->network_families[AF_UNIX] = 0xffff;
+ profile->network_families[AF_NETLINK] = 0xffff;
+
/* get file rules */
profile->file_rules = aa_unpack_dfa(e);
if (IS_ERR(profile->file_rules)) {

View file

@ -1,461 +0,0 @@
From: John Johansen <jjohansen@suse.de>
Subject: AppArmor: per profile controls for system rlimits
Provide contol of rlimits on a per profile basis. Each profile provides
a per limit contol and corresponding hard limit value, such that when a
profile becomes attached to a task it sets the tasks limits to be <= to
the profiles specified limits. Note: the profile limit value will not
raise a tasks limit if it is already less than the profile mandates.
In addition to setting a tasks limits, the ability to set limits on
a confined task are controlled. AppArmor only controls the raising
of a tasks limits Tasks with CAP_SYS_RESOURCE can have their hard limits
raised up to the value specified by the profile. AppArmor does not
prevent a task for lowering its hard limits, nor does it provide
additional control on soft limits.
AppArmor only controls the limits specified in a profile so that
any limit not specified is free to be modified subject to standard
linux limitations.
---
security/apparmor/apparmor.h | 23 ++++++
security/apparmor/apparmorfs.c | 2
security/apparmor/lsm.c | 16 ++++
security/apparmor/main.c | 132 +++++++++++++++++++++++++++++++----
security/apparmor/module_interface.c | 56 ++++++++++++++
5 files changed, 215 insertions(+), 14 deletions(-)
--- a/security/apparmor/apparmor.h
+++ b/security/apparmor/apparmor.h
@@ -16,6 +16,7 @@
#include <linux/fs.h>
#include <linux/binfmts.h>
#include <linux/rcupdate.h>
+#include <linux/resource.h>
#include <linux/socket.h>
#include <net/sock.h>
@@ -136,6 +137,18 @@ extern unsigned int apparmor_path_max;
#define AA_ERROR(fmt, args...) printk(KERN_ERR "AppArmor: " fmt, ##args)
+/* struct aa_rlimit - rlimits settings for the profile
+ * @mask: which hard limits to set
+ * @limits: rlimit values that override task limits
+ *
+ * AppArmor rlimits are used to set confined task rlimits. Only the
+ * limits specified in @mask will be controlled by apparmor.
+ */
+struct aa_rlimit {
+ unsigned int mask;
+ struct rlimit limits[RLIM_NLIMITS];
+};
+
struct aa_profile;
/* struct aa_namespace - namespace for a set of profiles
@@ -170,6 +183,8 @@ struct aa_namespace {
* @audit_caps: caps that are to be audited
* @quiet_caps: caps that should not be audited
* @capabilities: capabilities granted by the process
+ * @rlimits: rlimits for the profile
+ * @task_count: how many tasks the profile is attached to
* @count: reference count of the profile
* @task_contexts: list of tasks confined by profile
* @lock: lock for the task_contexts list
@@ -206,6 +221,9 @@ struct aa_profile {
kernel_cap_t audit_caps;
kernel_cap_t quiet_caps;
+ struct aa_rlimit rlimits;
+ unsigned int task_count;
+
struct kref count;
struct list_head task_contexts;
spinlock_t lock;
@@ -257,6 +275,7 @@ struct aa_audit {
const char *name2;
const char *name3;
int request_mask, denied_mask, audit_mask;
+ int rlimit;
struct iattr *iattr;
pid_t task, parent;
int family, type, protocol;
@@ -324,6 +343,10 @@ extern int aa_may_ptrace(struct aa_task_
extern int aa_net_perm(struct aa_profile *profile, char *operation,
int family, int type, int protocol);
extern int aa_revalidate_sk(struct sock *sk, char *operation);
+extern int aa_task_setrlimit(struct aa_profile *profile, unsigned int resource,
+ struct rlimit *new_rlim);
+extern void aa_set_rlimits(struct task_struct *task, struct aa_profile *profile);
+
/* lsm.c */
extern int apparmor_initialized;
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -105,7 +105,7 @@ static ssize_t aa_features_read(struct f
{
const char *features = "file=3.0 capability=2.0 network=1.0 "
"change_hat=1.4 change_profile=1.0 "
- "aanamespaces=1.0";
+ "aanamespaces=1.0 rlimit=1.0";
return simple_read_from_buffer(buf, size, ppos, features,
strlen(features));
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -866,6 +866,21 @@ static int apparmor_setprocattr(struct t
return error;
}
+static int apparmor_task_setrlimit(unsigned int resource,
+ struct rlimit *new_rlim)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ profile = aa_get_profile(current);
+ if (profile) {
+ error = aa_task_setrlimit(profile, resource, new_rlim);
+ }
+ aa_put_profile(profile);
+
+ return error;
+}
+
struct security_operations apparmor_ops = {
.ptrace = apparmor_ptrace,
.capget = cap_capget,
@@ -907,6 +922,7 @@ struct security_operations apparmor_ops
.task_free_security = apparmor_task_free_security,
.task_post_setuid = cap_task_post_setuid,
.task_reparent_to_init = cap_task_reparent_to_init,
+ .task_setrlimit = apparmor_task_setrlimit,
.getprocattr = apparmor_getprocattr,
.setprocattr = apparmor_setprocattr,
--- a/security/apparmor/main.c
+++ b/security/apparmor/main.c
@@ -177,6 +177,9 @@ static int aa_audit_base(struct aa_profi
if (sa->request_mask)
audit_log_format(ab, " fsuid=%d", current->fsuid);
+ if (sa->rlimit)
+ audit_log_format(ab, " rlimit=%d", sa->rlimit - 1);
+
if (sa->iattr) {
struct iattr *iattr = sa->iattr;
@@ -872,6 +875,79 @@ int aa_revalidate_sk(struct sock *sk, ch
return error;
}
+/**
+ * aa_task_setrlimit - test permission to set an rlimit
+ * @profile - profile confining the task
+ * @resource - the resource being set
+ * @new_rlim - the new resource limit
+ *
+ * Control raising the processes hard limit.
+ */
+int aa_task_setrlimit(struct aa_profile *profile, unsigned int resource,
+ struct rlimit *new_rlim)
+{
+ struct aa_audit sa;
+ int error = 0;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.operation = "setrlimit";
+ sa.gfp_mask = GFP_KERNEL;
+ sa.rlimit = resource + 1;
+
+ if (profile->rlimits.mask & (1 << resource) &&
+ new_rlim->rlim_max > profile->rlimits.limits[resource].rlim_max) {
+ sa.error_code = -EACCES;
+
+ error = aa_audit(profile, &sa);
+ }
+
+ return error;
+}
+
+static int aa_rlimit_nproc(struct aa_profile *profile) {
+ if (profile && (profile->rlimits.mask & (1 << RLIMIT_NPROC)) &&
+ profile->task_count >= profile->rlimits.limits[RLIMIT_NPROC].rlim_max)
+ return -EAGAIN;
+ return 0;
+}
+
+void aa_set_rlimits(struct task_struct *task, struct aa_profile *profile)
+{
+ int i, mask;
+
+ if (!profile)
+ return;
+
+ if (!profile->rlimits.mask)
+ return;
+
+ task_lock(task->group_leader);
+ mask = 1;
+ for (i = 0; i < RLIM_NLIMITS; i++, mask <<= 1) {
+ struct rlimit new_rlim, *old_rlim;
+
+ /* check to see if NPROC which is per profile and handled
+ * in clone/exec or whether this is a limit to be set
+ * can't set cpu limit either right now
+ */
+ if (i == RLIMIT_NPROC || i == RLIMIT_CPU)
+ continue;
+
+ old_rlim = task->signal->rlim + i;
+ new_rlim = *old_rlim;
+
+ if (mask & profile->rlimits.mask &&
+ profile->rlimits.limits[i].rlim_max < new_rlim.rlim_max) {
+ new_rlim.rlim_max = profile->rlimits.limits[i].rlim_max;
+ /* soft limit should not exceed hard limit */
+ if (new_rlim.rlim_cur > new_rlim.rlim_max)
+ new_rlim.rlim_cur = new_rlim.rlim_max;
+ }
+
+ *old_rlim = new_rlim;
+ }
+ task_unlock(task->group_leader);
+}
/*******************************
* Global task related functions
@@ -885,6 +961,7 @@ int aa_revalidate_sk(struct sock *sk, ch
*/
int aa_clone(struct task_struct *child)
{
+ struct aa_audit sa;
struct aa_task_context *cxt, *child_cxt;
struct aa_profile *profile;
@@ -894,6 +971,11 @@ int aa_clone(struct task_struct *child)
if (!child_cxt)
return -ENOMEM;
+ memset(&sa, 0, sizeof(sa));
+ sa.operation = "clone";
+ sa.task = child->pid;
+ sa.gfp_mask = GFP_KERNEL;
+
repeat:
profile = aa_get_profile(current);
if (profile) {
@@ -910,18 +992,22 @@ repeat:
goto repeat;
}
+ if (aa_rlimit_nproc(profile)) {
+ sa.info = "rlimit nproc limit exceeded";
+ unlock_profile(profile);
+ aa_audit_reject(profile, &sa);
+ aa_put_profile(profile);
+ return -EAGAIN;
+ }
+
/* No need to grab the child's task lock here. */
aa_change_task_context(child, child_cxt, profile,
cxt->cookie, cxt->previous_profile);
+
unlock_profile(profile);
if (APPARMOR_COMPLAIN(child_cxt) &&
profile == profile->ns->null_complain_profile) {
- struct aa_audit sa;
- memset(&sa, 0, sizeof(sa));
- sa.operation = "clone";
- sa.gfp_mask = GFP_KERNEL;
- sa.task = child->pid;
aa_audit_hint(profile, &sa);
}
aa_put_profile(profile);
@@ -1156,6 +1242,10 @@ repeat:
sa.task = current->parent->pid;
aa_audit_reject(profile, &sa);
}
+ if (PTR_ERR(old_profile) == -EAGAIN) {
+ sa.info = "rlimit nproc limit exceeded";
+ aa_audit_reject(profile, &sa);
+ }
new_profile = old_profile;
goto cleanup;
}
@@ -1296,6 +1386,12 @@ static int do_change_profile(struct aa_p
goto out;
}
+ if ((error = aa_rlimit_nproc(new_profile))) {
+ sa->info = "rlimit nproc limit exceeded";
+ aa_audit_reject(cxt->profile, sa);
+ goto out;
+ }
+
if (new_profile == ns->null_complain_profile)
aa_audit_hint(cxt->profile, sa);
@@ -1482,17 +1578,18 @@ struct aa_profile *__aa_replace_profile(
cxt = lock_task_and_profiles(task, profile);
if (unlikely(profile && profile->isstale)) {
- task_unlock(task);
- unlock_both_profiles(profile, cxt ? cxt->profile : NULL);
- aa_free_task_context(new_cxt);
- return ERR_PTR(-ESTALE);
+ old_profile = ERR_PTR(-ESTALE);
+ goto error;
}
if ((current->ptrace & PT_PTRACED) && aa_may_ptrace(cxt, profile)) {
- task_unlock(task);
- unlock_both_profiles(profile, cxt ? cxt->profile : NULL);
- aa_free_task_context(new_cxt);
- return ERR_PTR(-EPERM);
+ old_profile = ERR_PTR(-EPERM);
+ goto error;
+ }
+
+ if (aa_rlimit_nproc(profile)) {
+ old_profile = ERR_PTR(-EAGAIN);
+ goto error;
}
if (cxt)
@@ -1500,8 +1597,15 @@ struct aa_profile *__aa_replace_profile(
aa_change_task_context(task, new_cxt, profile, 0, NULL);
task_unlock(task);
+ aa_set_rlimits(task, profile);
unlock_both_profiles(profile, old_profile);
return old_profile;
+
+error:
+ task_unlock(task);
+ unlock_both_profiles(profile, cxt ? cxt->profile : NULL);
+ aa_free_task_context(new_cxt);
+ return old_profile;
}
/**
@@ -1566,6 +1670,7 @@ void aa_change_task_context(struct task_
if (old_cxt) {
list_del_init(&old_cxt->list);
+ old_cxt->profile->task_count--;
call_rcu(&old_cxt->rcu, free_aa_task_context_rcu_callback);
}
if (new_cxt) {
@@ -1577,6 +1682,7 @@ void aa_change_task_context(struct task_
new_cxt->cookie = cookie;
new_cxt->task = task;
new_cxt->profile = aa_dup_profile(profile);
+ profile->task_count++;
new_cxt->previous_profile = aa_dup_profile(previous_profile);
list_move(&new_cxt->list, &profile->task_contexts);
}
--- a/security/apparmor/module_interface.c
+++ b/security/apparmor/module_interface.c
@@ -177,6 +177,22 @@ fail:
return 0;
}
+static int aa_is_u64(struct aa_ext *e, u64 *data, const char *name)
+{
+ void *pos = e->pos;
+ if (aa_is_nameX(e, AA_U64, name)) {
+ if (!aa_inbounds(e, sizeof(u64)))
+ goto fail;
+ if (data)
+ *data = le64_to_cpu(get_unaligned((u64 *)e->pos));
+ e->pos += sizeof(u64);
+ return 1;
+ }
+fail:
+ e->pos = pos;
+ return 0;
+}
+
static size_t aa_is_array(struct aa_ext *e, const char *name)
{
void *pos = e->pos;
@@ -311,6 +327,39 @@ fail:
return 0;
}
+int aa_unpack_rlimits(struct aa_ext *e, struct aa_profile *profile)
+{
+ void *pos = e->pos;
+
+ /* rlimits are optional */
+ if (aa_is_nameX(e, AA_STRUCT, "rlimits")) {
+ int i, size;
+ u32 tmp = 0;
+ if (!aa_is_u32(e, &tmp, NULL))
+ goto fail;
+ profile->rlimits.mask = tmp;
+
+ size = aa_is_array(e, NULL);
+ if (size != RLIM_NLIMITS)
+ goto fail;
+ for (i = 0; i < size; i++) {
+ u64 tmp = 0;
+ if (!aa_is_u64(e, &tmp, NULL))
+ goto fail;
+ profile->rlimits.limits[i].rlim_max = tmp;
+ }
+ if (!aa_is_nameX(e, AA_ARRAYEND, NULL))
+ goto fail;
+ if (!aa_is_nameX(e, AA_STRUCTEND, NULL))
+ goto fail;
+ }
+ return 1;
+
+fail:
+ e->pos = pos;
+ return 0;
+}
+
/**
* aa_unpack_profile - unpack a serialized profile
* @e: serialized data extent information
@@ -354,6 +403,9 @@ static struct aa_profile *aa_unpack_prof
if (!aa_is_u32(e, &(profile->set_caps), NULL))
goto fail;
+ if (!aa_unpack_rlimits(e, profile))
+ goto fail;
+
size = aa_is_array(e, "net_allowed_af");
if (size) {
if (size > AF_MAX)
@@ -613,6 +665,8 @@ ssize_t aa_replace_profile(void *udata,
sa.operation = "profile_load";
goto out;
}
+ /* do not fail replacement based off of profile's NPROC rlimit */
+
/*
* Replacement needs to allocate a new aa_task_context for each
* task confined by old_profile. To do this the profile locks
@@ -633,6 +687,7 @@ ssize_t aa_replace_profile(void *udata,
task_lock(task);
task_replace(task, new_cxt, new_profile);
task_unlock(task);
+ aa_set_rlimits(task, new_profile);
new_cxt = NULL;
}
unlock_both_profiles(old_profile, new_profile);
@@ -655,6 +710,7 @@ out:
*
* remove a profile from the profile list and all aa_task_context references
* to said profile.
+ * NOTE: removing confinement does not restore rlimits to preconfinemnet values
*/
ssize_t aa_remove_profile(char *name, size_t size)
{

View file

@ -1,73 +0,0 @@
---
security/apparmor/apparmor.h | 1 +
security/apparmor/match.c | 9 +++++++--
security/apparmor/match.h | 2 ++
3 files changed, 10 insertions(+), 2 deletions(-)
--- a/security/apparmor/apparmor.h
+++ b/security/apparmor/apparmor.h
@@ -87,6 +87,7 @@
AA_AUDIT_FIELD)
#define AA_VALID_PERM_MASK (AA_FILE_PERMS | AA_SHARED_PERMS)
+#define AA_VALID_PERM2_MASK 0x0fffffff
#define AA_SECURE_EXEC_NEEDED 1
--- a/security/apparmor/match.c
+++ b/security/apparmor/match.c
@@ -83,6 +83,7 @@ int unpack_dfa(struct aa_dfa *dfa, void
switch(table->td_id) {
case YYTD_ID_ACCEPT:
+ case YYTD_ID_ACCEPT2:
case YYTD_ID_BASE:
dfa->tables[table->td_id - 1] = table;
if (table->td_flags != YYTD_DATA32)
@@ -134,7 +135,8 @@ int verify_dfa(struct aa_dfa *dfa)
int error = -EPROTO;
/* check that required tables exist */
- if (!(dfa->tables[YYTD_ID_ACCEPT -1 ] &&
+ if (!(dfa->tables[YYTD_ID_ACCEPT - 1] &&
+ dfa->tables[YYTD_ID_ACCEPT2 - 1] &&
dfa->tables[YYTD_ID_DEF - 1] &&
dfa->tables[YYTD_ID_BASE - 1] &&
dfa->tables[YYTD_ID_NXT - 1] &&
@@ -144,7 +146,8 @@ int verify_dfa(struct aa_dfa *dfa)
/* accept.size == default.size == base.size */
state_count = dfa->tables[YYTD_ID_BASE - 1]->td_lolen;
if (!(state_count == dfa->tables[YYTD_ID_DEF - 1]->td_lolen &&
- state_count == dfa->tables[YYTD_ID_ACCEPT - 1]->td_lolen))
+ state_count == dfa->tables[YYTD_ID_ACCEPT - 1]->td_lolen &&
+ state_count == dfa->tables[YYTD_ID_ACCEPT2 - 1]->td_lolen))
goto out;
/* next.size == chk.size */
@@ -177,6 +180,8 @@ int verify_dfa(struct aa_dfa *dfa)
if (mode & ~AA_VALID_PERM_MASK)
goto out;
+ if (ACCEPT_TABLE2(dfa)[i] & ~AA_VALID_PERM2_MASK)
+ goto out;
/* if any exec modifier is set MAY_EXEC must be set */
if ((mode & AA_USER_EXEC_TYPE) && !(mode & AA_USER_EXEC))
--- a/security/apparmor/match.h
+++ b/security/apparmor/match.h
@@ -39,6 +39,7 @@ struct table_set_header {
#define YYTD_ID_DEF 4
#define YYTD_ID_EC 5
#define YYTD_ID_META 6
+#define YYTD_ID_ACCEPT2 7
#define YYTD_ID_NXT 8
@@ -60,6 +61,7 @@ struct table_header {
#define CHECK_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_CHK - 1]->td_data))
#define EQUIV_TABLE(DFA) ((u8 *)((DFA)->tables[YYTD_ID_EC - 1]->td_data))
#define ACCEPT_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT - 1]->td_data))
+#define ACCEPT_TABLE2(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT2 -1]->td_data))
struct aa_dfa {
struct table_header *tables[YYTD_ID_NXT];

View file

@ -1,141 +0,0 @@
---
Documentation/lsm/AppArmor-Security-Goal.txt | 134 +++++++++++++++++++++++++++
1 file changed, 134 insertions(+)
--- /dev/null
+++ b/Documentation/lsm/AppArmor-Security-Goal.txt
@@ -0,0 +1,134 @@
+AppArmor Security Goal
+Crispin Cowan, PhD
+MercenaryLinux.com
+
+This document specifies the security goal that AppArmor is intended to
+achieve, so that users can evaluate whether AppArmor will meet their
+needs, and kernel developers can evaluate whether AppArmor is living up
+to its claims. This document is *not* a general purpose explanation of
+how AppArmor works, nor is it an explanation for why one might want to
+use AppArmor rather than some other system.
+
+AppArmor is intended to limit system damage from attackers exploiting
+vulnerabilities in applications that the system hosts. The threat is
+that an attacker can cause a vulnerable application to do something
+unexpected and undesirable. AppArmor addresses this threat by confining
+the application to access only the resources it needs to access to
+execute properly, effectively imposing "least privilege" execution on
+the application.
+
+Applications interact with the rest of the system via resources
+including files, interprocess communication, networking, capabilities,
+and execution of other applications. The purpose of least privilege is
+to bound the damage that a malicious user or code can do by removing
+access to resources that the application does not need for its intended
+function. This is true for all access control systems, including AppArmor.
+
+The "attacker" is someone trying to gain the privileges of a process for
+themselves. For instance, a policy for a web server might grant read
+only access to most web documents, preventing an attacker who can
+corrupt the web server from defacing the web pages. A web server has
+access to the web server's local file system, and a network attacker
+trying to hack the web server does not have such file access. An e-mail
+attacker attempting to infect the recipient of the e-mail does not have
+access to the files that the victim user's mail client does. By limiting
+the scope of access for an application, AppArmor can limit the damage an
+attacker can do by exploiting vulnerabilities in applications.
+
+An "application" is one or more related processes performing a function,
+e.g. the gang of processes that constitute an Apache web server, or a
+Postfix mail server. AppArmor *only* confines processes that the
+AppArmor policy says it should confine, and other processes are
+permitted to do anything that DAC permits. This is sometimes known as a
+targeted security policy.
+
+AppArmor does not provide a "default" policy that applies to all
+processes. So to defend an entire host, you have to piece-wise confine
+each process that is exposed to potential attack. For instance, to
+defend a system against network attack, place AppArmor profiles around
+every application that accesses the network. This limits the damage a
+network attacker can do to the file system to only those files granted
+by the profiles for the network-available applications. Similarly, to
+defend a system against attack from the console, place AppArmor profiles
+around every application that accessed the keyboard and mouse. The
+system is "defended" in that the worst the attacker can do to corrupt
+the system is limited to the transitive closure of what the confined
+processes are allowed to access.
+
+AppArmor currently mediates access to files, ability to use POSIX.1e
+Capabilities, and coarse-grained control on network access. This is
+sufficient to prevent a confined process from *directly* corrupting the
+file system. It is not sufficient to prevent a confined process from
+*indirectly* corrupting the system by influencing some other process to
+do the dirty deed. But to do so requires a complicit process that can be
+manipulated through another channel such as IPC. A "complicit" process
+is either a malicious process the attacker somehow got control of, or is
+a process that is actively listening to IPC of some kind and can be
+corrupted via IPC.
+
+The only IPC that AppArmor mediates is access to named sockets, FIFOs,
+etc. that appear in the file system name space, a side effect of
+AppArmor's file access mediation. Future versions of AppArmor will
+mediate more resources, including finer grained network access controls,
+and controls on various forms of IPC.
+
+AppArmor specifies the programs to be confined and the resources they
+can access in a syntax similar to how users are accustomed to accessing
+those resources. So file access controls are specified using absolute
+paths with respect to the name space the process is in. POSIX.1e
+capabilities are specified by name. Network access controls currently
+are specified by simply naming the protocol that can be used e.g. tcp,
+udp, and in the future will be more general, resembling firewall rules.
+
+Thus the AppArmor security goal should be considered piecewise from the
+point of view of a single confined process: that process should only be
+able to access the resources specified in its profile:
+
+ * can only access files that are reachable in its name space by path
+ names matching its profile, and only with the permitted modes:
+ read, append, write, memory map, execute, and link
+ * can only use the POSIX.1e capabilities listed in the profile
+ * can only perform the network operations listed in the profile
+
+Security issues that AppArmor explicitly does *not* address:
+
+ * Processes that are not confined by AppArmor are not restricted in
+ any way by AppArmor. If an unconfined process is considered an
+ unacceptable threat, then confine additional applications until
+ adequate security is achieved.
+ * A process that is not permitted to directly access a resource can
+ influence some other process that does have access to the resource
+ may do so, if the "influence" is a permitted action.
+ * A confined process may only access a file if it has at least one
+ of the files aliases specified in its profile. If a file alias is
+ not specified in the profile then it can not be accessed by that
+ path. The creation of aliases needs to be tightly controlled in
+ confined applications, hard links creation should be limited to
+ provide adequate security.
+ * A confined process can operate on a file descriptor passed to it
+ by an unconfined process, even if it manipulates a file not in the
+ confined process's profile. To block this attack, confine the
+ process that passed the file descriptor.
+ * Process activities not currently mediated by AppArmor are
+ permitted, e.g. confined processes can perform any IPC that DAC
+ permits, other than signals as mediated by CAP_KILL.
+ * Manipulating AppArmor policy requires being both root privileged
+ and not being confined by AppArmor, thus there is explicitly no
+ capability for non-privileged users to change AppArmor policy.
+ * AppArmor confines processes if they are children of a confined
+ process, or if the name of the exec'd child matches the name of an
+ AppArmor profile. Another process could copy a program to a
+ different path name and then execute it without confinement, but
+ the other process would have to have permission to do so in the
+ first place. To prevent this, confine the other process and
+ additional applications until adequate security is achieved.
+ * Mount and namespace manipulations can be used to arbitrarily
+ change the pathnames that files appear at, and thus completely
+ bypass AppArmor policy. To prevent this, processes confined by
+ AppArmor are currently not permitted to call mount or manipulate
+ name spaces at all. A future development may provide more granular
+ controls on mount and namespace manipulations.
+ * AppArmor does not slice bread, cure cancer, bring world peace, or
+ provide perfect security. This list may be expanded :-)
+
+

View file

@ -1,18 +0,0 @@
---
security/apparmor/main.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
--- a/security/apparmor/main.c
+++ b/security/apparmor/main.c
@@ -159,8 +159,10 @@ static int aa_audit_base(struct aa_profi
return type == AUDIT_APPARMOR_ALLOWED ? 0 : -ENOMEM;
}
+ audit_log_format(ab, " type=%d", type);
+
if (sa->operation)
- audit_log_format(ab, "operation=\"%s\"", sa->operation);
+ audit_log_format(ab, " operation=\"%s\"", sa->operation);
if (sa->info) {
audit_log_format(ab, " info=\"%s\"", sa->info);

View file

@ -1,16 +0,0 @@
---
security/apparmor/main.c | 3 +++
1 file changed, 3 insertions(+)
--- a/security/apparmor/main.c
+++ b/security/apparmor/main.c
@@ -405,6 +405,9 @@ static int aa_audit_base(struct aa_profi
if (sa->denied_mask)
aa_audit_file_mask(ab, "denied_mask", sa->denied_mask);
+ if (sa->request_mask)
+ audit_log_format(ab, " fsuid=%d", current->fsuid);
+
if (sa->iattr) {
struct iattr *iattr = sa->iattr;

View file

@ -1,87 +0,0 @@
---
security/apparmor/apparmor.h | 10 ++++++++++
security/apparmor/apparmorfs.c | 4 ++--
security/apparmor/lsm.c | 15 ++++++---------
security/apparmor/module_interface.c | 2 ++
4 files changed, 20 insertions(+), 11 deletions(-)
--- a/security/apparmor/apparmor.h
+++ b/security/apparmor/apparmor.h
@@ -158,8 +158,17 @@ struct aa_namespace {
* @file_rules: dfa containing the profiles file rules
* @flags: flags controlling profile behavior
* @isstale: flag indicating if profile is stale
+ * @set_caps: capabilities that are being set
+ * @capabilities: capabilities mask
+ * @audit_caps: caps that are to be audited
+ * @quiet_caps: caps that should not be audited
* @capabilities: capabilities granted by the process
* @count: reference count of the profile
+ * @task_contexts: list of tasks confined by profile
+ * @lock: lock for the task_contexts list
+ * @network_families: basic network permissions
+ * @audit_network: which network permissions to force audit
+ * @quiet_network: which network permissions to quiet rejects
*
* The AppArmor profile contains the basic confinement data. Each profile
* has a name, and all nonstale profile are in a profile namespace.
@@ -183,6 +192,7 @@ struct aa_profile {
} flags;
int isstale;
+ kernel_cap_t set_caps;
kernel_cap_t capabilities;
kernel_cap_t audit_caps;
kernel_cap_t quiet_caps;
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -103,8 +103,8 @@ static struct file_operations apparmorfs
static ssize_t aa_features_read(struct file *file, char __user *buf,
size_t size, loff_t *ppos)
{
- const char *features = "file=3.0 capability=1.0 network=1.0 "
- "change_hat=1.3 change_profile=1.0 "
+ const char *features = "file=3.0 capability=2.0 network=1.0 "
+ "change_hat=1.4 change_profile=1.0 "
"aanamespaces=1.0";
return simple_read_from_buffer(buf, size, ppos, features,
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -210,19 +210,16 @@ static int apparmor_ptrace(struct task_s
static int apparmor_capable(struct task_struct *task, int cap)
{
int error;
+ struct aa_task_context *cxt;
/* cap_capable returns 0 on success, else -EPERM */
error = cap_capable(task, cap);
- if (!error) {
- struct aa_task_context *cxt;
-
- rcu_read_lock();
- cxt = aa_task_context(task);
- if (cxt)
- error = aa_capability(cxt, cap);
- rcu_read_unlock();
- }
+ rcu_read_lock();
+ cxt = aa_task_context(task);
+ if (cxt && (!error || cap_raised(cxt->profile->set_caps, cap)))
+ error = aa_capability(cxt, cap);
+ rcu_read_unlock();
return error;
}
--- a/security/apparmor/module_interface.c
+++ b/security/apparmor/module_interface.c
@@ -316,6 +316,8 @@ static struct aa_profile *aa_unpack_prof
goto fail;
if (!aa_is_u32(e, &(profile->quiet_caps), NULL))
goto fail;
+ if (!aa_is_u32(e, &(profile->set_caps), NULL))
+ goto fail;
size = aa_is_array(e, "net_allowed_af");
if (size) {

View file

@ -1,95 +0,0 @@
This patch removes magic cookies from the aa_change_profile interface, making
it a true one-way transition.
It also fixes a refcounting bug with previous_profile by virtue of removing
the broken code entirely.
Signed-off-by: Kenny Graunke <kgraunke@novell.com>
Signed-off-by: Seth Arnold <seth.arnold@suse.de>
---
security/apparmor/apparmor.h | 2 +-
security/apparmor/main.c | 21 +++++++--------------
security/apparmor/procattr.c | 9 +--------
3 files changed, 9 insertions(+), 23 deletions(-)
--- a/security/apparmor/apparmor.h
+++ b/security/apparmor/apparmor.h
@@ -211,7 +211,7 @@ extern int aa_clone(struct task_struct *
extern int aa_register(struct linux_binprm *bprm);
extern void aa_release(struct task_struct *task);
extern int aa_change_hat(const char *id, u64 hat_magic);
-extern int aa_change_profile(const char *name, u64 cookie);
+extern int aa_change_profile(const char *name);
extern struct aa_profile *__aa_find_profile(const char *name,
struct list_head *list);
extern struct aa_profile *__aa_replace_profile(struct task_struct *task,
--- a/security/apparmor/main.c
+++ b/security/apparmor/main.c
@@ -1110,20 +1110,18 @@ out:
}
/**
- * aa_change_profile - change profile to/from previous stored profile
+ * aa_change_profile - perform a one-way profile transition
* @name: name of profile to change to
- * @cookie: magic value to validate the profile change
*
- * Change to new profile @name, and store the @cookie in the current task
- * context. If the new @name is %NULL and the @cookie matches that
- * stored in the current task context, return to the previous profile.
+ * Change to new profile @name. Unlike with hats, there is no way
+ * to change back.
*
* Returns %0 on success, error otherwise.
*/
-int aa_change_profile(const char *name, u64 cookie)
+int aa_change_profile(const char *name)
{
struct aa_task_context *cxt;
- struct aa_profile *profile, *previous_profile;
+ struct aa_profile *profile;
struct aa_audit sa;
int error = 0;
@@ -1139,7 +1137,6 @@ repeat:
return -EPERM;
}
profile = aa_dup_profile(cxt->profile);
- previous_profile = aa_dup_profile(cxt->previous_profile);
task_unlock(current);
if (name) {
@@ -1150,13 +1147,9 @@ repeat:
aa_put_profile(profile);
return -EACCES;
}
- error = do_change_profile(profile, name, cookie, 0, &sa);
- } else if (previous_profile)
- error = do_change_profile(profile, previous_profile->name,
- cookie, 1, &sa);
- /* else ignore restores when there is no saved profile */
+ error = do_change_profile(profile, name, 0, 0, &sa);
+ }
- aa_put_profile(previous_profile);
aa_put_profile(profile);
if (error == -ESTALE)
goto repeat;
--- a/security/apparmor/procattr.c
+++ b/security/apparmor/procattr.c
@@ -87,14 +87,7 @@ int aa_setprocattr_changehat(char *args)
int aa_setprocattr_changeprofile(char *args)
{
- char *name;
- u64 cookie;
-
- name = split_token_from_name("change_profile", args, &cookie);
- if (IS_ERR(name))
- return PTR_ERR(name);
-
- return aa_change_profile(name, cookie);
+ return aa_change_profile(args);
}
int aa_setprocattr_setprofile(struct task_struct *task, char *args)

View file

@ -1,86 +0,0 @@
From: Andreas Gruenbacher <agruen@suse.de>
Subject: Add d_namespace_path() to compute namespace relative pathnames
In AppArmor, we are interested in pathnames relative to the namespace root.
This is the same as d_path() except for the root where the search ends. Add
a function for computing the namespace-relative path.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
fs/dcache.c | 6 +++---
fs/namespace.c | 27 +++++++++++++++++++++++++++
include/linux/dcache.h | 2 ++
include/linux/mount.h | 2 ++
4 files changed, 34 insertions(+), 3 deletions(-)
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1782,9 +1782,9 @@ shouldnt_be_hashed:
*
* 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, int fail_deleted)
+char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
+ struct dentry *root, struct vfsmount *rootmnt,
+ char *buffer, int buflen, int fail_deleted)
{
int namelen, is_slash, vfsmount_locked = 0;
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1883,3 +1883,30 @@ void __put_mnt_ns(struct mnt_namespace *
release_mounts(&umount_list);
kfree(ns);
}
+
+char *d_namespace_path(struct dentry *dentry, struct vfsmount *vfsmnt,
+ char *buf, int buflen)
+{
+ struct vfsmount *rootmnt, *nsrootmnt = NULL;
+ struct dentry *root = NULL;
+ char *res;
+
+ read_lock(&current->fs->lock);
+ rootmnt = mntget(current->fs->rootmnt);
+ read_unlock(&current->fs->lock);
+ spin_lock(&vfsmount_lock);
+ if (rootmnt->mnt_ns)
+ nsrootmnt = mntget(rootmnt->mnt_ns->root);
+ spin_unlock(&vfsmount_lock);
+ mntput(rootmnt);
+ if (nsrootmnt)
+ root = dget(nsrootmnt->mnt_root);
+ res = __d_path(dentry, vfsmnt, root, nsrootmnt, buf, buflen, 1);
+ dput(root);
+ mntput(nsrootmnt);
+ /* Prevent empty path for lazily unmounted filesystems. */
+ if (!IS_ERR(res) && *res == '\0')
+ *--res = '.';
+ return res;
+}
+EXPORT_SYMBOL(d_namespace_path);
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -300,6 +300,8 @@ extern int d_validate(struct dentry *, s
*/
extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...);
+extern char *__d_path(struct dentry *, struct vfsmount *, struct dentry *,
+ struct vfsmount *, char *, int, int);
extern char * d_path(struct dentry *, struct vfsmount *, char *, int);
/* Allocation counts.. */
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -103,5 +103,7 @@ extern void shrink_submounts(struct vfsm
extern spinlock_t vfsmount_lock;
extern dev_t name_to_dev_t(char *name);
+extern char *d_namespace_path(struct dentry *, struct vfsmount *, char *, int);
+
#endif
#endif /* _LINUX_MOUNT_H */

View file

@ -1,47 +0,0 @@
From: Andreas Gruenbacher <agruen@suse.de>
Subject: Switch to vfs_permission() in do_path_lookup()
Switch from file_permission() to vfs_permission() in do_path_lookup():
this avoids calling permission() with a NULL nameidata here.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
fs/namei.c | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1147,25 +1147,24 @@ static int fastcall do_path_lookup(int d
nd->dentry = dget(fs->pwd);
read_unlock(&fs->lock);
} else {
- struct dentry *dentry;
-
file = fget_light(dfd, &fput_needed);
retval = -EBADF;
if (!file)
goto out_fail;
- dentry = file->f_path.dentry;
+ nd->dentry = file->f_path.dentry;
+ nd->mnt = file->f_path.mnt;
retval = -ENOTDIR;
- if (!S_ISDIR(dentry->d_inode->i_mode))
+ if (!S_ISDIR(nd->dentry->d_inode->i_mode))
goto fput_fail;
- retval = file_permission(file, MAY_EXEC);
+ retval = vfs_permission(nd, MAY_EXEC);
if (retval)
goto fput_fail;
- nd->mnt = mntget(file->f_path.mnt);
- nd->dentry = dget(dentry);
+ mntget(nd->mnt);
+ dget(nd->dentry);
fput_light(file, fput_needed);
}

View file

@ -1,42 +0,0 @@
From: Andreas Gruenbacher <agruen@use.de>
Subject: Check for NULL nameidata in ecryptfs_d_revalidate
Some filesystems like nfsd and ecryptfs use lookup_one_len() on other
filesystems. This causes d_revalidate() calls with nd == NULL through
__lookup_hash() and cached_lookup(), so we need to check for NULL
nameidata.
Signed-off-by: Andreas Gruenbacher <agruen@use.de>
Cc: Mike Halcrow <mhalcrow@us.ibm.com>
Cc: Phillip Hellewell <phillip@hellewell.homeip.net>
---
fs/ecryptfs/dentry.c | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
--- a/fs/ecryptfs/dentry.c
+++ b/fs/ecryptfs/dentry.c
@@ -51,13 +51,17 @@ static int ecryptfs_d_revalidate(struct
if (!lower_dentry->d_op || !lower_dentry->d_op->d_revalidate)
goto out;
- dentry_save = nd->dentry;
- vfsmount_save = nd->mnt;
- nd->dentry = lower_dentry;
- nd->mnt = lower_mnt;
+ if (nd) {
+ dentry_save = nd->dentry;
+ vfsmount_save = nd->mnt;
+ nd->dentry = lower_dentry;
+ nd->mnt = lower_mnt;
+ }
rc = lower_dentry->d_op->d_revalidate(lower_dentry, nd);
- nd->dentry = dentry_save;
- nd->mnt = vfsmount_save;
+ if (nd) {
+ nd->dentry = dentry_save;
+ nd->mnt = vfsmount_save;
+ }
if (dentry->d_inode) {
struct inode *lower_inode =
ecryptfs_inode_to_lower(dentry->d_inode);

View file

@ -1,173 +0,0 @@
Allow the dfa to return its state, which will allow for pair matches.
---
security/apparmor/apparmor.h | 7 ++-
security/apparmor/inline.h | 2
security/apparmor/match.c | 99 ++++++++++++++++++++++++++++++++++++++-----
security/apparmor/match.h | 2
4 files changed, 99 insertions(+), 11 deletions(-)
--- a/security/apparmor/apparmor.h
+++ b/security/apparmor/apparmor.h
@@ -45,7 +45,6 @@
#define AA_SECURE_EXEC_NEEDED 1
-
/* Control parameters (0 or 1), settable thru module/boot flags or
* via /sys/kernel/security/apparmor/control */
extern int apparmor_complain;
@@ -260,5 +259,11 @@ extern void aa_match_free(struct aa_dfa
extern int unpack_dfa(struct aa_dfa *dfa, void *blob, size_t size);
extern int verify_dfa(struct aa_dfa *dfa);
extern unsigned int aa_dfa_match(struct aa_dfa *dfa, const char *str);
+extern unsigned int aa_dfa_next_state(struct aa_dfa *dfa, unsigned int start,
+ const char *str);
+extern unsigned int aa_match_state(struct aa_dfa *dfa, unsigned int start,
+ const char *str, unsigned int *final);
+extern unsigned int aa_dfa_null_transition(struct aa_dfa *dfa,
+ unsigned int start);
#endif /* __APPARMOR_H */
--- a/security/apparmor/inline.h
+++ b/security/apparmor/inline.h
@@ -12,6 +12,8 @@
#include <linux/sched.h>
+#include "match.h"
+
static inline int mediated_filesystem(struct inode *inode)
{
return !(inode->i_sb->s_flags & MS_NOUSER);
--- a/security/apparmor/match.c
+++ b/security/apparmor/match.c
@@ -208,22 +208,26 @@ void aa_match_free(struct aa_dfa *dfa)
}
/**
- * 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_next_state - traverse @dfa to find state @str stops at
+ * @dfa: the dfa to match @str against
+ * @start: the state of the dfa to start matching in
+ * @str: the string 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 is used to look up the accepting
- * label.
+ * aa_dfa_next_state will match @str against the dfa and return the state it
+ * finished matching in. The final state can be used to look up the accepting
+ * label, or as the start state of a continuing match.
*/
-unsigned int aa_dfa_match(struct aa_dfa *dfa, const char *str)
+unsigned int aa_dfa_next_state(struct aa_dfa *dfa, unsigned int start,
+ const char *str)
{
u16 *def = DEFAULT_TABLE(dfa);
u32 *base = BASE_TABLE(dfa);
u16 *next = NEXT_TABLE(dfa);
u16 *check = CHECK_TABLE(dfa);
- unsigned int state = 1, pos;
+ unsigned int state = start, pos;
+
+ if (state == 0)
+ return 0;
/* current state is <state>, matching character *str */
if (dfa->tables[YYTD_ID_EC - 1]) {
@@ -244,5 +248,80 @@ unsigned int aa_dfa_match(struct aa_dfa
state = def[state];
}
}
- return ACCEPT_TABLE(dfa)[state];
+ return state;
+}
+
+/**
+ * aa_dfa_null_transition - step to next state after null character
+ * @dfa: the dfa to match against
+ * @start: the state of the dfa to start matching in
+ *
+ * aa_dfa_null_transition transitions to the next state after a null
+ * character which is not used in standard matching and is only
+ * used to seperate pairs.
+ */
+unsigned int aa_dfa_null_transition(struct aa_dfa *dfa, unsigned int start)
+{
+ u16 *def = DEFAULT_TABLE(dfa);
+ u32 *base = BASE_TABLE(dfa);
+ u16 *next = NEXT_TABLE(dfa);
+ u16 *check = CHECK_TABLE(dfa);
+ unsigned int state = start, pos;
+
+ /* current state is <state>, matching character *str */
+ if (dfa->tables[YYTD_ID_EC - 1]) {
+ u8 *equiv = EQUIV_TABLE(dfa);
+ pos = base[state] + equiv[0];
+ if (check[pos] == state)
+ state = next[pos];
+ else
+ state = def[state];
+ } else {
+ pos = base[state] + 0;
+ if (check[pos] == state)
+ state = next[pos];
+ else
+ state = def[state];
+ }
+
+ return state;
+}
+
+/**
+ * aa_dfa_match - find accept perm for @str in @dfa
+ * @dfa: the dfa to match @str against
+ * @str: the string to match against the dfa
+ *
+ * aa_dfa_match will match @str and return the accept perms for the
+ * final state.
+ */
+unsigned int aa_dfa_match(struct aa_dfa *dfa, const char *str)
+{
+ return ACCEPT_TABLE(dfa)[aa_dfa_next_state(dfa, DFA_START, str)];
}
+
+/**
+ * aa_match_state - find accept perm and state for @str in @dfa
+ * @dfa: the dfa to match @str against
+ * @start: the state to start the match from
+ * @str: the string to match against the dfa
+ * @final: the state that the match finished in
+ *
+ * aa_match_state will match @str and return the accept perms, and @final
+ * state, the match occured in.
+ */
+unsigned int aa_match_state(struct aa_dfa *dfa, unsigned int start,
+ const char *str, unsigned int *final)
+{
+ unsigned int state;
+ if (dfa) {
+ state = aa_dfa_next_state(dfa, start, str);
+ if (final)
+ *final = state;
+ return ACCEPT_TABLE(dfa)[state];
+ }
+ if (final)
+ *final = 0;
+ return 0;
+}
+
--- a/security/apparmor/match.h
+++ b/security/apparmor/match.h
@@ -12,6 +12,8 @@
#ifndef __MATCH_H
#define __MATCH_H
+#define DFA_START 1
+
/**
* The format used for transition tables is based on the GNU flex table
* file format (--tables-file option; see Table File Format in the flex

View file

@ -1,72 +0,0 @@
---
security/apparmor/apparmor.h | 43 ++++++++++++++++++++++++++++---------------
1 file changed, 28 insertions(+), 15 deletions(-)
--- a/security/apparmor/apparmor.h
+++ b/security/apparmor/apparmor.h
@@ -26,25 +26,33 @@
#define AA_MAY_LINK 0x0010
#define AA_MAY_LOCK 0x0020
#define AA_EXEC_MMAP 0x0040
-#define AA_EXEC_UNSAFE 0x0080
-#define AA_EXEC_MOD_0 0x0100
-#define AA_EXEC_MOD_1 0x0200
+#define AA_MAY_MOUNT 0x0080 /* no direct audit mapping */
+#define AA_EXEC_UNSAFE 0x0100
+#define AA_EXEC_MOD_0 0x0200
+#define AA_EXEC_MOD_1 0x0400
+#define AA_EXEC_MOD_2 0x0800
+#define AA_EXEC_MOD_3 0x1000
+#define AA_EXEC_MOD_4 0x2000
+
#define AA_BASE_PERMS (MAY_READ | MAY_WRITE | MAY_EXEC | \
MAY_APPEND | AA_MAY_LINK | \
AA_MAY_LOCK | AA_EXEC_MMAP | \
- AA_EXEC_UNSAFE | AA_EXEC_MOD_0 | \
- AA_EXEC_MOD_1)
-#define AA_LINK_SUBSET_TEST 0x0020
-
-#define AA_EXEC_UNCONFINED 0
-#define AA_EXEC_INHERIT AA_EXEC_MOD_0
-#define AA_EXEC_PROFILE AA_EXEC_MOD_1
-#define AA_EXEC_PIX (AA_EXEC_MOD_0 | AA_EXEC_MOD_1)
-
-#define AA_EXEC_MODIFIERS (AA_EXEC_MOD_0 | AA_EXEC_MOD_1)
+ AA_MAY_MOUNT | AA_EXEC_UNSAFE | \
+ AA_EXEC_MOD_0 | AA_EXEC_MOD_1 | \
+ AA_EXEC_MOD_2 | AA_EXEC_MOD_3 | \
+ AA_EXEC_MOD_4)
+
+#define AA_EXEC_UNCONFINED AA_EXEC_MOD_0
+#define AA_EXEC_INHERIT AA_EXEC_MOD_1
+#define AA_EXEC_PROFILE (AA_EXEC_MOD_0 | AA_EXEC_MOD_1)
+#define AA_EXEC_PIX AA_EXEC_MOD_2
+
+#define AA_EXEC_MODIFIERS (AA_EXEC_MOD_0 | AA_EXEC_MOD_1 | \
+ AA_EXEC_MOD_2 | AA_EXEC_MOD_3 | \
+ AA_EXEC_MOD_4)
#define AA_USER_SHIFT 0
-#define AA_OTHER_SHIFT 10
+#define AA_OTHER_SHIFT 14
#define AA_USER_PERMS (AA_BASE_PERMS << AA_USER_SHIFT)
#define AA_OTHER_PERMS (AA_BASE_PERMS << AA_OTHER_SHIFT)
@@ -68,11 +76,16 @@
#define AA_ALL_EXEC_MODS (AA_USER_EXEC_MODS | \
AA_OTHER_EXEC_MODS)
+/* overloaded permissions for link pairs */
+#define AA_LINK_SUBSET_TEST 0x0020
+
/* shared permissions that are not duplicated in user::other */
+#define AA_AUDIT_FIELD 0x10000000
#define AA_CHANGE_HAT 0x20000000
#define AA_CHANGE_PROFILE 0x40000000
-#define AA_SHARED_PERMS (AA_CHANGE_HAT | AA_CHANGE_PROFILE)
+#define AA_SHARED_PERMS (AA_CHANGE_HAT | AA_CHANGE_PROFILE | \
+ AA_AUDIT_FIELD)
#define AA_VALID_PERM_MASK (AA_FILE_PERMS | AA_SHARED_PERMS)

View file

@ -1,130 +0,0 @@
From: Miklos Szeredi <mszeredi@suse.cz>
Add a new file operation: f_op->fgetattr(), that is invoked by
fstat(). Fall back to i_op->getattr() if it is not defined.
We need this because fstat() semantics can in some cases be better
implemented if the filesystem has the open file available.
Let's take the following example: we have a network filesystem, with
the server implemented as an unprivileged userspace process running on
a UNIX system (this is basically what sshfs does).
We want the filesystem to follow the familiar UNIX file semantics as
closely as possible. If for example we have this sequence of events,
we still would like fstat to work correctly:
1) file X is opened on client
2) file X is renamed to Y on server
3) fstat() is performed on open file descriptor on client
This is only possible if the filesystem server acutally uses fstat()
on a file descriptor obtained when the file was opened. Which means,
the filesystem client needs a way to get this information from the
VFS.
Even if we assume, that the remote filesystem never changes, it is
difficult to implement open-unlink-fstat semantics correctly in the
client, without having this information.
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
---
fs/fuse/file.c | 13 +++++++++++++
fs/stat.c | 29 ++++++++++++++++++++++++++++-
include/linux/fs.h | 1 +
3 files changed, 42 insertions(+), 1 deletion(-)
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -871,6 +871,17 @@ static int fuse_file_flock(struct file *
return err;
}
+static int fuse_file_fgetattr(struct file *file, struct kstat *stat)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ struct fuse_conn *fc = get_fuse_conn(inode);
+
+ if (!fuse_allow_task(fc, current))
+ return -EACCES;
+
+ return fuse_update_attributes(inode, stat, file, NULL);
+}
+
static sector_t fuse_bmap(struct address_space *mapping, sector_t block)
{
struct inode *inode = mapping->host;
@@ -920,6 +931,7 @@ static const struct file_operations fuse
.fsync = fuse_fsync,
.lock = fuse_file_lock,
.flock = fuse_file_flock,
+ .fgetattr = fuse_file_fgetattr,
.splice_read = generic_file_splice_read,
};
@@ -933,6 +945,7 @@ static const struct file_operations fuse
.fsync = fuse_fsync,
.lock = fuse_file_lock,
.flock = fuse_file_flock,
+ .fgetattr = fuse_file_fgetattr,
/* no mmap and splice_read */
};
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -55,6 +55,33 @@ int vfs_getattr(struct vfsmount *mnt, st
EXPORT_SYMBOL(vfs_getattr);
+/*
+ * Perform getattr on an open file
+ *
+ * Fall back to i_op->getattr (or generic_fillattr) if the filesystem
+ * doesn't define an f_op->fgetattr operation.
+ */
+static int vfs_fgetattr(struct file *file, struct kstat *stat)
+{
+ struct vfsmount *mnt = file->f_path.mnt;
+ struct dentry *dentry = file->f_path.dentry;
+ struct inode *inode = dentry->d_inode;
+ int retval;
+
+ retval = security_inode_getattr(mnt, dentry);
+ if (retval)
+ return retval;
+
+ if (file->f_op && file->f_op->fgetattr) {
+ return file->f_op->fgetattr(file, stat);
+ } else if (inode->i_op->getattr) {
+ return inode->i_op->getattr(mnt, dentry, stat);
+ } else {
+ generic_fillattr(inode, stat);
+ return 0;
+ }
+}
+
int vfs_stat_fd(int dfd, char __user *name, struct kstat *stat)
{
struct nameidata nd;
@@ -101,7 +128,7 @@ int vfs_fstat(unsigned int fd, struct ks
int error = -EBADF;
if (f) {
- error = vfs_getattr(f->f_path.mnt, f->f_path.dentry, stat);
+ error = vfs_fgetattr(f, stat);
fput(f);
}
return error;
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1188,6 +1188,7 @@ struct file_operations {
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **);
+ int (*fgetattr)(struct file *, struct kstat *);
};
struct inode_operations {

View file

@ -1,83 +0,0 @@
From: Andreas Gruenbacher <agruen@suse.de>
Subject: Enable LSM hooks to distinguish operations on file descriptors from operations on pathnames
Struct iattr already contains ia_file since commit cc4e69de from
Miklos (which is related to commit befc649c). Use this to pass
struct file down the setattr hooks. This allows LSMs to distinguish
operations on file descriptors from operations on paths.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
Cc: Miklos Szeredi <mszeredi@suse.cz>
---
fs/nfsd/vfs.c | 12 +++++++-----
fs/open.c | 4 +++-
2 files changed, 10 insertions(+), 6 deletions(-)
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -413,7 +413,7 @@ static ssize_t nfsd_getxattr(struct dent
{
ssize_t buflen;
- buflen = vfs_getxattr(dentry, mnt, key, NULL, 0);
+ buflen = vfs_getxattr(dentry, mnt, key, NULL, 0, NULL);
if (buflen <= 0)
return buflen;
@@ -421,7 +421,7 @@ static ssize_t nfsd_getxattr(struct dent
if (!*buf)
return -ENOMEM;
- return vfs_getxattr(dentry, mnt, key, *buf, buflen);
+ return vfs_getxattr(dentry, mnt, key, *buf, buflen, NULL);
}
#endif
@@ -447,7 +447,7 @@ set_nfsv4_acl_one(struct dentry *dentry,
goto out;
}
- error = vfs_setxattr(dentry, mnt, key, buf, len, 0);
+ error = vfs_setxattr(dentry, mnt, key, buf, len, 0, NULL);
out:
kfree(buf);
return error;
@@ -2051,12 +2051,14 @@ nfsd_set_posix_acl(struct svc_fh *fhp, i
mnt = fhp->fh_export->ex_mnt;
if (size)
- error = vfs_setxattr(fhp->fh_dentry, mnt, name, value, size,0);
+ error = vfs_setxattr(fhp->fh_dentry, mnt, name, value, size, 0,
+ NULL);
else {
if (!S_ISDIR(inode->i_mode) && type == ACL_TYPE_DEFAULT)
error = 0;
else {
- error = vfs_removexattr(fhp->fh_dentry, mnt, name);
+ error = vfs_removexattr(fhp->fh_dentry, mnt, name,
+ NULL);
if (error == -ENODATA)
error = 0;
}
--- a/fs/open.c
+++ b/fs/open.c
@@ -581,7 +581,7 @@ asmlinkage long sys_fchmod(unsigned int
if (mode == (mode_t) -1)
mode = inode->i_mode;
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
- newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
+ newattrs.ia_valid = ATTR_MODE | ATTR_CTIME | ATTR_FILE;
err = fnotify_change(dentry, file->f_path.mnt, &newattrs, file);
mutex_unlock(&inode->i_mutex);
@@ -661,6 +661,8 @@ static int chown_common(struct dentry *
if (!S_ISDIR(inode->i_mode))
newattrs.ia_valid |=
ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV;
+ if (file)
+ newattrs.ia_valid |= ATTR_FILE;
mutex_lock(&inode->i_mutex);
error = fnotify_change(dentry, mnt, &newattrs, file);
mutex_unlock(&inode->i_mutex);

View file

@ -1,31 +0,0 @@
From: Andreas Gruenbacher <agruen@suse.de>
Subject: Fix file_permission()
We cannot easily switch from file_permission() to vfs_permission()
everywhere, so fix file_permission() to not use a NULL nameidata
for the remaining users.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
fs/namei.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -313,7 +313,13 @@ int vfs_permission(struct nameidata *nd,
*/
int file_permission(struct file *file, int mask)
{
- return permission(file->f_path.dentry->d_inode, mask, NULL);
+ struct nameidata nd;
+
+ nd.dentry = file->f_path.dentry;
+ nd.mnt = file->f_path.mnt;
+ nd.flags = LOOKUP_ACCESS;
+
+ return permission(nd.dentry->d_inode, mask, &nd);
}
/*

View file

@ -1,17 +0,0 @@
---
security/apparmor/main.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
--- a/security/apparmor/main.c
+++ b/security/apparmor/main.c
@@ -1239,9 +1239,7 @@ repeat:
return -ENOENT;
}
- if (PROFILE_COMPLAIN(profile) ||
- (ns == profile->ns &&
- (aa_match(profile->file_rules, name) & AA_CHANGE_PROFILE)))
+ if (PROFILE_COMPLAIN(profile))
error = do_change_profile(profile, ns, name, 0, 0, &sa);
else {
/* check for a rule with a namespace prepended */

View file

@ -1,68 +0,0 @@
From: Andreas Gruenbacher <agruen@suse.de>
Subject: Distinguish between connected and disconnected paths in d_path()
Change d_path() so that it will never return a path starting with '/' if
the path doesn't lead up to the chroot directory. Also ensure that the
path returned never is the empty string: this would only occur with a lazily unmounted file system; return "." in that case instead.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
---
fs/dcache.c | 18 ++++--------------
fs/namespace.c | 3 ---
2 files changed, 4 insertions(+), 17 deletions(-)
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1829,8 +1829,11 @@ global_root:
buffer++;
buflen++;
}
- if (is_slash)
+ if (is_slash) {
+ if (*buffer == '\0')
+ *--buffer = '.';
goto out;
+ }
}
if (buflen < namelen)
goto Elong;
@@ -1843,18 +1846,6 @@ Elong:
goto out;
}
-static char *__connect_d_path(char *path, char *buffer)
-{
- if (!IS_ERR(path) && *path != '/') {
- /* Pretend that disconnected paths are hanging off the root. */
- if (path == buffer)
- path = ERR_PTR(-ENAMETOOLONG);
- else
- *--path = '/';
- }
- return path;
-}
-
/* write full pathname into buffer and return start of pathname */
char *d_path(struct dentry *dentry, struct vfsmount *vfsmnt, char *buf,
int buflen)
@@ -1868,7 +1859,6 @@ char *d_path(struct dentry *dentry, stru
root = dget(current->fs->root);
read_unlock(&current->fs->lock);
res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen, 0);
- res = __connect_d_path(res, buf);
dput(root);
mntput(rootmnt);
return res;
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1917,9 +1917,6 @@ char *d_namespace_path(struct dentry *de
res = __d_path(dentry, vfsmnt, root, nsrootmnt, buf, buflen, 1);
dput(root);
mntput(nsrootmnt);
- /* Prevent empty path for lazily unmounted filesystems. */
- if (!IS_ERR(res) && *res == '\0')
- *--res = '.';
return res;
}
EXPORT_SYMBOL(d_namespace_path);

View file

@ -1,134 +0,0 @@
---
security/apparmor/match.c | 74 +++++++++++++++++++++++++++++++---------------
1 file changed, 51 insertions(+), 23 deletions(-)
--- a/security/apparmor/match.c
+++ b/security/apparmor/match.c
@@ -213,17 +213,23 @@ void aa_match_free(struct aa_dfa *dfa)
}
/**
- * aa_dfa_next_state - traverse @dfa to find state @str stops at
+ * aa_dfa_next_state_len - traverse @dfa to find state @str stops at
* @dfa: the dfa to match @str against
* @start: the state of the dfa to start matching in
- * @str: the string to match against the dfa
+ * @str: the string of bytes to match against the dfa
+ * @len: length of the string of bytes to match
*
* aa_dfa_next_state will match @str against the dfa and return the state it
* finished matching in. The final state can be used to look up the accepting
* label, or as the start state of a continuing match.
+ *
+ * aa_dfa_next_state could be implement using this function by doing
+ * return aa_dfa_next_state_len(dfa, start, str, strlen(str));
+ * but that would require traversing the string twice and be slightly
+ * slower.
*/
-unsigned int aa_dfa_next_state(struct aa_dfa *dfa, unsigned int start,
- const char *str)
+unsigned int aa_dfa_next_state_len(struct aa_dfa *dfa, unsigned int start,
+ const char *str, int len)
{
u16 *def = DEFAULT_TABLE(dfa);
u32 *base = BASE_TABLE(dfa);
@@ -237,7 +243,7 @@ unsigned int aa_dfa_next_state(struct aa
/* current state is <state>, matching character *str */
if (dfa->tables[YYTD_ID_EC - 1]) {
u8 *equiv = EQUIV_TABLE(dfa);
- while (*str) {
+ for (; len; len--) {
pos = base[state] + equiv[(u8)*str++];
if (check[pos] == state)
state = next[pos];
@@ -245,7 +251,7 @@ unsigned int aa_dfa_next_state(struct aa
state = def[state];
}
} else {
- while (*str) {
+ for (; len; len--) {
pos = base[state] + (u8)*str++;
if (check[pos] == state)
state = next[pos];
@@ -257,15 +263,17 @@ unsigned int aa_dfa_next_state(struct aa
}
/**
- * aa_dfa_null_transition - step to next state after null character
- * @dfa: the dfa to match against
+ * aa_dfa_next_state - traverse @dfa to find state @str stops at
+ * @dfa: the dfa to match @str against
* @start: the state of the dfa to start matching in
+ * @str: the null terminated string of bytes to match against the dfa
*
- * aa_dfa_null_transition transitions to the next state after a null
- * character which is not used in standard matching and is only
- * used to seperate pairs.
+ * aa_dfa_next_state will match @str against the dfa and return the state it
+ * finished matching in. The final state can be used to look up the accepting
+ * label, or as the start state of a continuing match.
*/
-unsigned int aa_dfa_null_transition(struct aa_dfa *dfa, unsigned int start)
+unsigned int aa_dfa_next_state(struct aa_dfa *dfa, unsigned int start,
+ const char *str)
{
u16 *def = DEFAULT_TABLE(dfa);
u32 *base = BASE_TABLE(dfa);
@@ -273,26 +281,46 @@ unsigned int aa_dfa_null_transition(stru
u16 *check = CHECK_TABLE(dfa);
unsigned int state = start, pos;
+ if (state == 0)
+ return 0;
+
/* current state is <state>, matching character *str */
if (dfa->tables[YYTD_ID_EC - 1]) {
u8 *equiv = EQUIV_TABLE(dfa);
- pos = base[state] + equiv[0];
- if (check[pos] == state)
- state = next[pos];
- else
- state = def[state];
+ while (*str) {
+ pos = base[state] + equiv[(u8)*str++];
+ if (check[pos] == state)
+ state = next[pos];
+ else
+ state = def[state];
+ }
} else {
- pos = base[state] + 0;
- if (check[pos] == state)
- state = next[pos];
- else
- state = def[state];
+ while (*str) {
+ pos = base[state] + (u8)*str++;
+ if (check[pos] == state)
+ state = next[pos];
+ else
+ state = def[state];
+ }
}
-
return state;
}
/**
+ * aa_dfa_null_transition - step to next state after null character
+ * @dfa: the dfa to match against
+ * @start: the state of the dfa to start matching in
+ *
+ * aa_dfa_null_transition transitions to the next state after a null
+ * character which is not used in standard matching and is only
+ * used to seperate pairs.
+ */
+unsigned int aa_dfa_null_transition(struct aa_dfa *dfa, unsigned int start)
+{
+ return aa_dfa_next_state_len(dfa, start, "", 1);
+}
+
+/**
* aa_dfa_match - find accept perm for @str in @dfa
* @dfa: the dfa to match @str against
* @str: the string to match against the dfa

View file

@ -1,37 +0,0 @@
---
fs/fuse/dir.c | 2 +-
fs/fuse/file.c | 2 +-
fs/fuse/fuse_i.h | 3 +++
3 files changed, 5 insertions(+), 2 deletions(-)
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1167,7 +1167,7 @@ static int fuse_setattr(struct dentry *e
return fuse_do_setattr(entry, attr, NULL);
}
-static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
+int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
struct kstat *stat)
{
struct inode *inode = entry->d_inode;
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -855,7 +855,7 @@ static int fuse_file_fgetattr(struct fil
if (!fuse_allow_task(fc, current))
return -EACCES;
- return fuse_update_attributes(inode, stat, file, NULL);
+ return fuse_getattr(file->f_vfsmnt, file->f_dentry, stat);
}
static sector_t fuse_bmap(struct address_space *mapping, sector_t block)
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -597,3 +597,6 @@ int fuse_valid_type(int m);
int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task);
u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id);
+
+int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
+ struct kstat *stat);

View file

@ -1,30 +0,0 @@
From: Andreas Gruenbacher <agruen@suse.de>
Subject: Make getcwd() only return valid paths
Make getcwd() fail with -ENOENT if the current working directory is
disconnected: the process is not asking for some previous name of that
directory but for the current name; returning a path meaningless in the
context of that process makes no sense.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
---
fs/dcache.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1910,10 +1910,12 @@ asmlinkage long sys_getcwd(char __user *
read_unlock(&current->fs->lock);
cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE, 1);
- cwd = __connect_d_path(cwd, page);
error = PTR_ERR(cwd);
if (IS_ERR(cwd))
goto out;
+ error = -ENOENT;
+ if (*cwd != '/')
+ goto out;
error = -ERANGE;
len = PAGE_SIZE + page - cwd;

View file

@ -1,76 +0,0 @@
---
security/apparmor/main.c | 37 ++++++++++++++++++++-----------------
1 file changed, 20 insertions(+), 17 deletions(-)
--- a/security/apparmor/main.c
+++ b/security/apparmor/main.c
@@ -68,7 +68,7 @@ static int aa_link_denied(struct aa_prof
int *request_mask)
{
unsigned int state;
- int l_mode, t_mode, denied_mask = 0;
+ int l_mode, t_mode, l_subset, denied_mask = 0;
int link_mask = AA_MAY_LINK << target_mode;
*request_mask = link_mask;
@@ -83,31 +83,35 @@ static int aa_link_denied(struct aa_prof
if (!(mode & link_mask))
denied_mask |= link_mask;
+ /* return if link subset test is not required */
if (!(mode & (AA_LINK_SUBSET_TEST << target_mode)))
return denied_mask;
}
- /* do link perm subset test */
- t_mode = aa_match(profile->file_rules, target);
-
- /* Ignore valid-profile-transition flags. */
- l_mode &= ~AA_SHARED_PERMS;
- t_mode &= ~AA_SHARED_PERMS;
-
- *request_mask = l_mode | link_mask;
-
- /* Link always requires 'l' on the link for both parts of the pair.
+ /* Do link perm subset test
* If a subset test is required a permission subset test of the
* perms for the link are done against the user:group:other of the
* target's 'r', 'w', 'x', 'a', 'k', and 'm' permissions.
*
* If the link has 'x', an exact match of all the execute flags
- * ('i', 'u', 'p'). safe exec is treated as a subset of unsafe exec
+ * must match.
*/
-#define SUBSET_PERMS (AA_FILE_PERMS & ~AA_LINK_BITS)
denied_mask |= ~l_mode & link_mask;
- if (l_mode & SUBSET_PERMS) {
- denied_mask |= (l_mode & SUBSET_PERMS) & ~t_mode;
+
+ t_mode = aa_match(profile->file_rules, target);
+
+
+ /* For actual subset test ignore valid-profile-transition flags,
+ * and link bits
+ */
+ l_mode &= ~(AA_SHARED_PERMS | AA_LINK_BITS);
+ t_mode &= ~(AA_SHARED_PERMS | AA_LINK_BITS);
+ l_subset = l_mode & AA_FILE_PERMS;
+
+ *request_mask = l_mode | link_mask;
+
+ if (l_subset) {
+ denied_mask |= (l_subset) & ~t_mode;
if (denied_mask & AA_EXEC_BITS)
denied_mask |= l_mode & AA_ALL_EXEC_MODS;
else if (l_mode & AA_EXEC_BITS) {
@@ -126,9 +130,8 @@ static int aa_link_denied(struct aa_prof
denied_mask |= AA_OTHER_EXEC |
(l_mode & AA_OTHER_EXEC_MODS);
}
- } else
+ } else if (t_mode & AA_FILE_PERMS)
denied_mask |= t_mode | link_mask;
-#undef SUBSET_PERMS
return denied_mask;
}

View file

@ -1,22 +0,0 @@
fix bug where the error code and mask are not being set correctly
when pathname lookup fails.
---
security/apparmor/main.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
--- a/security/apparmor/main.c
+++ b/security/apparmor/main.c
@@ -191,8 +191,10 @@ static int aa_perm_dentry(struct aa_prof
*/
if (PTR_ERR(sa->name) == -ENOENT && (check & AA_CHECK_FD))
sa->denied_mask = 0;
- else
- sa->denied_mask = PTR_ERR(sa->name);
+ else {
+ sa->denied_mask = sa->requested_mask;
+ sa->error_code = PTR_ERR(sa->name);
+ }
sa->name = NULL;
} else
sa->denied_mask = aa_file_denied(profile, sa->name,

View file

@ -1,26 +0,0 @@
---
security/apparmor/main.c | 2 +-
security/apparmor/module_interface.c | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
--- a/security/apparmor/main.c
+++ b/security/apparmor/main.c
@@ -1119,7 +1119,7 @@ aa_x_to_profile(struct aa_profile *profi
default:
/* all other indexes are named transitions */
index = AA_EXEC_INDEX(xmode);
- if (index - 4 > profile->exec_table_size) {
+ if (index - 4 >= profile->exec_table_size) {
sa->info = "invalid named transition - exec failed";
sa->error_code = -EACCES;
new_profile = ERR_PTR(-EACCES);
--- a/security/apparmor/module_interface.c
+++ b/security/apparmor/module_interface.c
@@ -319,6 +319,7 @@ static int aa_unpack_exec_table(struct a
goto fail;
if (!aa_is_nameX(e, AA_STRUCTEND, NULL))
goto fail;
+ profile->exec_table_size = size;
}
return 1;

View file

@ -1,38 +0,0 @@
---
security/apparmor/lsm.c | 18 ------------------
1 file changed, 18 deletions(-)
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -717,22 +717,6 @@ static int apparmor_socket_shutdown(stru
return aa_revalidate_sk(sk, "socket_shutdown");
}
-static int apparmor_socket_getpeersec_stream(struct socket *sock,
- char __user *optval, int __user *optlen, unsigned len)
-{
- struct sock *sk = sock->sk;
-
- return aa_revalidate_sk(sk, "socket_getpeersec_stream");
-}
-
-static int apparmor_socket_getpeersec_dgram(struct socket *sock,
- struct sk_buff *skb, u32 *secid)
-{
- struct sock *sk = sock->sk;
-
- return aa_revalidate_sk(sk, "socket_getpeersec_dgram");
-}
-
static int apparmor_getprocattr(struct task_struct *task, char *name,
char **value)
{
@@ -882,8 +866,6 @@ struct security_operations apparmor_ops
.socket_getsockopt = apparmor_socket_getsockopt,
.socket_setsockopt = apparmor_socket_setsockopt,
.socket_shutdown = apparmor_socket_shutdown,
- .socket_getpeersec_stream = apparmor_socket_getpeersec_stream,
- .socket_getpeersec_dgram = apparmor_socket_getpeersec_dgram,
};
static void info_message(const char *str)

View file

@ -1,92 +0,0 @@
---
security/apparmor/list.c | 2 +-
security/apparmor/main.c | 20 +++++++++++---------
security/apparmor/procattr.c | 13 +++++++------
3 files changed, 19 insertions(+), 16 deletions(-)
--- a/security/apparmor/list.c
+++ b/security/apparmor/list.c
@@ -142,7 +142,7 @@ static int seq_show_profile(struct seq_f
seq_printf(f, "%s (%s)\n", profile->name,
PROFILE_COMPLAIN(profile) ? "complain" : "enforce");
else
- seq_printf(f, "%s:%s (%s)\n", profile->ns->name, profile->name,
+ seq_printf(f, ":%s:%s (%s)\n", profile->ns->name, profile->name,
PROFILE_COMPLAIN(profile) ? "complain" : "enforce");
return 0;
}
--- a/security/apparmor/main.c
+++ b/security/apparmor/main.c
@@ -251,8 +251,10 @@ static int aa_audit_base(struct aa_profi
audit_log_format(ab, " profile=");
audit_log_untrustedstring(ab, profile->name);
- audit_log_format(ab, " namespace=");
- audit_log_untrustedstring(ab, profile->ns->name);
+ if (profile->ns != default_namespace) {
+ audit_log_format(ab, " namespace=");
+ audit_log_untrustedstring(ab, profile->ns->name);
+ }
}
audit_log_end(ab);
@@ -1364,15 +1366,15 @@ repeat:
if (hat_name) {
char *name, *profile_name;
- /* Not Yet. This perm check is currently done by searching
- for the hat profile. When hat style profile names
- become more generic then this will be needed.
- if (!(aa_match(profile->file_rules, hat_name) &
- AA_CHANGE_PROFILE)) {
- error = -EACCES;
+ if (!PROFILE_COMPLAIN(profile) &&
+ !(aa_match(profile->file_rules, hat_name, NULL)
+ & AA_CHANGE_HAT)) {
+ /* missing permission to change_hat is treated the
+ * same as a failed hat search */
+ error = -ENOENT;
goto out;
}
- */
+
if (previous_profile)
profile_name = previous_profile->name;
else
--- a/security/apparmor/procattr.c
+++ b/security/apparmor/procattr.c
@@ -24,15 +24,16 @@ int aa_getprocattr(struct aa_profile *pr
mode_len = strlen(mode_str);
name_len = strlen(profile->name);
if (profile->ns != default_namespace)
- ns_len = strlen(profile->ns->name) + 1;
+ ns_len = strlen(profile->ns->name) + 2;
*len = mode_len + ns_len + name_len + 1;
str = kmalloc(*len, GFP_ATOMIC);
if (!str)
return -ENOMEM;
if (ns_len) {
- memcpy(str, profile->ns->name, ns_len - 1);
- str += ns_len - 1;
+ *str++ = ':';
+ memcpy(str, profile->ns->name, ns_len - 2);
+ str += ns_len - 2;
*str++ = ':';
}
memcpy(str, profile->name, name_len);
@@ -96,11 +97,11 @@ int aa_setprocattr_changeprofile(char *a
{
char *name = args, *ns_name = NULL;
- if (name[0] != '/') {
- char *split = strchr(name, ':');
+ if (name[0] == ':') {
+ char *split = strchr(&name[1], ':');
if (split) {
*split = 0;
- ns_name = name;
+ ns_name = &name[1];
name = split + 1;
}
}

View file

@ -1,18 +0,0 @@
The old style of casting in the rcu_dereference fails to compile with
the newer rcu_dereference macro.
---
security/apparmor/inline.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/security/apparmor/inline.h
+++ b/security/apparmor/inline.h
@@ -19,7 +19,7 @@ static inline int mediated_filesystem(st
static inline struct aa_task_context *aa_task_context(struct task_struct *task)
{
- return rcu_dereference((struct aa_task_context *)task->security);
+ return (struct aa_task_context *) rcu_dereference(task->security);
}
/**

View file

@ -1,15 +0,0 @@
---
security/apparmor/main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/security/apparmor/main.c
+++ b/security/apparmor/main.c
@@ -338,7 +338,7 @@ static void aa_audit_file_mask(struct au
aa_audit_file_sub_mask(ab, other,
(mask & AA_OTHER_PERMS) >> AA_OTHER_SHIFT);
- audit_log_format(ab, " %s=\"%s::%s\"", name, user, other);
+ audit_log_format(ab, " %s=\"%s:%s\"", name, user, other);
}
static const char *address_families[] = {

View file

@ -1,44 +0,0 @@
From: John Johansen <jjohansen@suse.de>
Subject: Call lsm hook before unhashing dentry in vfs_rmdir()
If we unhash the dentry before calling the security_inode_rmdir hook,
we cannot compute the file's pathname in the hook anymore. AppArmor
needs to know the filename in order to decide whether a file may be
deleted, though.
Signed-off-by: John Johansen <jjohansen@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
---
fs/namei.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2097,6 +2097,10 @@ int vfs_rmdir(struct inode *dir, struct
if (!dir->i_op || !dir->i_op->rmdir)
return -EPERM;
+ error = security_inode_rmdir(dir, dentry, mnt);
+ if (error)
+ return error;
+
DQUOT_INIT(dir);
mutex_lock(&dentry->d_inode->i_mutex);
@@ -2104,12 +2108,9 @@ int vfs_rmdir(struct inode *dir, struct
if (d_mountpoint(dentry))
error = -EBUSY;
else {
- error = security_inode_rmdir(dir, dentry, mnt);
- if (!error) {
- error = dir->i_op->rmdir(dir, dentry);
- if (!error)
- dentry->d_inode->i_flags |= S_DEAD;
- }
+ error = dir->i_op->rmdir(dir, dentry);
+ if (!error)
+ dentry->d_inode->i_flags |= S_DEAD;
}
mutex_unlock(&dentry->d_inode->i_mutex);
if (!error) {

View file

@ -1,278 +0,0 @@
---
security/Makefile | 2
security/foobar/Makefile | 1
security/foobar/foobar.c | 257 +++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 260 insertions(+)
--- a/security/Makefile
+++ b/security/Makefile
@@ -16,3 +16,5 @@ obj-$(CONFIG_SECURITY) += security.o d
obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o
+
+subdir-$(CONFIG_SECURITY) += foobar
--- /dev/null
+++ b/security/foobar/Makefile
@@ -0,0 +1 @@
+obj-m += foobar.o
--- /dev/null
+++ b/security/foobar/foobar.c
@@ -0,0 +1,257 @@
+#include <linux/security.h>
+#include <linux/module.h>
+#include <linux/namei.h>
+
+#define log_path(dentry, mnt, fmt...) \
+ __log_path(__FUNCTION__, dentry, mnt, NULL, ##fmt)
+
+#define log_path_inode(inode, fmt...) \
+ __log_path(__FUNCTION__, NULL, NULL, inode, ##fmt)
+
+static int show_traversals;
+module_param(show_traversals, bool, 0644);
+
+static void __log_path(const char *op, struct dentry *dentry,
+ struct vfsmount *mnt, struct inode *inode,
+ char *fmt, ...)
+{
+ va_list ap;
+ char *page = NULL, *name = "<?>";
+
+ page = (char *)__get_free_page(GFP_KERNEL);
+ if (!page)
+ name = "<ENOMEM>";
+ else if (mnt) {
+ name = d_path(dentry, mnt, page + 1, PAGE_SIZE - 2);
+ if (IS_ERR(name)) {
+ snprintf(page, PAGE_SIZE, "<%ld>", PTR_ERR(name));
+ name = page;
+ } else {
+ page[PAGE_SIZE - 2] = '"';
+ page[PAGE_SIZE - 1] = '\0';
+ *--name = '"';
+ }
+ } else if (dentry) {
+ snprintf(page, PAGE_SIZE, "<%s>", dentry->d_name.name);
+ name = page;
+ } else if (inode) {
+ snprintf(page, PAGE_SIZE, "<%s:%ld>",
+ inode->i_sb->s_type->name,
+ inode->i_ino);
+ name = page;
+ }
+
+ if (fmt) {
+ char *buffer = (char *)__get_free_page(GFP_KERNEL);
+
+ if (buffer) {
+ int n;
+
+ n = snprintf(buffer, PAGE_SIZE, KERN_INFO "%s(%s, ",
+ op, name);
+ va_start(ap, fmt);
+ n += vsnprintf(buffer + n, PAGE_SIZE - n, fmt, ap);
+ va_end(ap);
+ snprintf(buffer + n, PAGE_SIZE - n, ")\n");
+ printk("%s", buffer);
+
+ free_page((unsigned long)buffer);
+ } else
+ printk("%s: Out of memory\n", __FUNCTION__);
+ } else
+ printk(KERN_INFO "%s(%s)\n", op, name);
+
+ free_page((unsigned long)page);
+}
+
+static int foobar_inode_mkdir(struct inode *inode, struct dentry *dentry,
+ struct vfsmount *mnt, int mask)
+{
+ log_path(dentry, mnt, NULL);
+
+ return 0;
+}
+
+static int foobar_inode_rmdir(struct inode *inode, struct dentry *dentry,
+ struct vfsmount *mnt)
+{
+ log_path(dentry, mnt, NULL);
+
+ return 0;
+}
+
+static int foobar_inode_create(struct inode *inode, struct dentry *dentry,
+ struct vfsmount *mnt, int mask)
+{
+ log_path(dentry, mnt, NULL);
+
+ return 0;
+}
+
+static int foobar_inode_link(struct dentry *old_dentry,
+ struct vfsmount *old_mnt,
+ struct inode *inode,
+ struct dentry *new_dentry,
+ struct vfsmount *new_mnt)
+{
+ log_path(old_dentry, old_mnt, "<old>");
+ log_path(new_dentry, new_mnt, "<new>");
+
+ return 0;
+}
+
+static int foobar_inode_unlink(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt)
+{
+ log_path(dentry, mnt, NULL);
+
+ return 0;
+}
+
+static int foobar_inode_mknod(struct inode *inode, struct dentry *dentry,
+ struct vfsmount *mnt, int mode, dev_t dev)
+{
+ log_path(dentry, mnt, NULL);
+
+ return 0;
+}
+
+static int foobar_inode_rename(struct inode *old_inode,
+ struct dentry *old_dentry,
+ struct vfsmount *old_mnt,
+ struct inode *new_inode,
+ struct dentry *new_dentry,
+ struct vfsmount *new_mnt)
+{
+ log_path(old_dentry, old_mnt, "<old>");
+ log_path(new_dentry, new_mnt, "<new>");
+
+ return 0;
+}
+
+static int foobar_inode_setattr(struct dentry *dentry, struct vfsmount *mnt,
+ struct iattr *iattr)
+{
+ log_path(dentry, mnt, NULL);
+
+ return 0;
+}
+
+static int foobar_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
+ char *name, void *value, size_t size,
+ int flags, struct file *file)
+{
+ log_path(dentry, mnt, NULL);
+
+ return 0;
+}
+
+static int foobar_inode_getxattr(struct dentry *dentry,
+ struct vfsmount *mnt, char *name, struct file *file)
+{
+ log_path(dentry, mnt, NULL);
+
+ return 0;
+}
+
+static int foobar_inode_listxattr(struct dentry *dentry,
+ struct vfsmount *mnt, struct file *file)
+{
+ log_path(dentry, mnt, NULL);
+
+ return 0;
+}
+
+static int foobar_inode_removexattr(struct dentry *dentry,
+ struct vfsmount *mnt, char *name, struct file *file)
+{
+ log_path(dentry, mnt, NULL);
+
+ return 0;
+}
+
+static int foobar_inode_symlink(struct inode *dir,
+ struct dentry *dentry, struct vfsmount *mnt,
+ const char *old_name)
+{
+ log_path(dentry, mnt, NULL);
+
+ return 0;
+}
+
+static int foobar_inode_permission(struct inode *inode, int mask,
+ struct nameidata *nd)
+{
+ if (nd && (nd->flags & (LOOKUP_PARENT | LOOKUP_CONTINUE)) &&
+ !show_traversals)
+ return 0;
+
+ if (nd) {
+ char *parent = "", *sep="", *cont = "";
+
+ if (nd->flags & LOOKUP_PARENT)
+ parent = "LOOKUP_PARENT";
+ if (nd->flags & LOOKUP_CONTINUE)
+ cont = "LOOKUP_CONTINUE";
+ if ((nd->flags & (LOOKUP_PARENT | LOOKUP_CONTINUE)) ==
+ (LOOKUP_PARENT | LOOKUP_CONTINUE))
+ sep = ", ";
+ else if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_CONTINUE)))
+ sep = "0";
+
+ log_path(nd->dentry, nd->mnt, "%c%c%c%c, %s%s%s",
+ mask & MAY_READ ? 'r' : '-',
+ mask & MAY_WRITE ? 'w' : '-',
+ mask & MAY_EXEC ? 'x' : '-',
+ mask & MAY_APPEND ? 'a' : '-',
+ parent, sep, cont);
+ } else {
+ log_path_inode(inode, "%c%c%c%c, 0",
+ mask & MAY_READ ? 'r' : '-',
+ mask & MAY_WRITE ? 'w' : '-',
+ mask & MAY_EXEC ? 'x' : '-',
+ mask & MAY_APPEND ? 'a' : '-');
+ }
+
+ return 0;
+}
+
+struct security_operations foobar_ops = {
+ .inode_create = foobar_inode_create,
+ .inode_link = foobar_inode_link,
+ .inode_unlink = foobar_inode_unlink,
+ .inode_mkdir = foobar_inode_mkdir,
+ .inode_rmdir = foobar_inode_rmdir,
+ .inode_mknod = foobar_inode_mknod,
+ .inode_rename = foobar_inode_rename,
+ .inode_setattr = foobar_inode_setattr,
+ .inode_setxattr = foobar_inode_setxattr,
+ .inode_getxattr = foobar_inode_getxattr,
+ .inode_listxattr = foobar_inode_listxattr,
+ .inode_removexattr = foobar_inode_removexattr,
+ .inode_symlink = foobar_inode_symlink,
+ .inode_permission = foobar_inode_permission,
+};
+
+static int __init foobar_init(void)
+{
+ int error;
+
+ error = register_security(&foobar_ops);
+ if (error)
+ printk(KERN_ERR "Unable to load foobar lsm\n");
+
+ return error;
+}
+
+static void __exit foobar_exit(void)
+{
+ if (unregister_security(&foobar_ops))
+ printk(KERN_ERR "Unable to properly unregister foobar lsm\n");
+}
+
+module_init(foobar_init);
+module_exit(foobar_exit);
+
+MODULE_DESCRIPTION("lsm module logging to syslog");
+MODULE_LICENSE("GPL");

View file

@ -1,27 +0,0 @@
---
fs/open.c | 3 +++
include/linux/fs.h | 1 +
2 files changed, 4 insertions(+)
--- a/fs/open.c
+++ b/fs/open.c
@@ -207,6 +207,9 @@ int do_truncate(struct dentry *dentry, s
newattrs.ia_size = length;
newattrs.ia_valid = ATTR_SIZE | time_attrs;
+ if (filp)
+ newattrs.ia_valid |= ATTR_FILE;
+
/* Remove suid/sgid on truncate too */
newattrs.ia_valid |= should_remove_suid(dentry);
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -329,6 +329,7 @@ typedef void (dio_iodone_t)(struct kiocb
#define ATTR_ATTR_FLAG 1024
#define ATTR_KILL_SUID 2048
#define ATTR_KILL_SGID 4096
+#define ATTR_FILE 8192
#define ATTR_KILL_PRIV 16384
#define ATTR_OPEN 32768 /* Truncating from open(O_TRUNC) */

View file

@ -1,392 +0,0 @@
Subject: VFS: new fsetattr() file operation
From: Miklos Szeredi <mszeredi@suse.cz>
Add a new file operation: f_op->fsetattr(), that is invoked by
ftruncate, fchmod, fchown and utimensat. Fall back to i_op->setattr()
if it is not defined.
For the reasons why we need this, see patch adding fgetattr().
ftruncate() already passed the open file to the filesystem via the
ia_file member of struct iattr. However it is cleaner to have a
separate file operation for this, so remove ia_file, ATTR_FILE and
convert existing users: fuse and AFS.
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> ---
Signed-off-by: John Johansen <jjohansen@suse.de> ---
---
fs/afs/dir.c | 1 +
fs/afs/file.c | 1 +
fs/afs/inode.c | 19 +++++++++++++++----
fs/afs/internal.h | 1 +
fs/attr.c | 18 ++++++++++++++----
fs/fuse/dir.c | 20 +++++++++-----------
fs/fuse/file.c | 7 +++++++
fs/fuse/fuse_i.h | 4 ++++
fs/open.c | 20 ++++++++------------
fs/utimes.c | 2 +-
include/linux/fs.h | 10 ++--------
11 files changed, 63 insertions(+), 40 deletions(-)
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -45,6 +45,7 @@ const struct file_operations afs_dir_fil
.release = afs_release,
.readdir = afs_readdir,
.lock = afs_lock,
+ .fsetattr = afs_fsetattr,
};
const struct inode_operations afs_dir_inode_operations = {
--- a/fs/afs/file.c
+++ b/fs/afs/file.c
@@ -36,6 +36,7 @@ const struct file_operations afs_file_op
.fsync = afs_fsync,
.lock = afs_lock,
.flock = afs_flock,
+ .fsetattr = afs_fsetattr,
};
const struct inode_operations afs_file_inode_operations = {
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -360,7 +360,8 @@ void afs_clear_inode(struct inode *inode
/*
* set the attributes of an inode
*/
-int afs_setattr(struct dentry *dentry, struct iattr *attr)
+static int afs_do_setattr(struct dentry *dentry, struct iattr *attr,
+ struct file *file)
{
struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode);
struct key *key;
@@ -382,8 +383,8 @@ int afs_setattr(struct dentry *dentry, s
afs_writeback_all(vnode);
}
- if (attr->ia_valid & ATTR_FILE) {
- key = attr->ia_file->private_data;
+ if (file) {
+ key = file->private_data;
} else {
key = afs_request_key(vnode->volume->cell);
if (IS_ERR(key)) {
@@ -393,10 +394,20 @@ int afs_setattr(struct dentry *dentry, s
}
ret = afs_vnode_setattr(vnode, key, attr);
- if (!(attr->ia_valid & ATTR_FILE))
+ if (!file)
key_put(key);
error:
_leave(" = %d", ret);
return ret;
}
+
+int afs_setattr(struct dentry *dentry, struct iattr *attr)
+{
+ return afs_do_setattr(dentry, attr, NULL);
+}
+
+int afs_fsetattr(struct file *file, struct iattr *attr)
+{
+ return afs_do_setattr(file->f_path.dentry, attr, file);
+}
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -550,6 +550,7 @@ extern void afs_zap_data(struct afs_vnod
extern int afs_validate(struct afs_vnode *, struct key *);
extern int afs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
extern int afs_setattr(struct dentry *, struct iattr *);
+extern int afs_fsetattr(struct file *, struct iattr *);
extern void afs_clear_inode(struct inode *);
/*
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -100,8 +100,8 @@ int inode_setattr(struct inode * inode,
}
EXPORT_SYMBOL(inode_setattr);
-int notify_change(struct dentry *dentry, struct vfsmount *mnt,
- struct iattr *attr)
+int fnotify_change(struct dentry *dentry, struct vfsmount *mnt,
+ struct iattr *attr, struct file *file)
{
struct inode *inode = dentry->d_inode;
mode_t mode = inode->i_mode;
@@ -160,8 +160,12 @@ int notify_change(struct dentry *dentry,
if (inode->i_op && inode->i_op->setattr) {
error = security_inode_setattr(dentry, mnt, attr);
- if (!error)
- error = inode->i_op->setattr(dentry, attr);
+ if (!error) {
+ if (file && file->f_op && file->f_op->fsetattr)
+ error = file->f_op->fsetattr(file, attr);
+ else
+ error = inode->i_op->setattr(dentry, attr);
+ }
} else {
error = inode_change_ok(inode, attr);
if (!error)
@@ -184,4 +188,10 @@ int notify_change(struct dentry *dentry,
return error;
}
+int notify_change(struct dentry *dentry, struct vfsmount *mnt,
+ struct iattr *attr)
+{
+ return fnotify_change(dentry, mnt, attr, NULL);
+}
+
EXPORT_SYMBOL(notify_change);
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1063,21 +1063,22 @@ static int fuse_dir_fsync(struct file *f
return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
}
-static bool update_mtime(unsigned ivalid)
+static bool update_mtime(unsigned ivalid, bool have_file)
{
/* Always update if mtime is explicitly set */
if (ivalid & ATTR_MTIME_SET)
return true;
/* If it's an open(O_TRUNC) or an ftruncate(), don't update */
- if ((ivalid & ATTR_SIZE) && (ivalid & (ATTR_OPEN | ATTR_FILE)))
+ if ((ivalid & ATTR_SIZE) && ((ivalid & ATTR_OPEN) || have_file))
return false;
/* In all other cases update */
return true;
}
-static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg)
+static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg,
+ bool have_file)
{
unsigned ivalid = iattr->ia_valid;
@@ -1096,7 +1097,7 @@ static void iattr_to_fattr(struct iattr
if (!(ivalid & ATTR_ATIME_SET))
arg->valid |= FATTR_ATIME_NOW;
}
- if ((ivalid & ATTR_MTIME) && update_mtime(ivalid)) {
+ if ((ivalid & ATTR_MTIME) && update_mtime(ivalid, have_file)) {
arg->valid |= FATTR_MTIME;
arg->mtime = iattr->ia_mtime.tv_sec;
arg->mtimensec = iattr->ia_mtime.tv_nsec;
@@ -1113,8 +1114,8 @@ static void iattr_to_fattr(struct iattr
* vmtruncate() doesn't allow for this case, so do the rlimit checking
* and the actual truncation by hand.
*/
-static int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
- struct file *file)
+int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
+ struct file *file)
{
struct inode *inode = entry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode);
@@ -1152,7 +1153,7 @@ static int fuse_do_setattr(struct dentry
memset(&inarg, 0, sizeof(inarg));
memset(&outarg, 0, sizeof(outarg));
- iattr_to_fattr(attr, &inarg);
+ iattr_to_fattr(attr, &inarg, file != NULL);
if (file) {
struct fuse_file *ff = file->private_data;
inarg.valid |= FATTR_FH;
@@ -1194,10 +1195,7 @@ static int fuse_do_setattr(struct dentry
static int fuse_setattr(struct dentry *entry, struct iattr *attr)
{
- if (attr->ia_valid & ATTR_FILE)
- return fuse_do_setattr(entry, attr, attr->ia_file);
- else
- return fuse_do_setattr(entry, attr, NULL);
+ return fuse_do_setattr(entry, attr, NULL);
}
static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -907,6 +907,11 @@ static sector_t fuse_bmap(struct address
return err ? 0 : outarg.block;
}
+static int fuse_fsetattr(struct file *file, struct iattr *attr)
+{
+ return fuse_do_setattr(file->f_path.dentry, attr, file);
+}
+
static const struct file_operations fuse_file_operations = {
.llseek = generic_file_llseek,
.read = do_sync_read,
@@ -920,6 +925,7 @@ static const struct file_operations fuse
.fsync = fuse_fsync,
.lock = fuse_file_lock,
.flock = fuse_file_flock,
+ .fsetattr = fuse_fsetattr,
.splice_read = generic_file_splice_read,
};
@@ -933,6 +939,7 @@ static const struct file_operations fuse
.fsync = fuse_fsync,
.lock = fuse_file_lock,
.flock = fuse_file_flock,
+ .fsetattr = fuse_fsetattr,
/* no mmap and splice_read */
};
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -505,6 +505,10 @@ void fuse_change_attributes(struct inode
*/
int fuse_dev_init(void);
+
+int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
+ struct file *file);
+
/**
* Cleanup the client device
*/
--- a/fs/open.c
+++ b/fs/open.c
@@ -206,16 +206,12 @@ int do_truncate(struct dentry *dentry, s
newattrs.ia_size = length;
newattrs.ia_valid = ATTR_SIZE | time_attrs;
- if (filp) {
- newattrs.ia_file = filp;
- newattrs.ia_valid |= ATTR_FILE;
- }
/* Remove suid/sgid on truncate too */
newattrs.ia_valid |= should_remove_suid(dentry);
mutex_lock(&dentry->d_inode->i_mutex);
- err = notify_change(dentry, mnt, &newattrs);
+ err = fnotify_change(dentry, mnt, &newattrs, filp);
mutex_unlock(&dentry->d_inode->i_mutex);
return err;
}
@@ -583,7 +579,7 @@ asmlinkage long sys_fchmod(unsigned int
mode = inode->i_mode;
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
- err = notify_change(dentry, file->f_path.mnt, &newattrs);
+ err = fnotify_change(dentry, file->f_path.mnt, &newattrs, file);
mutex_unlock(&inode->i_mutex);
out_putf:
@@ -633,7 +629,7 @@ asmlinkage long sys_chmod(const char __u
}
static int chown_common(struct dentry * dentry, struct vfsmount *mnt,
- uid_t user, gid_t group)
+ uid_t user, gid_t group, struct file *file)
{
struct inode * inode;
int error;
@@ -663,7 +659,7 @@ static int chown_common(struct dentry *
newattrs.ia_valid |=
ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV;
mutex_lock(&inode->i_mutex);
- error = notify_change(dentry, mnt, &newattrs);
+ error = fnotify_change(dentry, mnt, &newattrs, file);
mutex_unlock(&inode->i_mutex);
out:
return error;
@@ -677,7 +673,7 @@ asmlinkage long sys_chown(const char __u
error = user_path_walk(filename, &nd);
if (error)
goto out;
- error = chown_common(nd.dentry, nd.mnt, user, group);
+ error = chown_common(nd.dentry, nd.mnt, user, group, NULL);
path_release(&nd);
out:
return error;
@@ -697,7 +693,7 @@ asmlinkage long sys_fchownat(int dfd, co
error = __user_walk_fd(dfd, filename, follow, &nd);
if (error)
goto out;
- error = chown_common(nd.dentry, nd.mnt, user, group);
+ error = chown_common(nd.dentry, nd.mnt, user, group, NULL);
path_release(&nd);
out:
return error;
@@ -711,7 +707,7 @@ asmlinkage long sys_lchown(const char __
error = user_path_walk_link(filename, &nd);
if (error)
goto out;
- error = chown_common(nd.dentry, nd.mnt, user, group);
+ error = chown_common(nd.dentry, nd.mnt, user, group, NULL);
path_release(&nd);
out:
return error;
@@ -730,7 +726,7 @@ asmlinkage long sys_fchown(unsigned int
dentry = file->f_path.dentry;
audit_inode(NULL, dentry);
- error = chown_common(dentry, file->f_path.mnt, user, group);
+ error = chown_common(dentry, file->f_path.mnt, user, group, file);
fput(file);
out:
return error;
--- a/fs/utimes.c
+++ b/fs/utimes.c
@@ -132,7 +132,7 @@ long do_utimes(int dfd, char __user *fil
}
}
mutex_lock(&inode->i_mutex);
- error = notify_change(path.dentry, path.mnt, &newattrs);
+ error = fnotify_change(path.dentry, path.mnt, &newattrs, f);
mutex_unlock(&inode->i_mutex);
dput_and_out:
if (f)
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -329,7 +329,6 @@ typedef void (dio_iodone_t)(struct kiocb
#define ATTR_ATTR_FLAG 1024
#define ATTR_KILL_SUID 2048
#define ATTR_KILL_SGID 4096
-#define ATTR_FILE 8192
#define ATTR_KILL_PRIV 16384
#define ATTR_OPEN 32768 /* Truncating from open(O_TRUNC) */
@@ -351,13 +350,6 @@ struct iattr {
struct timespec ia_atime;
struct timespec ia_mtime;
struct timespec ia_ctime;
-
- /*
- * Not an attribute, but an auxilary info for filesystems wanting to
- * implement an ftruncate() like method. NOTE: filesystem should
- * check for (ia_valid & ATTR_FILE), and not for (ia_file != NULL).
- */
- struct file *ia_file;
};
/*
@@ -1188,6 +1180,7 @@ struct file_operations {
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **);
+ int (*fsetattr)(struct file *, struct iattr *);
};
struct inode_operations {
@@ -1694,6 +1687,7 @@ extern int do_remount_sb(struct super_bl
extern sector_t bmap(struct inode *, sector_t);
#endif
extern int notify_change(struct dentry *, struct vfsmount *, struct iattr *);
+extern int fnotify_change(struct dentry *, struct vfsmount *, struct iattr *, struct file *);
extern int permission(struct inode *, int, struct nameidata *);
extern int generic_permission(struct inode *, int,
int (*check_acl)(struct inode *, int));

View file

@ -1,39 +0,0 @@
---
security/apparmor/apparmor.h | 5 +++--
security/apparmor/main.c | 9 +++++++++
2 files changed, 12 insertions(+), 2 deletions(-)
--- a/security/apparmor/apparmor.h
+++ b/security/apparmor/apparmor.h
@@ -68,10 +68,11 @@
#define AA_ALL_EXEC_MODS (AA_USER_EXEC_MODS | \
AA_OTHER_EXEC_MODS)
-/* shared permissions that are not duplicated in user:group:other */
+/* shared permissions that are not duplicated in user::other */
+#define AA_CHANGE_HAT 0x20000000
#define AA_CHANGE_PROFILE 0x40000000
-#define AA_SHARED_PERMS (AA_CHANGE_PROFILE)
+#define AA_SHARED_PERMS (AA_CHANGE_HAT | AA_CHANGE_PROFILE)
#define AA_VALID_PERM_MASK (AA_FILE_PERMS | AA_SHARED_PERMS)
--- a/security/apparmor/main.c
+++ b/security/apparmor/main.c
@@ -1300,6 +1300,15 @@ repeat:
if (hat_name) {
char *name, *profile_name;
+ /* Not Yet. This perm check is currently done by searching
+ for the hat profile. When hat style profile names
+ become more generic then this will be needed.
+ if (!(aa_match(profile->file_rules, hat_name) &
+ AA_CHANGE_PROFILE)) {
+ error = -EACCES;
+ goto out;
+ }
+ */
if (previous_profile)
profile_name = previous_profile->name;
else

View file

@ -1,86 +0,0 @@
From: Andreas Gruenbacher <agruen@suse.de>
Subject: Remove redundant may_create() argument
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
---
fs/namei.c | 22 ++++++++++------------
1 file changed, 10 insertions(+), 12 deletions(-)
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1462,16 +1462,14 @@ static int may_delete(struct inode *dir,
* 3. We should have write and exec permissions on dir
* 4. We can't do it if dir is immutable (done in permission())
*/
-static inline int may_create(struct inode *dir, struct dentry *child,
- struct nameidata2 *nd)
+static inline int may_create(struct nameidata2 *nd, struct dentry *child)
{
if (child->d_inode)
return -EEXIST;
- if (IS_DEADDIR(dir))
+ if (IS_DEADDIR(nd->dentry->d_inode))
return -ENOENT;
- if (nd)
- nd->flags |= LOOKUP_CONTINUE;
- return permission(dir,MAY_WRITE | MAY_EXEC, nd);
+ nd->flags |= LOOKUP_CONTINUE;
+ return permission(nd->dentry->d_inode, MAY_WRITE | MAY_EXEC, nd);
}
/*
@@ -1537,7 +1535,7 @@ void unlock_rename(struct dentry *p1, st
int vfs_create(struct nameidata2 *nd, struct dentry *dentry, int mode)
{
struct inode *dir = nd->dentry->d_inode;
- int error = may_create(dir, dentry, nd);
+ int error = may_create(nd, dentry);
if (error)
return error;
@@ -1883,7 +1881,7 @@ EXPORT_SYMBOL_GPL(lookup_create);
int vfs_mknod(struct nameidata2 *nd, struct dentry *dentry, int mode, dev_t dev)
{
struct inode *dir = nd->dentry->d_inode;
- int error = may_create(dir, dentry, nd);
+ int error = may_create(nd, dentry);
if (error)
return error;
@@ -1963,7 +1961,7 @@ asmlinkage long sys_mknod(const char __u
int vfs_mkdir(struct nameidata2 *nd, struct dentry *dentry, int mode)
{
struct inode *dir = nd->dentry->d_inode;
- int error = may_create(dir, dentry, nd);
+ int error = may_create(nd, dentry);
if (error)
return error;
@@ -2232,7 +2230,7 @@ int vfs_symlink(struct nameidata2 *nd, s
const char *oldname, int mode)
{
struct inode *dir = nd->dentry->d_inode;
- int error = may_create(dir, dentry, nd);
+ int error = may_create(nd, dentry);
if (error)
return error;
@@ -2304,7 +2302,7 @@ int vfs_link(struct nameidata2 *old_nd,
if (!inode)
return -ENOENT;
- error = may_create(dir, new_dentry, new_parent);
+ error = may_create(new_parent, new_dentry);
if (error)
return error;
@@ -2522,7 +2520,7 @@ int vfs_rename(struct nameidata2 *old_nd
return error;
if (!new_dentry->d_inode)
- error = may_create(new_dir, new_dentry, new_nd);
+ error = may_create(new_nd, new_dentry);
else
error = may_delete(new_dir, new_dentry, is_dir);
if (error)

View file

@ -1,74 +0,0 @@
From: Andreas Gruenbacher <agruen@suse.de>
Subject: Pass nameidata2 to may_delete()
Pass the nameidata through to may_delete(), and pass it on to the
permission() call.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
---
fs/namei.c | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1418,8 +1418,9 @@ static inline int check_sticky(struct in
* 10. We don't allow removal of NFS sillyrenamed files; it's handled by
* nfs_async_unlink().
*/
-static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
+static int may_delete(struct nameidata2 *nd, struct dentry *victim, int isdir)
{
+ struct inode *dir = nd->dentry->d_inode;
int error;
if (!victim->d_inode)
@@ -1428,11 +1429,8 @@ static int may_delete(struct inode *dir,
BUG_ON(victim->d_parent->d_inode != dir);
audit_inode_child(victim->d_name.name, victim->d_inode, dir);
-#if 0
- if (nd)
- nd->flags |= LOOKUP_CONTINUE;
-#endif
- error = permission(dir,MAY_WRITE | MAY_EXEC, NULL);
+ nd->flags |= LOOKUP_CONTINUE;
+ error = permission(dir,MAY_WRITE | MAY_EXEC, nd);
if (error)
return error;
if (IS_APPEND(dir))
@@ -2049,7 +2047,7 @@ void dentry_unhash(struct dentry *dentry
int vfs_rmdir(struct nameidata2 *nd, struct dentry *dentry)
{
struct inode *dir = nd->dentry->d_inode;
- int error = may_delete(dir, dentry, 1);
+ int error = may_delete(nd, dentry, 1);
if (error)
return error;
@@ -2131,7 +2129,7 @@ asmlinkage long sys_rmdir(const char __u
int vfs_unlink(struct nameidata2 *nd, struct dentry *dentry)
{
struct inode *dir = nd->dentry->d_inode;
- int error = may_delete(dir, dentry, 0);
+ int error = may_delete(nd, dentry, 0);
if (error)
return error;
@@ -2517,14 +2515,14 @@ int vfs_rename(struct nameidata2 *old_nd
if (old_dentry->d_inode == new_dentry->d_inode)
return 0;
- error = may_delete(old_dir, old_dentry, is_dir);
+ error = may_delete(old_nd, old_dentry, is_dir);
if (error)
return error;
if (!new_dentry->d_inode)
error = may_create(new_nd, new_dentry);
else
- error = may_delete(new_dir, new_dentry, is_dir);
+ error = may_delete(new_nd, new_dentry, is_dir);
if (error)
return error;

View file

@ -1,60 +0,0 @@
From: Andreas Gruenbacher <agruen@suse.de>
Subject: Make d_path() consistent across mount operations
The path that __d_path() computes can become slightly inconsistent when it
races with mount operations: it grabs the vfsmount_lock when traversing mount
points but immediately drops it again, only to re-grab it when it reaches the
next mount point. The result is that the filename computed is not always
consisent, and the file may never have had that name. (This is unlikely, but
still possible.)
Fix this by grabbing the vfsmount_lock when the first mount point is reached,
and holding onto it until the d_cache lookup is completed.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
fs/dcache.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1786,7 +1786,7 @@ static char *__d_path(struct dentry *den
struct dentry *root, struct vfsmount *rootmnt,
char *buffer, int buflen, int fail_deleted)
{
- int namelen, is_slash;
+ int namelen, is_slash, vfsmount_locked = 0;
if (buflen < 2)
return ERR_PTR(-ENAMETOOLONG);
@@ -1809,14 +1809,14 @@ static char *__d_path(struct dentry *den
struct dentry * parent;
if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
- spin_lock(&vfsmount_lock);
- if (vfsmnt->mnt_parent == vfsmnt) {
- spin_unlock(&vfsmount_lock);
- goto global_root;
+ if (!vfsmount_locked) {
+ spin_lock(&vfsmount_lock);
+ vfsmount_locked = 1;
}
+ if (vfsmnt->mnt_parent == vfsmnt)
+ goto global_root;
dentry = vfsmnt->mnt_mountpoint;
vfsmnt = vfsmnt->mnt_parent;
- spin_unlock(&vfsmount_lock);
continue;
}
parent = dentry->d_parent;
@@ -1835,6 +1835,8 @@ static char *__d_path(struct dentry *den
*--buffer = '/';
out:
+ if (vfsmount_locked)
+ spin_unlock(&vfsmount_lock);
spin_unlock(&dcache_lock);
return buffer;

View file

@ -1,47 +0,0 @@
From: Andreas Gruenbacher <agruen@suse.de>
Subject: nfs NULL nameidata check?
nfs_lookup() checks for NULL nameidata in one place, but not in another. In
nfs_sillyrename() it calls lookup_one_len() -> __lookup_hash(), which passes
in a NULL nameidata to nfs_lookup(). Unless I'm overlooking something,
fs/nfs/dir.c:923 will dereference this NULL pointer if the sillyrenamed file
exists?
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
---
fs/nfs/dir.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -896,15 +896,15 @@ int nfs_is_exclusive_create(struct inode
return (nd->intent.open.flags & O_EXCL) != 0;
}
-static inline int nfs_reval_fsid(struct vfsmount *mnt, struct inode *dir,
+static inline int nfs_reval_fsid(struct nameidata *nd, struct inode *dir,
struct nfs_fh *fh, struct nfs_fattr *fattr)
{
struct nfs_server *server = NFS_SERVER(dir);
- if (!nfs_fsid_equal(&server->fsid, &fattr->fsid))
- /* Revalidate fsid on root dir */
- return __nfs_revalidate_inode(server, mnt->mnt_root->d_inode);
- return 0;
+ if (nd == NULL || nfs_fsid_equal(&server->fsid, &fattr->fsid))
+ return 0;
+ /* Revalidate fsid on root dir */
+ return __nfs_revalidate_inode(server, nd->mnt->mnt_root->d_inode);
}
static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata2 *nd)
@@ -945,7 +945,7 @@ static struct dentry *nfs_lookup(struct
res = ERR_PTR(error);
goto out_unlock;
}
- error = nfs_reval_fsid(nd->mnt, dir, &fhandle, &fattr);
+ error = nfs_reval_fsid(nd, dir, &fhandle, &fattr);
if (error < 0) {
res = ERR_PTR(error);
goto out_unlock;

View file

@ -1,45 +0,0 @@
From: Andreas Gruenbacher <agruen@suse.de>
Subject: Pass nameidata2 to permission() from nfsd_permission()
Construct a nameidata object and pass it down to permission(), so
that we can do the proper mount flag checks there.
Note that confining nfsd with AppArmor makes no sense, and so this
patch is not necessary for AppArmor alone.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
fs/nfsd/vfs.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1804,6 +1804,7 @@ nfsd_statfs(struct svc_rqst *rqstp, stru
__be32
nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc)
{
+ struct nameidata2 nd;
struct inode *inode = dentry->d_inode;
int err;
@@ -1869,12 +1870,16 @@ nfsd_permission(struct svc_export *exp,
inode->i_uid == current->fsuid)
return 0;
- err = permission(inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC), NULL);
+ nd.dentry = dentry;
+ nd.mnt = exp->ex_mnt;
+ nd.flags = LOOKUP_ACCESS;
+
+ err = permission(inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC), &nd);
/* Allow read access to binaries even when mode 111 */
if (err == -EACCES && S_ISREG(inode->i_mode) &&
acc == (MAY_READ | MAY_OWNER_OVERRIDE))
- err = permission(inode, MAY_EXEC, NULL);
+ err = permission(inode, MAY_EXEC, &nd);
return err? nfserrno(err) : 0;
}

View file

@ -1,139 +0,0 @@
---
security/apparmor/apparmor.h | 21 ++++++++++-----------
security/apparmor/main.c | 40 ++++++++++++----------------------------
security/apparmor/match.c | 9 +++++++--
3 files changed, 29 insertions(+), 41 deletions(-)
--- a/security/apparmor/apparmor.h
+++ b/security/apparmor/apparmor.h
@@ -42,15 +42,18 @@
AA_EXEC_MOD_2 | AA_EXEC_MOD_3 | \
AA_EXEC_MOD_4)
+#define AA_EXEC_MODIFIERS (AA_EXEC_MOD_0 | AA_EXEC_MOD_1 | \
+ AA_EXEC_MOD_2 | AA_EXEC_MOD_3 | \
+ AA_EXEC_MOD_4)
+
+#define AA_EXEC_TYPE (MAY_EXEC | AA_EXEC_UNSAFE | \
+ AA_EXEC_MODIFIERS)
+
#define AA_EXEC_UNCONFINED AA_EXEC_MOD_0
#define AA_EXEC_INHERIT AA_EXEC_MOD_1
#define AA_EXEC_PROFILE (AA_EXEC_MOD_0 | AA_EXEC_MOD_1)
#define AA_EXEC_PIX AA_EXEC_MOD_2
-#define AA_EXEC_MODIFIERS (AA_EXEC_MOD_0 | AA_EXEC_MOD_1 | \
- AA_EXEC_MOD_2 | AA_EXEC_MOD_3 | \
- AA_EXEC_MOD_4)
-
#define AA_USER_SHIFT 0
#define AA_OTHER_SHIFT 14
@@ -65,16 +68,12 @@
#define AA_USER_EXEC (MAY_EXEC << AA_USER_SHIFT)
#define AA_OTHER_EXEC (MAY_EXEC << AA_OTHER_SHIFT)
-#define AA_USER_EXEC_MODS (AA_EXEC_MODIFIERS << AA_USER_SHIFT)
-#define AA_OTHER_EXEC_MODS (AA_EXEC_MODIFIERS << AA_OTHER_SHIFT)
-
-#define AA_USER_EXEC_UNSAFE (AA_EXEC_UNSAFE << AA_USER_SHIFT)
-#define AA_OTHER_EXEC_UNSAFE (AA_EXEC_UNSAFE << AA_OTHER_SHIFT)
+#define AA_USER_EXEC_TYPE (AA_EXEC_TYPE << AA_USER_SHIFT)
+#define AA_OTHER_EXEC_TYPE (AA_EXEC_TYPE << AA_OTHER_SHIFT)
#define AA_EXEC_BITS (AA_USER_EXEC | AA_OTHER_EXEC)
-#define AA_ALL_EXEC_MODS (AA_USER_EXEC_MODS | \
- AA_OTHER_EXEC_MODS)
+#define ALL_AA_EXEC_TYPE (AA_USER_EXEC_TYPE | AA_OTHER_EXEC_TYPE)
/* overloaded permissions for link pairs */
#define AA_LINK_SUBSET_TEST 0x0020
--- a/security/apparmor/main.c
+++ b/security/apparmor/main.c
@@ -68,7 +68,7 @@ static int aa_link_denied(struct aa_prof
int *request_mask)
{
unsigned int state;
- int l_mode, t_mode, l_subset, denied_mask = 0;
+ int l_mode, t_mode, denied_mask = 0;
int link_mask = AA_MAY_LINK << target_mode;
*request_mask = link_mask;
@@ -90,7 +90,7 @@ static int aa_link_denied(struct aa_prof
/* Do link perm subset test
* If a subset test is required a permission subset test of the
- * perms for the link are done against the user:group:other of the
+ * perms for the link are done against the user::other of the
* target's 'r', 'w', 'x', 'a', 'k', and 'm' permissions.
*
* If the link has 'x', an exact match of all the execute flags
@@ -100,38 +100,22 @@ static int aa_link_denied(struct aa_prof
t_mode = aa_match(profile->file_rules, target);
-
/* For actual subset test ignore valid-profile-transition flags,
* and link bits
*/
- l_mode &= ~(AA_SHARED_PERMS | AA_LINK_BITS);
- t_mode &= ~(AA_SHARED_PERMS | AA_LINK_BITS);
- l_subset = l_mode & AA_FILE_PERMS;
+ l_mode &= AA_FILE_PERMS & ~AA_LINK_BITS;
+ t_mode &= AA_FILE_PERMS & ~AA_LINK_BITS;
*request_mask = l_mode | link_mask;
- if (l_subset) {
- denied_mask |= (l_subset) & ~t_mode;
- if (denied_mask & AA_EXEC_BITS)
- denied_mask |= l_mode & AA_ALL_EXEC_MODS;
- else if (l_mode & AA_EXEC_BITS) {
- if (!(l_mode & AA_USER_EXEC_UNSAFE))
- l_mode |= t_mode & AA_USER_EXEC_UNSAFE;
- if (l_mode & AA_USER_EXEC &&
- (l_mode & AA_USER_EXEC_MODS) !=
- (t_mode & AA_USER_EXEC_MODS))
- denied_mask |= AA_USER_EXEC |
- (l_mode & AA_USER_EXEC_MODS);
- if (!(l_mode & AA_OTHER_EXEC_UNSAFE))
- l_mode |= t_mode & AA_OTHER_EXEC_UNSAFE;
- if (l_mode & AA_OTHER_EXEC &&
- (l_mode & AA_OTHER_EXEC_MODS) !=
- (t_mode & AA_OTHER_EXEC_MODS))
- denied_mask |= AA_OTHER_EXEC |
- (l_mode & AA_OTHER_EXEC_MODS);
- }
- } else if (t_mode & AA_FILE_PERMS)
- denied_mask |= t_mode | link_mask;
+ if (l_mode) {
+ denied_mask |= l_mode & ~t_mode;
+ if ((l_mode & AA_EXEC_BITS) &&
+ (l_mode & ALL_AA_EXEC_TYPE) !=
+ (t_mode & ALL_AA_EXEC_TYPE))
+ denied_mask = (denied_mask & ~ALL_AA_EXEC_TYPE) |
+ (l_mode & ALL_AA_EXEC_TYPE);
+ }
return denied_mask;
}
--- a/security/apparmor/match.c
+++ b/security/apparmor/match.c
@@ -175,9 +175,14 @@ int verify_dfa(struct aa_dfa *dfa)
for (i = 0; i < state_count; i++) {
int mode = ACCEPT_TABLE(dfa)[i];
- if (mode & ~AA_VALID_PERM_MASK) {
+ if (mode & ~AA_VALID_PERM_MASK)
+ goto out;
+
+ /* if any exec modifier is set MAY_EXEC must be set */
+ if ((mode & AA_USER_EXEC_TYPE) && !(mode & AA_USER_EXEC))
+ goto out;
+ if ((mode & AA_OTHER_EXEC_TYPE) && !(mode & AA_OTHER_EXEC))
goto out;
- }
}
error = 0;

View file

@ -1,3 +0,0 @@
obj-$(CONFIG_SECURITY_FOOBAR) += foobar.o
foobar-y := foobar-lsm.o

View file

@ -1 +0,0 @@
obj-m += foobar.o

View file

@ -1,197 +0,0 @@
#include <linux/security.h>
#include <linux/module.h>
#include <linux/namei.h>
static void log_path(char *op, struct dentry *dentry, struct vfsmount *mnt)
{
char *page, *name;
if (!mnt) {
printk(KERN_INFO "foobar(%s): %p NULL vfsmnt\n", op, dentry);
return;
}
page = (char *)__get_free_page(GFP_KERNEL);
if (!page) {
printk(KERN_ERR "foobar(%s): Unable to get page for path %p/%p\n",
op, mnt, dentry);
goto out;
}
name=d_path(dentry, mnt, page, PAGE_SIZE);
if (IS_ERR(name)){
printk(KERN_ERR "foobar(%s): Error path %p/%p overflowed buffer\n",
op, mnt, dentry);
goto out;
}
printk(KERN_INFO "foobar(%s): %p/%p->'%s'\n",
op, mnt, dentry, name);
out:
if (page)
free_page((unsigned long)page);
}
static int foobar_inode_mkdir(struct inode *inode, struct dentry *dentry,
struct vfsmount *mnt, int mask)
{
log_path("inode_mkdir", dentry, mnt);
return 0;
}
static int foobar_inode_rmdir(struct inode *inode, struct dentry *dentry,
struct vfsmount *mnt)
{
log_path("inode_rmdir", dentry, mnt);
return 0;
}
static int foobar_inode_create(struct inode *inode, struct dentry *dentry,
struct vfsmount *mnt, int mask)
{
log_path("inode_create", dentry, mnt);
return 0;
}
static int foobar_inode_link(struct dentry *old_dentry,
struct vfsmount *old_mnt,
struct inode *inode,
struct dentry *new_dentry,
struct vfsmount *new_mnt)
{
log_path("inode_link (old)", old_dentry, old_mnt);
log_path("inode_link (new)", new_dentry, new_mnt);
return 0;
}
static int foobar_inode_unlink(struct inode *dir, struct dentry *dentry,
struct vfsmount *mnt)
{
log_path("inode_unlink", dentry, mnt);
return 0;
}
static int foobar_inode_mknod(struct inode *inode, struct dentry *dentry,
struct vfsmount *mnt, int mode, dev_t dev)
{
log_path("inode_mknod", dentry, mnt);
return 0;
}
static int foobar_inode_rename(struct inode *old_inode,
struct dentry *old_dentry,
struct vfsmount *old_mnt,
struct inode *new_inode,
struct dentry *new_dentry,
struct vfsmount *new_mnt)
{
log_path("inode_rename (old)", old_dentry, old_mnt);
log_path("inode_rename (new)", new_dentry, new_mnt);
return 0;
}
static int foobar_inode_setattr(struct dentry *dentry, struct vfsmount *mnt,
struct iattr *iattr)
{
log_path("inode_setattr", dentry, mnt);
return 0;
}
static int foobar_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
char *name, void *value, size_t size,
int flags)
{
log_path("inode_setxattr", dentry, mnt);
return 0;
}
static int foobar_inode_getxattr(struct dentry *dentry,
struct vfsmount *mnt, char *name)
{
log_path("inode_getxattr", dentry, mnt);
return 0;
}
static int foobar_inode_listxattr(struct dentry *dentry,
struct vfsmount *mnt)
{
log_path("inode_listxattr", dentry, mnt);
return 0;
}
static int foobar_inode_removexattr(struct dentry *dentry,
struct vfsmount *mnt, char *name)
{
log_path("inode_removexattr", dentry, mnt);
return 0;
}
static int foobar_inode_symlink(struct inode *dir,
struct dentry *dentry, struct vfsmount *mnt,
const char *old_name)
{
log_path("inode_symlink", dentry, mnt);
return 0;
}
static int foobar_inode_permission(struct inode *inode, int mask,
struct nameidata *nd)
{
log_path("inode_permission", nd->dentry, nd->mnt);
return 0;
}
struct security_operations foobar_ops = {
.inode_create = foobar_inode_create,
.inode_link = foobar_inode_link,
.inode_unlink = foobar_inode_unlink,
.inode_mkdir = foobar_inode_mkdir,
.inode_rmdir = foobar_inode_rmdir,
.inode_mknod = foobar_inode_mknod,
.inode_rename = foobar_inode_rename,
.inode_setattr = foobar_inode_setattr,
.inode_setxattr = foobar_inode_setxattr,
.inode_getxattr = foobar_inode_getxattr,
.inode_listxattr = foobar_inode_listxattr,
.inode_removexattr = foobar_inode_removexattr,
.inode_symlink = foobar_inode_symlink,
// .inode_permission = foobar_inode_permission,
};
static int __init foobar_init(void)
{
int error;
if ((error = register_security(&foobar_ops))) {
printk(KERN_ERR "Unable to load dummy module\n");
}
return error;
}
static void __exit foobar_exit(void)
{
if (unregister_security(&foobar_ops))
printk(KERN_ERR "Unable to properly unregister module\n");
}
module_init(foobar_init);
module_exit(foobar_exit);
MODULE_DESCRIPTION("Test module");
MODULE_LICENSE("GPL");

View file

@ -1,561 +0,0 @@
---
security/apparmor/apparmor.h | 60 +++++++---
security/apparmor/apparmorfs.c | 2
security/apparmor/lsm.c | 2
security/apparmor/main.c | 193 +++++++++++++++++++++++------------
security/apparmor/match.c | 8 -
security/apparmor/module_interface.c | 3
6 files changed, 179 insertions(+), 89 deletions(-)
--- a/security/apparmor/apparmor.h
+++ b/security/apparmor/apparmor.h
@@ -26,22 +26,50 @@
#define AA_MAY_LINK 0x0010
#define AA_MAY_LOCK 0x0020
#define AA_EXEC_MMAP 0x0040
+#define AA_EXEC_UNSAFE 0x0080
+#define AA_EXEC_MOD_0 0x0100
+#define AA_EXEC_MOD_1 0x0200
+#define AA_BASE_PERMS (MAY_READ | MAY_WRITE | MAY_EXEC | \
+ MAY_APPEND | AA_MAY_LINK | \
+ AA_MAY_LOCK | AA_EXEC_MMAP | \
+ AA_EXEC_UNSAFE | AA_EXEC_MOD_0 | \
+ AA_EXEC_MOD_1)
-#define AA_CHANGE_PROFILE 0x04000000
-#define AA_EXEC_INHERIT 0x08000000
-#define AA_EXEC_UNCONFINED 0x10000000
-#define AA_EXEC_PROFILE 0x20000000
-#define AA_EXEC_UNSAFE 0x40000000
-
-#define AA_EXEC_MODIFIERS (AA_EXEC_INHERIT | \
- AA_EXEC_UNCONFINED | \
- AA_EXEC_PROFILE)
+#define AA_EXEC_UNCONFINED 0
+#define AA_EXEC_INHERIT AA_EXEC_MOD_0
+#define AA_EXEC_PROFILE AA_EXEC_MOD_1
+#define AA_EXEC_PIX (AA_EXEC_MOD_0 | AA_EXEC_MOD_1)
-#define AA_VALID_PERM_MASK (MAY_READ | MAY_WRITE | MAY_EXEC | \
- MAY_APPEND | AA_MAY_LINK | \
- AA_MAY_LOCK | \
- AA_EXEC_MODIFIERS | AA_EXEC_MMAP | \
- AA_EXEC_UNSAFE | AA_CHANGE_PROFILE)
+#define AA_EXEC_MODIFIERS (AA_EXEC_MOD_0 | AA_EXEC_MOD_1)
+
+#define AA_USER_SHIFT 0
+#define AA_OTHER_SHIFT 10
+
+#define AA_USER_PERMS (AA_BASE_PERMS << AA_USER_SHIFT)
+#define AA_OTHER_PERMS (AA_BASE_PERMS << AA_OTHER_SHIFT)
+
+#define AA_FILE_PERMS (AA_USER_PERMS | AA_OTHER_PERMS)
+
+#define AA_LINK_BITS ((AA_MAY_LINK << AA_USER_SHIFT) | \
+ (AA_MAY_LINK << AA_OTHER_SHIFT))
+
+#define AA_USER_EXEC (MAY_EXEC << AA_USER_SHIFT)
+#define AA_OTHER_EXEC (MAY_EXEC << AA_OTHER_SHIFT)
+
+#define AA_USER_EXEC_MODS (AA_EXEC_MODIFIERS << AA_USER_SHIFT)
+#define AA_OTHER_EXEC_MODS (AA_EXEC_MODIFIERS << AA_OTHER_SHIFT)
+
+#define AA_EXEC_BITS (AA_USER_EXEC | AA_OTHER_EXEC)
+
+#define AA_ALL_EXEC_MODS (AA_USER_EXEC_MODS | \
+ AA_OTHER_EXEC_MODS)
+
+/* shared permissions that are not duplicated in user:group:other */
+#define AA_CHANGE_PROFILE 0x40000000
+
+#define AA_SHARED_PERMS (AA_CHANGE_PROFILE)
+
+#define AA_VALID_PERM_MASK (AA_FILE_PERMS | AA_SHARED_PERMS)
#define AA_SECURE_EXEC_NEEDED 1
@@ -183,7 +211,7 @@ struct aa_audit {
const char *name;
const char *name2;
const char *name3;
- int requested_mask, denied_mask;
+ int request_mask, denied_mask;
struct iattr *iattr;
pid_t task, parent;
int family, type, protocol;
@@ -226,7 +254,7 @@ extern int aa_perm_dir(struct aa_profile
struct dentry *dentry, struct vfsmount *mnt,
int mask);
extern int aa_perm_path(struct aa_profile *, const char *operation,
- const char *name, int);
+ const char *name, int mask, uid_t uid);
extern int aa_link(struct aa_profile *profile,
struct dentry *link, struct vfsmount *link_mnt,
struct dentry *target, struct vfsmount *target_mnt);
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -89,7 +89,7 @@ static struct file_operations apparmorfs
static ssize_t aa_matching_read(struct file *file, char __user *buf,
size_t size, loff_t *ppos)
{
- const char *matching = "pattern=aadfa perms=rwxamlz";
+ const char *matching = "pattern=aadfa perms=rwxamlz user:other";
return simple_read_from_buffer(buf, size, ppos, matching,
strlen(matching));
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -199,7 +199,7 @@ static int apparmor_sysctl(struct ctl_ta
if (name && name - buffer >= 5) {
name -= 5;
memcpy(name, "/proc", 5);
- error = aa_perm_path(profile, "sysctl", name, mask);
+ error = aa_perm_path(profile, "sysctl", name, mask, 0);
}
free_page((unsigned long)buffer);
}
--- a/security/apparmor/main.c
+++ b/security/apparmor/main.c
@@ -31,6 +31,14 @@ static const char *capability_names[] =
struct aa_namespace *default_namespace;
+static int aa_inode_mode(struct inode *inode)
+{
+ /* if the inode doesn't exist the user is creating it */
+ if (!inode || current->fsuid == inode->i_uid)
+ return AA_USER_SHIFT;
+ return AA_OTHER_SHIFT;
+}
+
/**
* aa_file_denied - check for @mask access on a file
* @profile: profile to check against
@@ -51,39 +59,52 @@ static int aa_file_denied(struct aa_prof
* @profile: profile to check against
* @link: pathname of link being created
* @target: pathname of target to be linked to
+ * @target_mode: UGO shift for target inode
* @request_mask: the permissions subset valid only if link succeeds
* Return %0 on success, or else the permissions that the profile denies.
*/
static int aa_link_denied(struct aa_profile *profile, const char *link,
- const char *target, int *request_mask)
+ const char *target, int target_mode,
+ int *request_mask)
{
int l_mode, t_mode, denied_mask;
+ int link_mask = AA_MAY_LINK << target_mode;
l_mode = aa_match(profile->file_rules, link);
t_mode = aa_match(profile->file_rules, target);
/* Ignore valid-profile-transition flags. */
- l_mode &= ~AA_CHANGE_PROFILE;
- t_mode &= ~AA_CHANGE_PROFILE;
+ l_mode &= ~AA_SHARED_PERMS;
+ t_mode &= ~AA_SHARED_PERMS;
- *request_mask = l_mode | AA_MAY_LINK;
-
- /* Link always requires 'l' on the link, a subset of the
- * target's 'r', 'w', 'x', 'a', 'z', and 'm' permissions on the link,
- * and if the link has 'x', an exact match of all the execute flags
- * ('i', 'u', 'U', 'p', 'P').
- */
-#define RWXAZM (MAY_READ | MAY_WRITE | MAY_EXEC | MAY_APPEND | AA_MAY_LOCK | \
- AA_EXEC_MMAP)
- denied_mask = ~l_mode & AA_MAY_LINK;
- if (l_mode & RWXAZM)
- denied_mask |= (l_mode & ~ AA_MAY_LINK) & ~t_mode;
- else
- denied_mask |= t_mode | AA_MAY_LINK;
- if (denied_mask & AA_EXEC_MODIFIERS)
- denied_mask |= MAY_EXEC;
+ *request_mask = l_mode | link_mask;
-#undef RWXAZM
+ /* Link always requires 'l' on the link, a subset for user:other
+ * of the target's 'r', 'w', 'x', 'a', 'z', and 'm' permissions on
+ * the link, and if the link has 'x', an exact match of all the
+ * execute flags ('i', 'u', 'U', 'p', 'P').
+ */
+#define SUBSET_PERMS (AA_FILE_PERMS & ~AA_LINK_BITS)
+ denied_mask = ~l_mode & link_mask;
+ if (l_mode & SUBSET_PERMS) {
+ denied_mask |= (l_mode & SUBSET_PERMS) & ~t_mode;
+ if (denied_mask & AA_EXEC_BITS)
+ denied_mask |= l_mode & AA_ALL_EXEC_MODS;
+ else if (l_mode & AA_EXEC_BITS) {
+ if (l_mode & AA_USER_EXEC &&
+ (l_mode & AA_USER_EXEC_MODS) !=
+ (t_mode & AA_USER_EXEC_MODS))
+ denied_mask |= AA_USER_EXEC |
+ (l_mode & AA_USER_EXEC_MODS);
+ if (l_mode & AA_OTHER_EXEC &&
+ (l_mode & AA_OTHER_EXEC_MODS) !=
+ (t_mode & AA_OTHER_EXEC_MODS))
+ denied_mask |= AA_OTHER_EXEC |
+ (l_mode & AA_OTHER_EXEC_MODS);
+ }
+ } else
+ denied_mask |= t_mode | link_mask;
+#undef SUBSET_PERMS
return denied_mask;
}
@@ -173,7 +194,7 @@ static int aa_perm_dentry(struct aa_prof
char *buffer = NULL;
sa->name = aa_get_name(dentry, mnt, &buffer, check);
-
+ sa->request_mask <<= aa_inode_mode(dentry->d_inode);
if (IS_ERR(sa->name)) {
/*
* deleted files are given a pass on permission checks when
@@ -182,13 +203,13 @@ static int aa_perm_dentry(struct aa_prof
if (PTR_ERR(sa->name) == -ENOENT && (check & AA_CHECK_FD))
sa->denied_mask = 0;
else {
- sa->denied_mask = sa->requested_mask;
+ sa->denied_mask = sa->request_mask;
sa->error_code = PTR_ERR(sa->name);
}
sa->name = NULL;
} else
sa->denied_mask = aa_file_denied(profile, sa->name,
- sa->requested_mask);
+ sa->request_mask);
if (!sa->denied_mask)
sa->error_code = 0;
@@ -229,10 +250,10 @@ void free_default_namespace(void)
default_namespace = NULL;
}
-static void aa_audit_file_mask(struct audit_buffer *ab, const char *name,
- int mask)
+static void aa_audit_file_sub_mask(struct audit_buffer *ab, char *buffer,
+ int mask)
{
- char mask_str[10], *m = mask_str;
+ char *m = buffer;
if (mask & AA_EXEC_MMAP)
*m++ = 'm';
@@ -242,32 +263,58 @@ static void aa_audit_file_mask(struct au
*m++ = 'w';
else if (mask & MAY_APPEND)
*m++ = 'a';
- if (mask & (MAY_EXEC | AA_EXEC_MODIFIERS)) {
+ if (mask & MAY_EXEC) {
if (mask & AA_EXEC_UNSAFE) {
- if (mask & AA_EXEC_INHERIT)
- *m++ = 'i';
- if (mask & AA_EXEC_UNCONFINED)
+ switch(mask & AA_EXEC_MODIFIERS) {
+ case AA_EXEC_UNCONFINED:
*m++ = 'u';
- if (mask & AA_EXEC_PROFILE)
+ break;
+ case AA_EXEC_PIX:
+ *m++ = 'p';
+ /* fall through */
+ case AA_EXEC_INHERIT:
+ *m++ = 'i';
+ break;
+ case AA_EXEC_PROFILE:
*m++ = 'p';
+ break;
+ }
} else {
- if (mask & AA_EXEC_INHERIT)
- *m++ = 'I';
- if (mask & AA_EXEC_UNCONFINED)
+ switch(mask & AA_EXEC_MODIFIERS) {
+ case AA_EXEC_UNCONFINED:
*m++ = 'U';
- if (mask & AA_EXEC_PROFILE)
+ break;
+ case AA_EXEC_PIX:
*m++ = 'P';
+ /* fall through */
+ case AA_EXEC_INHERIT:
+ *m++ = 'I';
+ break;
+ case AA_EXEC_PROFILE:
+ *m++ = 'P';
+ break;
+ }
}
- if (mask & MAY_EXEC)
- *m++ = 'x';
+ *m++ = 'x';
}
if (mask & AA_MAY_LINK)
*m++ = 'l';
if (mask & AA_MAY_LOCK)
*m++ = 'k';
*m++ = '\0';
+}
+
+static void aa_audit_file_mask(struct audit_buffer *ab, const char *name,
+ int mask)
+{
+ char user[10], other[10];
- audit_log_format(ab, " %s=\"%s\"", name, mask_str);
+ aa_audit_file_sub_mask(ab, user,
+ (mask & AA_USER_PERMS) >> AA_USER_SHIFT);
+ aa_audit_file_sub_mask(ab, other,
+ (mask & AA_OTHER_PERMS) >> AA_OTHER_SHIFT);
+
+ audit_log_format(ab, " %s=\"%s::%s\"", name, user, other);
}
static const char *address_families[] = {
@@ -316,8 +363,8 @@ static int aa_audit_base(struct aa_profi
if (sa->info)
audit_log_format(ab, " info=\"%s\"", sa->info);
- if (sa->requested_mask)
- aa_audit_file_mask(ab, "requested_mask", sa->requested_mask);
+ if (sa->request_mask)
+ aa_audit_file_mask(ab, "request_mask", sa->request_mask);
if (sa->denied_mask)
aa_audit_file_mask(ab, "denied_mask", sa->denied_mask);
@@ -472,7 +519,7 @@ int aa_attr(struct aa_profile *profile,
sa.operation = "setattr";
sa.gfp_mask = GFP_KERNEL;
sa.iattr = iattr;
- sa.requested_mask = MAY_WRITE;
+ sa.request_mask = MAY_WRITE;
sa.error_code = -EACCES;
check = 0;
@@ -506,7 +553,7 @@ int aa_perm_xattr(struct aa_profile *pro
memset(&sa, 0, sizeof(sa));
sa.operation = operation;
sa.gfp_mask = GFP_KERNEL;
- sa.requested_mask = mask;
+ sa.request_mask = mask;
sa.error_code = -EACCES;
if (inode && S_ISDIR(inode->i_mode))
@@ -540,7 +587,7 @@ int aa_perm(struct aa_profile *profile,
memset(&sa, 0, sizeof(sa));
sa.operation = operation;
sa.gfp_mask = GFP_KERNEL;
- sa.requested_mask = mask;
+ sa.request_mask = mask;
sa.error_code = -EACCES;
error = aa_perm_dentry(profile, dentry, mnt, &sa, check);
@@ -569,24 +616,28 @@ int aa_perm_dir(struct aa_profile *profi
memset(&sa, 0, sizeof(sa));
sa.operation = operation;
sa.gfp_mask = GFP_KERNEL;
- sa.requested_mask = mask;
+ sa.request_mask = mask;
sa.error_code = -EACCES;
return aa_perm_dentry(profile, dentry, mnt, &sa, AA_CHECK_DIR);
}
int aa_perm_path(struct aa_profile *profile, const char *operation,
- const char *name, int mask)
+ const char *name, int mask, uid_t uid)
{
struct aa_audit sa;
memset(&sa, 0, sizeof(sa));
sa.operation = operation;
sa.gfp_mask = GFP_KERNEL;
- sa.requested_mask = mask;
+ sa.request_mask = mask;
sa.name = name;
+ if (current->fsuid == uid)
+ sa.request_mask = mask << AA_USER_SHIFT;
+ else
+ sa.request_mask = mask << AA_OTHER_SHIFT;
- sa.denied_mask = aa_file_denied(profile, name, mask);
+ sa.denied_mask = aa_file_denied(profile, name, sa.request_mask) ;
sa.error_code = sa.denied_mask ? -EACCES : 0;
return aa_audit(profile, &sa);
@@ -672,9 +723,10 @@ int aa_link(struct aa_profile *profile,
}
if (sa.name && sa.name2) {
- sa.requested_mask = AA_MAY_LINK;
+ sa.request_mask = AA_MAY_LINK;
sa.denied_mask = aa_link_denied(profile, sa.name, sa.name2,
- &sa.requested_mask);
+ aa_inode_mode(target->d_inode),
+ &sa.request_mask);
sa.error_code = sa.denied_mask ? -EACCES : 0;
}
@@ -818,7 +870,7 @@ aa_register_find(struct aa_profile *prof
__FUNCTION__, new_profile->name);
} else if (mandatory && profile) {
sa->info = "mandatory profile missing";
- sa->denied_mask = MAY_EXEC;
+ sa->denied_mask = sa->request_mask; /* shifted MAY_EXEC */
if (complain) {
aa_audit_hint(profile, sa);
new_profile =
@@ -829,7 +881,7 @@ aa_register_find(struct aa_profile *prof
}
} else {
/* Only way we can get into this code is if task
- * is unconfined.
+ * is unconfined, or pix.
*/
AA_DEBUG("%s: No profile found for exec image '%s'\n",
__FUNCTION__,
@@ -851,7 +903,7 @@ int aa_register(struct linux_binprm *bpr
char *buffer = NULL;
struct file *filp = bprm->file;
struct aa_profile *profile, *old_profile, *new_profile = NULL;
- int exec_mode = AA_EXEC_UNSAFE, complain = 0;
+ int exec_mode, complain = 0, shift;
struct aa_audit sa;
AA_DEBUG("%s\n", __FUNCTION__);
@@ -862,11 +914,14 @@ int aa_register(struct linux_binprm *bpr
return -ENOENT;
}
+ shift = aa_inode_mode(filp->f_dentry->d_inode);
+ exec_mode = AA_EXEC_UNSAFE << shift;
+
memset(&sa, 0, sizeof(sa));
sa.operation = "exec";
sa.gfp_mask = GFP_KERNEL;
sa.name = filename;
- sa.requested_mask = MAY_EXEC;
+ sa.request_mask = MAY_EXEC << shift;
repeat:
profile = aa_get_profile(current);
@@ -878,16 +933,16 @@ repeat:
*/
exec_mode = aa_match(profile->file_rules, filename);
- if (exec_mode & (MAY_EXEC | AA_EXEC_MODIFIERS)) {
- switch (exec_mode & (MAY_EXEC | AA_EXEC_MODIFIERS)) {
- case MAY_EXEC | AA_EXEC_INHERIT:
+ if (exec_mode & sa.request_mask) {
+ switch ((exec_mode >> shift) & AA_EXEC_MODIFIERS) {
+ case AA_EXEC_INHERIT:
AA_DEBUG("%s: INHERIT %s\n",
__FUNCTION__,
filename);
/* nothing to be done here */
goto cleanup;
- case MAY_EXEC | AA_EXEC_UNCONFINED:
+ case AA_EXEC_UNCONFINED:
AA_DEBUG("%s: UNCONFINED %s\n",
__FUNCTION__,
filename);
@@ -896,7 +951,7 @@ repeat:
new_profile = NULL;
break;
- case MAY_EXEC | AA_EXEC_PROFILE:
+ case AA_EXEC_PROFILE:
AA_DEBUG("%s: PROFILE %s\n",
__FUNCTION__,
filename);
@@ -905,6 +960,18 @@ repeat:
1, complain,
&sa);
break;
+ case AA_EXEC_PIX:
+ AA_DEBUG("%s: PROFILE %s\n",
+ __FUNCTION__,
+ filename);
+ new_profile = aa_register_find(profile,
+ filename,
+ 0, complain,
+ &sa);
+ if (!new_profile)
+ /* inherit - nothing to be done here */
+ goto cleanup;
+ break;
}
} else if (complain) {
@@ -914,9 +981,9 @@ repeat:
*/
new_profile =
aa_dup_profile(profile->ns->null_complain_profile);
- exec_mode |= AA_EXEC_UNSAFE;
+ exec_mode |= AA_EXEC_UNSAFE << shift;
} else {
- sa.denied_mask = MAY_EXEC;
+ sa.denied_mask = sa.request_mask;
aa_audit_reject(profile, &sa);
new_profile = ERR_PTR(-EPERM);
}
@@ -937,7 +1004,7 @@ repeat:
if (PTR_ERR(old_profile) == -ESTALE)
goto repeat;
if (PTR_ERR(old_profile) == -EPERM) {
- sa.denied_mask = MAY_EXEC;
+ sa.denied_mask = sa.request_mask;
sa.info = "unable to set profile due to ptrace";
sa.task = current->parent->pid;
aa_audit_reject(profile, &sa);
@@ -957,7 +1024,7 @@ repeat:
* Cases 2 and 3 are marked as requiring secure exec
* (unless policy specified "unsafe exec")
*/
- if (!(exec_mode & AA_EXEC_UNSAFE)) {
+ if (!(exec_mode & (AA_EXEC_UNSAFE << shift))) {
unsigned long bprm_flags;
bprm_flags = AA_SECURE_EXEC_NEEDED;
@@ -967,7 +1034,7 @@ repeat:
if (complain && new_profile &&
new_profile == new_profile->ns->null_complain_profile) {
- sa.requested_mask = 0;
+ sa.request_mask = 0;
sa.name = NULL;
sa.info = "set profile";
aa_audit_hint(new_profile, &sa);
--- a/security/apparmor/match.c
+++ b/security/apparmor/match.c
@@ -175,14 +175,8 @@ int verify_dfa(struct aa_dfa *dfa)
for (i = 0; i < state_count; i++) {
int mode = ACCEPT_TABLE(dfa)[i];
- if (mode & ~AA_VALID_PERM_MASK)
+ if (mode & ~AA_VALID_PERM_MASK) {
goto out;
-
- /* if MAY_EXEC, exactly one exec modifier must be set */
- if (mode & MAY_EXEC) {
- mode &= AA_EXEC_MODIFIERS;
- if (mode & (mode - 1))
- goto out;
}
}
--- a/security/apparmor/module_interface.c
+++ b/security/apparmor/module_interface.c
@@ -349,7 +349,8 @@ fail:
sa.operation = operation;
sa.gfp_mask = GFP_KERNEL;
sa.name = profile && profile->name ? profile->name : "unknown";
- sa.info = "failed to unpack profile";
+ if (!sa.info)
+ sa.info = "failed to unpack profile";
aa_audit_status(NULL, &sa);
if (profile)

View file

@ -1,24 +0,0 @@
From: Andreas Gruenbacher <agruen@suse.de>
Subject: Allow permission functions to tell between parent and leaf checks
Set the LOOKUP_CONTINUE flag when checking parent permissions. This allows
permission functions to tell between parent and leaf checks.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
fs/namei.c | 2 ++
1 file changed, 2 insertions(+)
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1508,6 +1508,8 @@ static inline int may_create(struct inod
return -EEXIST;
if (IS_DEADDIR(dir))
return -ENOENT;
+ if (nd)
+ nd->flags |= LOOKUP_CONTINUE;
return permission(dir,MAY_WRITE | MAY_EXEC, nd);
}

View file

@ -1,129 +0,0 @@
From: Andreas Gruenbacher <agruen@suse.de>
Subject: Filter out disconnected paths from /proc/mounts
Use d_path() instead of seq_path when generating /proc/mounts and
/proc/$id/mountstats, reuse the same buffer for all mounts, and filter out
disconnected paths.
This path has no net effect in itself because d_path() so far doesn't
distinguish sconnected and disconnected paths yet. The next patch fixes that
though; without this patch, the next patch would break /proc/mounts and
/proc/$id/mountstats.
There is some disagreement what /proc/mounts should include. Currently it
reports all mounts from the current namespace and doesn't include lazy
unmounts. This leads to ambiguities with the rootfs (which is an internal mount
irrelevant to user-space except in the initrd), and in chroots.
With this and the next patch, /proc/mounts only reports the mounts reachable
for the current process, which makes a lot more sense IMO. If the current
process is rooted in the namespace root (which it usually is), it will see all
mounts except for the rootfs.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
---
fs/namespace.c | 23 +++++++++++++++++++++--
fs/proc/base.c | 10 +++++++++-
2 files changed, 30 insertions(+), 3 deletions(-)
--- 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 {
@@ -371,10 +379,15 @@ static int show_vfsmnt(struct seq_file *
{ 0, NULL }
};
struct proc_fs_info *fs_infop;
+ char *path;
+
+ 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,8 +414,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;
+
+ 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) {
@@ -413,7 +432,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 */
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -354,8 +354,11 @@ static const struct inode_operations pro
};
extern struct seq_operations mounts_op;
+
+/* Keep in sync with fs/namespace.c! */
struct proc_mounts {
struct seq_file m;
+ void *page;
int event;
};
@@ -383,12 +386,16 @@ static int __mounts_open(struct inode *i
p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL);
if (p) {
file->private_data = &p->m;
- ret = seq_open(file, seq_ops);
+ 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);
@@ -407,6 +414,7 @@ static int mounts_release(struct inode *
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);
}

View file

@ -1,98 +0,0 @@
From: Andreas Gruenbacher <agruen@suse.de>
Subject: Remove duplicate proc code
Remove some duplicate code in generating the contents of /proc/mounts and
/proc/$pid/mountstats.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
---
This patch is optional, and does not affect the rest of this series.
fs/proc/base.c | 45 +++++++++++++++------------------------------
1 file changed, 15 insertions(+), 30 deletions(-)
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -359,7 +359,8 @@ struct proc_mounts {
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;
@@ -382,7 +383,7 @@ 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);
+ ret = seq_open(file, seq_ops);
if (!ret) {
p->m.private = ns;
p->event = ns->event;
@@ -395,17 +396,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;
+
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;
@@ -432,31 +441,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 = {

File diff suppressed because it is too large Load diff

View file

@ -1,144 +0,0 @@
From: Andreas Gruenbacher <agruen@suse.de>
Subject: Pass struct path down to remove_suid and children
Required by a later patch that adds a struct vfsmount parameter to
notify_change().
Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
fs/ntfs/file.c | 2 +-
fs/splice.c | 4 ++--
fs/xfs/linux-2.6/xfs_lrw.c | 2 +-
include/linux/fs.h | 4 ++--
mm/filemap.c | 16 ++++++++--------
mm/filemap_xip.c | 2 +-
mm/shmem.c | 2 +-
7 files changed, 16 insertions(+), 16 deletions(-)
--- a/fs/ntfs/file.c
+++ b/fs/ntfs/file.c
@@ -2120,7 +2120,7 @@ static ssize_t ntfs_file_aio_write_noloc
goto out;
if (!count)
goto out;
- err = remove_suid(file->f_path.dentry);
+ err = remove_suid(&file->f_path);
if (err)
goto out;
file_update_time(file);
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -775,7 +775,7 @@ generic_file_splice_write_nolock(struct
ssize_t ret;
int err;
- err = remove_suid(out->f_path.dentry);
+ err = remove_suid(&out->f_path);
if (unlikely(err))
return err;
@@ -835,7 +835,7 @@ generic_file_splice_write(struct pipe_in
if (killpriv)
err = security_inode_killpriv(out->f_path.dentry);
if (!err && killsuid)
- err = __remove_suid(out->f_path.dentry, killsuid);
+ err = __remove_suid(&out->f_path, killsuid);
mutex_unlock(&inode->i_mutex);
if (err)
return err;
--- a/fs/xfs/linux-2.6/xfs_lrw.c
+++ b/fs/xfs/linux-2.6/xfs_lrw.c
@@ -727,7 +727,7 @@ start:
!capable(CAP_FSETID)) {
error = xfs_write_clear_setuid(xip);
if (likely(!error))
- error = -remove_suid(file->f_path.dentry);
+ error = -remove_suid(&file->f_path);
if (unlikely(error)) {
goto out_unlock_internal;
}
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1766,9 +1766,9 @@ extern void __iget(struct inode * inode)
extern void clear_inode(struct inode *);
extern void destroy_inode(struct inode *);
extern struct inode *new_inode(struct super_block *);
-extern int __remove_suid(struct dentry *, int);
+extern int __remove_suid(struct path *, int);
extern int should_remove_suid(struct dentry *);
-extern int remove_suid(struct dentry *);
+extern int remove_suid(struct path *);
extern void __insert_inode_hash(struct inode *, unsigned long hashval);
extern void remove_inode_hash(struct inode *);
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1610,26 +1610,26 @@ int should_remove_suid(struct dentry *de
}
EXPORT_SYMBOL(should_remove_suid);
-int __remove_suid(struct dentry *dentry, int kill)
+int __remove_suid(struct path *path, int kill)
{
struct iattr newattrs;
newattrs.ia_valid = ATTR_FORCE | kill;
- return notify_change(dentry, &newattrs);
+ return notify_change(path->dentry, &newattrs);
}
-int remove_suid(struct dentry *dentry)
+int remove_suid(struct path *path)
{
- int killsuid = should_remove_suid(dentry);
- int killpriv = security_inode_need_killpriv(dentry);
+ int killsuid = should_remove_suid(path->dentry);
+ int killpriv = security_inode_need_killpriv(path->dentry);
int error = 0;
if (killpriv < 0)
return killpriv;
if (killpriv)
- error = security_inode_killpriv(dentry);
+ error = security_inode_killpriv(path->dentry);
if (!error && killsuid)
- error = __remove_suid(dentry, killsuid);
+ error = __remove_suid(path, killsuid);
return error;
}
@@ -2342,7 +2342,7 @@ __generic_file_aio_write_nolock(struct k
if (count == 0)
goto out;
- err = remove_suid(file->f_path.dentry);
+ err = remove_suid(&file->f_path);
if (err)
goto out;
--- a/mm/filemap_xip.c
+++ b/mm/filemap_xip.c
@@ -378,7 +378,7 @@ xip_file_write(struct file *filp, const
if (count == 0)
goto out_backing;
- ret = remove_suid(filp->f_path.dentry);
+ ret = remove_suid(&filp->f_path);
if (ret)
goto out_backing;
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1525,7 +1525,7 @@ shmem_file_write(struct file *file, cons
if (err || !count)
goto out;
- err = remove_suid(file->f_path.dentry);
+ err = remove_suid(&file->f_path);
if (err)
goto out;

View file

@ -1,107 +0,0 @@
From: Tony Jones <tonyj@suse.de>
Subject: Pass struct vfsmount to the inode_create LSM hook
This is needed for computing pathnames in the AppArmor LSM.
Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
fs/namei.c | 2 +-
include/linux/security.h | 9 ++++++---
security/dummy.c | 2 +-
security/security.c | 5 +++--
security/selinux/hooks.c | 3 ++-
5 files changed, 13 insertions(+), 8 deletions(-)
--- a/fs/namei.c 2007-11-02 17:44:43.000000000 -0400
+++ b/fs/namei.c 2007-11-02 17:49:23.000000000 -0400
@@ -1583,7 +1583,7 @@ int vfs_create(struct inode *dir, struct
return -EACCES; /* shouldn't it be ENOSYS? */
mode &= S_IALLUGO;
mode |= S_IFREG;
- error = security_inode_create(dir, dentry, mode);
+ error = security_inode_create(dir, dentry, nd ? nd->mnt : NULL, mode);
if (error)
return error;
DQUOT_INIT(dir);
--- a/include/linux/security.h 2007-11-02 17:44:43.000000000 -0400
+++ b/include/linux/security.h 2007-11-02 17:49:39.000000000 -0400
@@ -297,6 +297,7 @@ struct request_sock;
* Check permission to create a regular file.
* @dir contains inode structure of the parent of the new file.
* @dentry contains the dentry structure for the file to be created.
+ * @mnt is the vfsmount corresponding to @dentry (may be NULL).
* @mode contains the file mode of the file to be created.
* Return 0 if permission is granted.
* @inode_link:
@@ -1247,8 +1248,8 @@ struct security_operations {
void (*inode_free_security) (struct inode *inode);
int (*inode_init_security) (struct inode *inode, struct inode *dir,
char **name, void **value, size_t *len);
- int (*inode_create) (struct inode *dir,
- struct dentry *dentry, int mode);
+ int (*inode_create) (struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt, int mode);
int (*inode_link) (struct dentry *old_dentry,
struct inode *dir, struct dentry *new_dentry);
int (*inode_unlink) (struct inode *dir, struct dentry *dentry);
@@ -1503,7 +1504,8 @@ int security_inode_alloc(struct inode *i
void security_inode_free(struct inode *inode);
int security_inode_init_security(struct inode *inode, struct inode *dir,
char **name, void **value, size_t *len);
-int security_inode_create(struct inode *dir, struct dentry *dentry, int mode);
+int security_inode_create(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt, int mode);
int security_inode_link(struct dentry *old_dentry, struct inode *dir,
struct dentry *new_dentry);
int security_inode_unlink(struct inode *dir, struct dentry *dentry);
@@ -1813,6 +1815,7 @@ static inline int security_inode_init_se
static inline int security_inode_create (struct inode *dir,
struct dentry *dentry,
+ struct vfsmount *mnt,
int mode)
{
return 0;
--- a/security/dummy.c 2007-11-02 17:44:43.000000000 -0400
+++ b/security/dummy.c 2007-11-02 17:49:23.000000000 -0400
@@ -262,7 +262,7 @@ static int dummy_inode_init_security (st
}
static int dummy_inode_create (struct inode *inode, struct dentry *dentry,
- int mask)
+ struct vfsmount *mnt, int mask)
{
return 0;
}
--- a/security/security.c 2007-11-02 17:46:44.000000000 -0400
+++ b/security/security.c 2007-11-02 17:49:23.000000000 -0400
@@ -329,11 +329,12 @@ int security_inode_init_security(struct
}
EXPORT_SYMBOL(security_inode_init_security);
-int security_inode_create(struct inode *dir, struct dentry *dentry, int mode)
+int security_inode_create(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt, int mode)
{
if (unlikely(IS_PRIVATE(dir)))
return 0;
- return security_ops->inode_create(dir, dentry, mode);
+ return security_ops->inode_create(dir, dentry, mnt, mode);
}
int security_inode_link(struct dentry *old_dentry, struct inode *dir,
--- a/security/selinux/hooks.c 2007-11-02 17:44:43.000000000 -0400
+++ b/security/selinux/hooks.c 2007-11-02 17:49:23.000000000 -0400
@@ -2184,7 +2184,8 @@ static int selinux_inode_init_security(s
return 0;
}
-static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int mask)
+static int selinux_inode_create(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt, int mask)
{
return may_create(dir, dentry, SECCLASS_FILE);
}

View file

@ -1,110 +0,0 @@
From: Tony Jones <tonyj@suse.de>
Subject: Pass struct vfsmount to the inode_getxattr LSM hook
This is needed for computing pathnames in the AppArmor LSM.
Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
fs/xattr.c | 2 +-
include/linux/security.h | 11 +++++++----
security/dummy.c | 3 ++-
security/security.c | 5 +++--
security/selinux/hooks.c | 3 ++-
5 files changed, 15 insertions(+), 9 deletions(-)
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -115,7 +115,7 @@ vfs_getxattr(struct dentry *dentry, stru
if (error)
return error;
- error = security_inode_getxattr(dentry, name);
+ error = security_inode_getxattr(dentry, mnt, name);
if (error)
return error;
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -405,7 +405,7 @@ struct request_sock;
* @value identified by @name for @dentry and @mnt.
* @inode_getxattr:
* Check permission before obtaining the extended attributes
- * identified by @name for @dentry.
+ * identified by @name for @dentry and @mnt.
* Return 0 if permission is granted.
* @inode_listxattr:
* Check permission before obtaining the list of extended attribute
@@ -1291,7 +1291,8 @@ struct security_operations {
struct vfsmount *mnt,
char *name, void *value,
size_t size, int flags);
- int (*inode_getxattr) (struct dentry *dentry, char *name);
+ int (*inode_getxattr) (struct dentry *dentry, struct vfsmount *mnt,
+ char *name);
int (*inode_listxattr) (struct dentry *dentry);
int (*inode_removexattr) (struct dentry *dentry, char *name);
int (*inode_need_killpriv) (struct dentry *dentry);
@@ -1554,7 +1555,8 @@ int security_inode_setxattr(struct dentr
void security_inode_post_setxattr(struct dentry *dentry, struct vfsmount *mnt,
char *name, void *value, size_t size,
int flags);
-int security_inode_getxattr(struct dentry *dentry, char *name);
+int security_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
+ char *name);
int security_inode_listxattr(struct dentry *dentry);
int security_inode_removexattr(struct dentry *dentry, char *name);
int security_inode_need_killpriv(struct dentry *dentry);
@@ -1954,7 +1956,8 @@ static inline void security_inode_post_s
int flags)
{ }
-static inline int security_inode_getxattr (struct dentry *dentry, char *name)
+static inline int security_inode_getxattr (struct dentry *dentry,
+ struct vfsmount *mnt, char *name)
{
return 0;
}
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -365,7 +365,8 @@ static void dummy_inode_post_setxattr (s
{
}
-static int dummy_inode_getxattr (struct dentry *dentry, char *name)
+static int dummy_inode_getxattr (struct dentry *dentry,
+ struct vfsmount *mnt, char *name)
{
return 0;
}
--- a/security/security.c
+++ b/security/security.c
@@ -458,11 +458,12 @@ void security_inode_post_setxattr(struct
security_ops->inode_post_setxattr(dentry, mnt, name, value, size, flags);
}
-int security_inode_getxattr(struct dentry *dentry, char *name)
+int security_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
+ char *name)
{
if (unlikely(IS_PRIVATE(dentry->d_inode)))
return 0;
- return security_ops->inode_getxattr(dentry, name);
+ return security_ops->inode_getxattr(dentry, mnt, name);
}
int security_inode_listxattr(struct dentry *dentry)
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2409,7 +2409,8 @@ static void selinux_inode_post_setxattr(
return;
}
-static int selinux_inode_getxattr (struct dentry *dentry, char *name)
+static int selinux_inode_getxattr (struct dentry *dentry, struct vfsmount *mnt,
+ char *name)
{
return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
}

View file

@ -1,134 +0,0 @@
From: Tony Jones <tonyj@suse.de>
Subject: Pass the struct vfsmounts to the inode_link LSM hook
This is needed for computing pathnames in the AppArmor LSM.
Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
fs/namei.c | 3 ++-
include/linux/security.h | 16 +++++++++++-----
security/dummy.c | 6 ++++--
security/security.c | 8 +++++---
security/selinux/hooks.c | 9 +++++++--
5 files changed, 29 insertions(+), 13 deletions(-)
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2356,7 +2356,8 @@ int vfs_link(struct dentry *old_dentry,
if (S_ISDIR(old_dentry->d_inode->i_mode))
return -EPERM;
- error = security_inode_link(old_dentry, dir, new_dentry);
+ error = security_inode_link(old_dentry, old_mnt, dir, new_dentry,
+ new_mnt);
if (error)
return error;
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -303,8 +303,10 @@ struct request_sock;
* @inode_link:
* Check permission before creating a new hard link to a file.
* @old_dentry contains the dentry structure for an existing link to the file.
+ * @old_mnt is the vfsmount corresponding to @old_dentry (may be NULL).
* @dir contains the inode structure of the parent directory of the new link.
* @new_dentry contains the dentry structure for the new link.
+ * @new_mnt is the vfsmount corresponding to @new_dentry (may be NULL).
* Return 0 if permission is granted.
* @inode_unlink:
* Check the permission to remove a hard link to a file.
@@ -1255,8 +1257,9 @@ struct security_operations {
char **name, void **value, size_t *len);
int (*inode_create) (struct inode *dir, struct dentry *dentry,
struct vfsmount *mnt, int mode);
- int (*inode_link) (struct dentry *old_dentry,
- struct inode *dir, struct dentry *new_dentry);
+ int (*inode_link) (struct dentry *old_dentry, struct vfsmount *old_mnt,
+ struct inode *dir, struct dentry *new_dentry,
+ struct vfsmount *new_mnt);
int (*inode_unlink) (struct inode *dir, struct dentry *dentry);
int (*inode_symlink) (struct inode *dir, struct dentry *dentry,
struct vfsmount *mnt, const char *old_name);
@@ -1513,8 +1516,9 @@ int security_inode_init_security(struct
char **name, void **value, size_t *len);
int security_inode_create(struct inode *dir, struct dentry *dentry,
struct vfsmount *mnt, int mode);
-int security_inode_link(struct dentry *old_dentry, struct inode *dir,
- struct dentry *new_dentry);
+int security_inode_link(struct dentry *old_dentry, struct vfsmount *old_mnt,
+ struct inode *dir, struct dentry *new_dentry,
+ struct vfsmount *new_mnt);
int security_inode_unlink(struct inode *dir, struct dentry *dentry);
int security_inode_symlink(struct inode *dir, struct dentry *dentry,
struct vfsmount *mnt, const char *old_name);
@@ -1832,8 +1836,10 @@ static inline int security_inode_create
}
static inline int security_inode_link (struct dentry *old_dentry,
+ struct vfsmount *old_mnt,
struct inode *dir,
- struct dentry *new_dentry)
+ struct dentry *new_dentry,
+ struct vfsmount *new_mnt)
{
return 0;
}
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -267,8 +267,10 @@ static int dummy_inode_create (struct in
return 0;
}
-static int dummy_inode_link (struct dentry *old_dentry, struct inode *inode,
- struct dentry *new_dentry)
+static int dummy_inode_link (struct dentry *old_dentry,
+ struct vfsmount *old_mnt, struct inode *inode,
+ struct dentry *new_dentry,
+ struct vfsmount *new_mnt)
{
return 0;
}
--- a/security/security.c
+++ b/security/security.c
@@ -336,12 +336,14 @@ int security_inode_create(struct inode *
return security_ops->inode_create(dir, dentry, mnt, mode);
}
-int security_inode_link(struct dentry *old_dentry, struct inode *dir,
- struct dentry *new_dentry)
+int security_inode_link(struct dentry *old_dentry, struct vfsmount *old_mnt,
+ struct inode *dir, struct dentry *new_dentry,
+ struct vfsmount *new_mnt)
{
if (unlikely(IS_PRIVATE(old_dentry->d_inode)))
return 0;
- return security_ops->inode_link(old_dentry, dir, new_dentry);
+ return security_ops->inode_link(old_dentry, old_mnt, dir,
+ new_dentry, new_mnt);
}
int security_inode_unlink(struct inode *dir, struct dentry *dentry)
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2190,11 +2190,16 @@ static int selinux_inode_create(struct i
return may_create(dir, dentry, SECCLASS_FILE);
}
-static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
+static int selinux_inode_link(struct dentry *old_dentry,
+ struct vfsmount *old_mnt,
+ struct inode *dir,
+ struct dentry *new_dentry,
+ struct vfsmount *new_mnt)
{
int rc;
- rc = secondary_ops->inode_link(old_dentry,dir,new_dentry);
+ rc = secondary_ops->inode_link(old_dentry, old_mnt, dir, new_dentry,
+ new_mnt);
if (rc)
return rc;
return may_link(dir, old_dentry, MAY_LINK);

View file

@ -1,105 +0,0 @@
From: Tony Jones <tonyj@suse.de>
Subject: Pass struct vfsmount to the inode_listxattr LSM hook
This is needed for computing pathnames in the AppArmor LSM.
Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
fs/xattr.c | 2 +-
include/linux/security.h | 9 +++++----
security/dummy.c | 2 +-
security/security.c | 4 ++--
security/selinux/hooks.c | 2 +-
5 files changed, 10 insertions(+), 9 deletions(-)
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -148,7 +148,7 @@ vfs_listxattr(struct dentry *dentry, str
struct inode *inode = dentry->d_inode;
ssize_t error;
- error = security_inode_listxattr(dentry);
+ error = security_inode_listxattr(dentry, mnt);
if (error)
return error;
error = -EOPNOTSUPP;
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -409,7 +409,7 @@ struct request_sock;
* Return 0 if permission is granted.
* @inode_listxattr:
* Check permission before obtaining the list of extended attribute
- * names for @dentry.
+ * names for @dentry and @mnt.
* Return 0 if permission is granted.
* @inode_removexattr:
* Check permission before removing the extended attribute
@@ -1293,7 +1293,7 @@ struct security_operations {
size_t size, int flags);
int (*inode_getxattr) (struct dentry *dentry, struct vfsmount *mnt,
char *name);
- int (*inode_listxattr) (struct dentry *dentry);
+ int (*inode_listxattr) (struct dentry *dentry, struct vfsmount *mnt);
int (*inode_removexattr) (struct dentry *dentry, char *name);
int (*inode_need_killpriv) (struct dentry *dentry);
int (*inode_killpriv) (struct dentry *dentry);
@@ -1557,7 +1557,7 @@ void security_inode_post_setxattr(struct
int flags);
int security_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
char *name);
-int security_inode_listxattr(struct dentry *dentry);
+int security_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt);
int security_inode_removexattr(struct dentry *dentry, char *name);
int security_inode_need_killpriv(struct dentry *dentry);
int security_inode_killpriv(struct dentry *dentry);
@@ -1962,7 +1962,8 @@ static inline int security_inode_getxatt
return 0;
}
-static inline int security_inode_listxattr (struct dentry *dentry)
+static inline int security_inode_listxattr (struct dentry *dentry,
+ struct vfsmount *mnt)
{
return 0;
}
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -371,7 +371,7 @@ static int dummy_inode_getxattr (struct
return 0;
}
-static int dummy_inode_listxattr (struct dentry *dentry)
+static int dummy_inode_listxattr (struct dentry *dentry, struct vfsmount *mnt)
{
return 0;
}
--- a/security/security.c
+++ b/security/security.c
@@ -466,11 +466,11 @@ int security_inode_getxattr(struct dentr
return security_ops->inode_getxattr(dentry, mnt, name);
}
-int security_inode_listxattr(struct dentry *dentry)
+int security_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt)
{
if (unlikely(IS_PRIVATE(dentry->d_inode)))
return 0;
- return security_ops->inode_listxattr(dentry);
+ return security_ops->inode_listxattr(dentry, mnt);
}
int security_inode_removexattr(struct dentry *dentry, char *name)
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2415,7 +2415,7 @@ static int selinux_inode_getxattr (struc
return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
}
-static int selinux_inode_listxattr (struct dentry *dentry)
+static int selinux_inode_listxattr (struct dentry *dentry, struct vfsmount *mnt)
{
return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
}

View file

@ -1,106 +0,0 @@
From: Tony Jones <tonyj@suse.de>
Subject: Pass struct vfsmount to the inode_mkdir LSM hook
This is needed for computing pathnames in the AppArmor LSM.
Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
fs/namei.c | 2 +-
include/linux/security.h | 8 ++++++--
security/dummy.c | 2 +-
security/security.c | 5 +++--
security/selinux/hooks.c | 3 ++-
5 files changed, 13 insertions(+), 7 deletions(-)
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2009,7 +2009,7 @@ int vfs_mkdir(struct inode *dir, struct
return -EPERM;
mode &= (S_IRWXUGO|S_ISVTX);
- error = security_inode_mkdir(dir, dentry, mode);
+ error = security_inode_mkdir(dir, dentry, mnt, mode);
if (error)
return error;
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -322,6 +322,7 @@ struct request_sock;
* associated with inode strcture @dir.
* @dir containst the inode structure of parent of the directory to be created.
* @dentry contains the dentry structure of new directory.
+ * @mnt is the vfsmount corresponding to @dentry (may be NULL).
* @mode contains the mode of new directory.
* Return 0 if permission is granted.
* @inode_rmdir:
@@ -1256,7 +1257,8 @@ struct security_operations {
int (*inode_unlink) (struct inode *dir, struct dentry *dentry);
int (*inode_symlink) (struct inode *dir,
struct dentry *dentry, const char *old_name);
- int (*inode_mkdir) (struct inode *dir, struct dentry *dentry, int mode);
+ int (*inode_mkdir) (struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt, int mode);
int (*inode_rmdir) (struct inode *dir, struct dentry *dentry);
int (*inode_mknod) (struct inode *dir, struct dentry *dentry,
int mode, dev_t dev);
@@ -1513,7 +1515,8 @@ int security_inode_link(struct dentry *o
int security_inode_unlink(struct inode *dir, struct dentry *dentry);
int security_inode_symlink(struct inode *dir, struct dentry *dentry,
const char *old_name);
-int security_inode_mkdir(struct inode *dir, struct dentry *dentry, int mode);
+int security_inode_mkdir(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt, int mode);
int security_inode_rmdir(struct inode *dir, struct dentry *dentry);
int security_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev);
int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
@@ -1846,6 +1849,7 @@ static inline int security_inode_symlink
static inline int security_inode_mkdir (struct inode *dir,
struct dentry *dentry,
+ struct vfsmount *mnt,
int mode)
{
return 0;
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -285,7 +285,7 @@ static int dummy_inode_symlink (struct i
}
static int dummy_inode_mkdir (struct inode *inode, struct dentry *dentry,
- int mask)
+ struct vfsmount *mnt, int mask)
{
return 0;
}
--- a/security/security.c
+++ b/security/security.c
@@ -359,11 +359,12 @@ int security_inode_symlink(struct inode
return security_ops->inode_symlink(dir, dentry, old_name);
}
-int security_inode_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+int security_inode_mkdir(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt, int mode)
{
if (unlikely(IS_PRIVATE(dir)))
return 0;
- return security_ops->inode_mkdir(dir, dentry, mode);
+ return security_ops->inode_mkdir(dir, dentry, mnt, mode);
}
int security_inode_rmdir(struct inode *dir, struct dentry *dentry)
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2215,7 +2215,8 @@ static int selinux_inode_symlink(struct
return may_create(dir, dentry, SECCLASS_LNK_FILE);
}
-static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, int mask)
+static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt, int mask)
{
return may_create(dir, dentry, SECCLASS_DIR);
}

View file

@ -1,110 +0,0 @@
From: Tony Jones <tonyj@suse.de>
Subject: Pass struct vfsmount to the inode_mknod LSM hook
This is needed for computing pathnames in the AppArmor LSM.
Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
fs/namei.c | 2 +-
include/linux/security.h | 7 +++++--
security/dummy.c | 2 +-
security/security.c | 5 +++--
security/selinux/hooks.c | 5 +++--
5 files changed, 13 insertions(+), 8 deletions(-)
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1932,7 +1932,7 @@ int vfs_mknod(struct inode *dir, struct
if (!dir->i_op || !dir->i_op->mknod)
return -EPERM;
- error = security_inode_mknod(dir, dentry, mode, dev);
+ error = security_inode_mknod(dir, dentry, mnt, mode, dev);
if (error)
return error;
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -337,6 +337,7 @@ struct request_sock;
* and not this hook.
* @dir contains the inode structure of parent of the new file.
* @dentry contains the dentry structure of the new file.
+ * @mnt is the vfsmount corresponding to @dentry (may be NULL).
* @mode contains the mode of the new file.
* @dev contains the device number.
* Return 0 if permission is granted.
@@ -1261,7 +1262,7 @@ struct security_operations {
struct vfsmount *mnt, int mode);
int (*inode_rmdir) (struct inode *dir, struct dentry *dentry);
int (*inode_mknod) (struct inode *dir, struct dentry *dentry,
- int mode, dev_t dev);
+ struct vfsmount *mnt, int mode, dev_t dev);
int (*inode_rename) (struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry);
int (*inode_readlink) (struct dentry *dentry);
@@ -1518,7 +1519,8 @@ int security_inode_symlink(struct inode
int security_inode_mkdir(struct inode *dir, struct dentry *dentry,
struct vfsmount *mnt, int mode);
int security_inode_rmdir(struct inode *dir, struct dentry *dentry);
-int security_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev);
+int security_inode_mknod(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt, int mode, dev_t dev);
int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry);
int security_inode_readlink(struct dentry *dentry);
@@ -1863,6 +1865,7 @@ static inline int security_inode_rmdir (
static inline int security_inode_mknod (struct inode *dir,
struct dentry *dentry,
+ struct vfsmount *mnt,
int mode, dev_t dev)
{
return 0;
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -296,7 +296,7 @@ static int dummy_inode_rmdir (struct ino
}
static int dummy_inode_mknod (struct inode *inode, struct dentry *dentry,
- int mode, dev_t dev)
+ struct vfsmount *mnt, int mode, dev_t dev)
{
return 0;
}
--- a/security/security.c
+++ b/security/security.c
@@ -374,11 +374,12 @@ int security_inode_rmdir(struct inode *d
return security_ops->inode_rmdir(dir, dentry);
}
-int security_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
+int security_inode_mknod(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt, int mode, dev_t dev)
{
if (unlikely(IS_PRIVATE(dir)))
return 0;
- return security_ops->inode_mknod(dir, dentry, mode, dev);
+ return security_ops->inode_mknod(dir, dentry, mnt, mode, dev);
}
int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2226,11 +2226,12 @@ static int selinux_inode_rmdir(struct in
return may_link(dir, dentry, MAY_RMDIR);
}
-static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
+static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt, int mode, dev_t dev)
{
int rc;
- rc = secondary_ops->inode_mknod(dir, dentry, mode, dev);
+ rc = secondary_ops->inode_mknod(dir, dentry, mnt, mode, dev);
if (rc)
return rc;

View file

@ -1,104 +0,0 @@
From: Tony Jones <tonyj@suse.de>
Subject: Pass struct vfsmount to the inode_readlink LSM hook
This is needed for computing pathnames in the AppArmor LSM.
Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
fs/stat.c | 2 +-
include/linux/security.h | 8 +++++---
security/dummy.c | 2 +-
security/security.c | 4 ++--
security/selinux/hooks.c | 2 +-
5 files changed, 10 insertions(+), 8 deletions(-)
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -306,7 +306,7 @@ asmlinkage long sys_readlinkat(int dfd,
error = -EINVAL;
if (inode->i_op && inode->i_op->readlink) {
- error = security_inode_readlink(nd.dentry);
+ error = security_inode_readlink(nd.dentry, nd.mnt);
if (!error) {
touch_atime(nd.mnt, nd.dentry);
error = inode->i_op->readlink(nd.dentry, buf, bufsiz);
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -352,6 +352,7 @@ struct request_sock;
* @inode_readlink:
* Check the permission to read the symbolic link.
* @dentry contains the dentry structure for the file link.
+ * @mnt is the vfsmount corresponding to @dentry (may be NULL).
* Return 0 if permission is granted.
* @inode_follow_link:
* Check permission to follow a symbolic link when looking up a pathname.
@@ -1266,7 +1267,7 @@ struct security_operations {
struct vfsmount *mnt, int mode, dev_t dev);
int (*inode_rename) (struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry);
- int (*inode_readlink) (struct dentry *dentry);
+ int (*inode_readlink) (struct dentry *dentry, struct vfsmount *mnt);
int (*inode_follow_link) (struct dentry *dentry, struct nameidata *nd);
int (*inode_permission) (struct inode *inode, int mask, struct nameidata *nd);
int (*inode_setattr) (struct dentry *dentry, struct vfsmount *mnt,
@@ -1524,7 +1525,7 @@ int security_inode_mknod(struct inode *d
struct vfsmount *mnt, int mode, dev_t dev);
int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry);
-int security_inode_readlink(struct dentry *dentry);
+int security_inode_readlink(struct dentry *dentry, struct vfsmount *mnt);
int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd);
int security_inode_permission(struct inode *inode, int mask, struct nameidata *nd);
int security_inode_setattr(struct dentry *dentry, struct vfsmount *mnt,
@@ -1881,7 +1882,8 @@ static inline int security_inode_rename
return 0;
}
-static inline int security_inode_readlink (struct dentry *dentry)
+static inline int security_inode_readlink(struct dentry *dentry,
+ struct vfsmount *mnt)
{
return 0;
}
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -309,7 +309,7 @@ static int dummy_inode_rename (struct in
return 0;
}
-static int dummy_inode_readlink (struct dentry *dentry)
+static int dummy_inode_readlink (struct dentry *dentry, struct vfsmount *mnt)
{
return 0;
}
--- a/security/security.c
+++ b/security/security.c
@@ -392,11 +392,11 @@ int security_inode_rename(struct inode *
new_dir, new_dentry);
}
-int security_inode_readlink(struct dentry *dentry)
+int security_inode_readlink(struct dentry *dentry, struct vfsmount *mnt)
{
if (unlikely(IS_PRIVATE(dentry->d_inode)))
return 0;
- return security_ops->inode_readlink(dentry);
+ return security_ops->inode_readlink(dentry, mnt);
}
int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd)
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2245,7 +2245,7 @@ static int selinux_inode_rename(struct i
return may_rename(old_inode, old_dentry, new_inode, new_dentry);
}
-static int selinux_inode_readlink(struct dentry *dentry)
+static int selinux_inode_readlink(struct dentry *dentry, struct vfsmount *mnt)
{
return dentry_has_perm(current, NULL, dentry, FILE__READ);
}

View file

@ -1,126 +0,0 @@
From: Tony Jones <tonyj@suse.de>
Subject: Pass struct vfsmount to the inode_removexattr LSM hook
This is needed for computing pathnames in the AppArmor LSM.
Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
fs/xattr.c | 2 +-
include/linux/security.h | 13 ++++++++-----
security/commoncap.c | 3 ++-
security/dummy.c | 3 ++-
security/security.c | 5 +++--
security/selinux/hooks.c | 3 ++-
6 files changed, 18 insertions(+), 11 deletions(-)
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -176,7 +176,7 @@ vfs_removexattr(struct dentry *dentry, s
if (error)
return error;
- error = security_inode_removexattr(dentry, name);
+ error = security_inode_removexattr(dentry, mnt, name);
if (error)
return error;
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -57,7 +57,7 @@ extern int cap_bprm_set_security (struct
extern void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe);
extern int cap_bprm_secureexec(struct linux_binprm *bprm);
extern int cap_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt, char *name, void *value, size_t size, int flags);
-extern int cap_inode_removexattr(struct dentry *dentry, char *name);
+extern int cap_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt, char *name);
extern int cap_inode_need_killpriv(struct dentry *dentry);
extern int cap_inode_killpriv(struct dentry *dentry);
extern int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid, int flags);
@@ -1294,7 +1294,8 @@ struct security_operations {
int (*inode_getxattr) (struct dentry *dentry, struct vfsmount *mnt,
char *name);
int (*inode_listxattr) (struct dentry *dentry, struct vfsmount *mnt);
- int (*inode_removexattr) (struct dentry *dentry, char *name);
+ int (*inode_removexattr) (struct dentry *dentry, struct vfsmount *mnt,
+ char *name);
int (*inode_need_killpriv) (struct dentry *dentry);
int (*inode_killpriv) (struct dentry *dentry);
int (*inode_getsecurity)(const struct inode *inode, const char *name, void *buffer, size_t size, int err);
@@ -1558,7 +1559,8 @@ void security_inode_post_setxattr(struct
int security_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
char *name);
int security_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt);
-int security_inode_removexattr(struct dentry *dentry, char *name);
+int security_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt,
+ char *name);
int security_inode_need_killpriv(struct dentry *dentry);
int security_inode_killpriv(struct dentry *dentry);
int security_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err);
@@ -1968,9 +1970,10 @@ static inline int security_inode_listxat
return 0;
}
-static inline int security_inode_removexattr (struct dentry *dentry, char *name)
+static inline int security_inode_removexattr (struct dentry *dentry,
+ struct vfsmount *mnt, char *name)
{
- return cap_inode_removexattr(dentry, name);
+ return cap_inode_removexattr(dentry, mnt, name);
}
static inline int security_inode_need_killpriv(struct dentry *dentry)
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -382,7 +382,8 @@ int cap_inode_setxattr(struct dentry *de
return 0;
}
-int cap_inode_removexattr(struct dentry *dentry, char *name)
+int cap_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt,
+ char *name)
{
if (!strcmp(name, XATTR_NAME_CAPS)) {
if (!capable(CAP_SETFCAP))
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -376,7 +376,8 @@ static int dummy_inode_listxattr (struct
return 0;
}
-static int dummy_inode_removexattr (struct dentry *dentry, char *name)
+static int dummy_inode_removexattr (struct dentry *dentry, struct vfsmount *mnt,
+ char *name)
{
if (!strncmp(name, XATTR_SECURITY_PREFIX,
sizeof(XATTR_SECURITY_PREFIX) - 1) &&
--- a/security/security.c
+++ b/security/security.c
@@ -473,11 +473,12 @@ int security_inode_listxattr(struct dent
return security_ops->inode_listxattr(dentry, mnt);
}
-int security_inode_removexattr(struct dentry *dentry, char *name)
+int security_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt,
+ char *name)
{
if (unlikely(IS_PRIVATE(dentry->d_inode)))
return 0;
- return security_ops->inode_removexattr(dentry, name);
+ return security_ops->inode_removexattr(dentry, mnt, name);
}
int security_inode_need_killpriv(struct dentry *dentry)
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2420,7 +2420,8 @@ static int selinux_inode_listxattr (stru
return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
}
-static int selinux_inode_removexattr (struct dentry *dentry, char *name)
+static int selinux_inode_removexattr (struct dentry *dentry,
+ struct vfsmount *mnt, char *name)
{
if (strcmp(name, XATTR_NAME_SELINUX))
return selinux_inode_setotherxattr(dentry, name);

View file

@ -1,136 +0,0 @@
From: Tony Jones <tonyj@suse.de>
Subject: Pass struct vfsmount to the inode_rename LSM hook
This is needed for computing pathnames in the AppArmor LSM.
Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
fs/namei.c | 6 ++++--
include/linux/security.h | 13 ++++++++++---
security/dummy.c | 4 +++-
security/security.c | 7 ++++---
security/selinux/hooks.c | 8 ++++++--
5 files changed, 27 insertions(+), 11 deletions(-)
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2480,7 +2480,8 @@ static int vfs_rename_dir(struct inode *
return error;
}
- error = security_inode_rename(old_dir, old_dentry, new_dir, new_dentry);
+ error = security_inode_rename(old_dir, old_dentry, old_mnt,
+ new_dir, new_dentry, new_mnt);
if (error)
return error;
@@ -2514,7 +2515,8 @@ static int vfs_rename_other(struct inode
struct inode *target;
int error;
- error = security_inode_rename(old_dir, old_dentry, new_dir, new_dentry);
+ error = security_inode_rename(old_dir, old_dentry, old_mnt,
+ new_dir, new_dentry, new_mnt);
if (error)
return error;
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -350,8 +350,10 @@ struct request_sock;
* Check for permission to rename a file or directory.
* @old_dir contains the inode structure for parent of the old link.
* @old_dentry contains the dentry structure of the old link.
+ * @old_mnt is the vfsmount corresponding to @old_dentry (may be NULL).
* @new_dir contains the inode structure for parent of the new link.
* @new_dentry contains the dentry structure of the new link.
+ * @new_mnt is the vfsmount corresponding to @new_dentry (may be NULL).
* Return 0 if permission is granted.
* @inode_readlink:
* Check the permission to read the symbolic link.
@@ -1273,7 +1275,9 @@ struct security_operations {
int (*inode_mknod) (struct inode *dir, struct dentry *dentry,
struct vfsmount *mnt, int mode, dev_t dev);
int (*inode_rename) (struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry);
+ struct vfsmount *old_mnt,
+ struct inode *new_dir, struct dentry *new_dentry,
+ struct vfsmount *new_mnt);
int (*inode_readlink) (struct dentry *dentry, struct vfsmount *mnt);
int (*inode_follow_link) (struct dentry *dentry, struct nameidata *nd);
int (*inode_permission) (struct inode *inode, int mask, struct nameidata *nd);
@@ -1534,7 +1538,8 @@ int security_inode_rmdir(struct inode *d
int security_inode_mknod(struct inode *dir, struct dentry *dentry,
struct vfsmount *mnt, int mode, dev_t dev);
int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry);
+ struct vfsmount *old_mnt, struct inode *new_dir,
+ struct dentry *new_dentry, struct vfsmount *new_mnt);
int security_inode_readlink(struct dentry *dentry, struct vfsmount *mnt);
int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd);
int security_inode_permission(struct inode *inode, int mask, struct nameidata *nd);
@@ -1890,8 +1895,10 @@ static inline int security_inode_mknod (
static inline int security_inode_rename (struct inode *old_dir,
struct dentry *old_dentry,
+ struct vfsmount *old_mnt,
struct inode *new_dir,
- struct dentry *new_dentry)
+ struct dentry *new_dentry,
+ struct vfsmount *new_mnt)
{
return 0;
}
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -307,8 +307,10 @@ static int dummy_inode_mknod (struct ino
static int dummy_inode_rename (struct inode *old_inode,
struct dentry *old_dentry,
+ struct vfsmount *old_mnt,
struct inode *new_inode,
- struct dentry *new_dentry)
+ struct dentry *new_dentry,
+ struct vfsmount *new_mnt)
{
return 0;
}
--- a/security/security.c
+++ b/security/security.c
@@ -387,13 +387,14 @@ int security_inode_mknod(struct inode *d
}
int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
- struct inode *new_dir, struct dentry *new_dentry)
+ struct vfsmount *old_mnt, struct inode *new_dir,
+ struct dentry *new_dentry, struct vfsmount *new_mnt)
{
if (unlikely(IS_PRIVATE(old_dentry->d_inode) ||
(new_dentry->d_inode && IS_PRIVATE(new_dentry->d_inode))))
return 0;
- return security_ops->inode_rename(old_dir, old_dentry,
- new_dir, new_dentry);
+ return security_ops->inode_rename(old_dir, old_dentry, old_mnt,
+ new_dir, new_dentry, new_mnt);
}
int security_inode_readlink(struct dentry *dentry, struct vfsmount *mnt)
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2246,8 +2246,12 @@ static int selinux_inode_mknod(struct in
return may_create(dir, dentry, inode_mode_to_security_class(mode));
}
-static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
- struct inode *new_inode, struct dentry *new_dentry)
+static int selinux_inode_rename(struct inode *old_inode,
+ struct dentry *old_dentry,
+ struct vfsmount *old_mnt,
+ struct inode *new_inode,
+ struct dentry *new_dentry,
+ struct vfsmount *new_mnt)
{
return may_rename(old_inode, old_dentry, new_inode, new_dentry);
}

View file

@ -1,109 +0,0 @@
From: Tony Jones <tonyj@suse.de>
Subject: Pass struct vfsmount to the inode_rmdir LSM hook
This is needed for computing pathnames in the AppArmor LSM.
Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
fs/namei.c | 2 +-
include/linux/security.h | 10 +++++++---
security/dummy.c | 3 ++-
security/security.c | 5 +++--
security/selinux/hooks.c | 3 ++-
5 files changed, 15 insertions(+), 8 deletions(-)
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2104,7 +2104,7 @@ int vfs_rmdir(struct inode *dir, struct
if (d_mountpoint(dentry))
error = -EBUSY;
else {
- error = security_inode_rmdir(dir, dentry);
+ error = security_inode_rmdir(dir, dentry, mnt);
if (!error) {
error = dir->i_op->rmdir(dir, dentry);
if (!error)
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -332,6 +332,7 @@ struct request_sock;
* Check the permission to remove a directory.
* @dir contains the inode structure of parent of the directory to be removed.
* @dentry contains the dentry structure of directory to be removed.
+ * @mnt is the vfsmount corresponding to @dentry (may be NULL).
* Return 0 if permission is granted.
* @inode_mknod:
* Check permissions when creating a special file (or a socket or a fifo
@@ -1265,7 +1266,8 @@ struct security_operations {
struct vfsmount *mnt, const char *old_name);
int (*inode_mkdir) (struct inode *dir, struct dentry *dentry,
struct vfsmount *mnt, int mode);
- int (*inode_rmdir) (struct inode *dir, struct dentry *dentry);
+ int (*inode_rmdir) (struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt);
int (*inode_mknod) (struct inode *dir, struct dentry *dentry,
struct vfsmount *mnt, int mode, dev_t dev);
int (*inode_rename) (struct inode *old_dir, struct dentry *old_dentry,
@@ -1524,7 +1526,8 @@ int security_inode_symlink(struct inode
struct vfsmount *mnt, const char *old_name);
int security_inode_mkdir(struct inode *dir, struct dentry *dentry,
struct vfsmount *mnt, int mode);
-int security_inode_rmdir(struct inode *dir, struct dentry *dentry);
+int security_inode_rmdir(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt);
int security_inode_mknod(struct inode *dir, struct dentry *dentry,
struct vfsmount *mnt, int mode, dev_t dev);
int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
@@ -1867,7 +1870,8 @@ static inline int security_inode_mkdir (
}
static inline int security_inode_rmdir (struct inode *dir,
- struct dentry *dentry)
+ struct dentry *dentry,
+ struct vfsmount *mnt)
{
return 0;
}
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -292,7 +292,8 @@ static int dummy_inode_mkdir (struct ino
return 0;
}
-static int dummy_inode_rmdir (struct inode *inode, struct dentry *dentry)
+static int dummy_inode_rmdir (struct inode *inode, struct dentry *dentry,
+ struct vfsmount *mnt)
{
return 0;
}
--- a/security/security.c
+++ b/security/security.c
@@ -369,11 +369,12 @@ int security_inode_mkdir(struct inode *d
return security_ops->inode_mkdir(dir, dentry, mnt, mode);
}
-int security_inode_rmdir(struct inode *dir, struct dentry *dentry)
+int security_inode_rmdir(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt)
{
if (unlikely(IS_PRIVATE(dentry->d_inode)))
return 0;
- return security_ops->inode_rmdir(dir, dentry);
+ return security_ops->inode_rmdir(dir, dentry, mnt);
}
int security_inode_mknod(struct inode *dir, struct dentry *dentry,
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2227,7 +2227,8 @@ static int selinux_inode_mkdir(struct in
return may_create(dir, dentry, SECCLASS_DIR);
}
-static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
+static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt)
{
return may_link(dir, dentry, MAY_RMDIR);
}

View file

@ -1,119 +0,0 @@
From: Tony Jones <tonyj@suse.de>
Subject: Pass struct vfsmount to the inode_setattr LSM hook
This is needed for computing pathnames in the AppArmor LSM.
Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
fs/attr.c | 4 ++--
include/linux/security.h | 8 ++++++--
security/dummy.c | 3 ++-
security/security.c | 5 +++--
security/selinux/hooks.c | 5 +++--
5 files changed, 16 insertions(+), 9 deletions(-)
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -159,13 +159,13 @@ int notify_change(struct dentry *dentry,
down_write(&dentry->d_inode->i_alloc_sem);
if (inode->i_op && inode->i_op->setattr) {
- error = security_inode_setattr(dentry, attr);
+ error = security_inode_setattr(dentry, mnt, attr);
if (!error)
error = inode->i_op->setattr(dentry, attr);
} else {
error = inode_change_ok(inode, attr);
if (!error)
- error = security_inode_setattr(dentry, attr);
+ error = security_inode_setattr(dentry, mnt, attr);
if (!error) {
if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
(ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid))
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -372,6 +372,7 @@ struct request_sock;
* file attributes change (such as when a file is truncated, chown/chmod
* operations, transferring disk quotas, etc).
* @dentry contains the dentry structure for the file.
+ * @mnt is the vfsmount corresponding to @dentry (may be NULL).
* @attr is the iattr structure containing the new file attributes.
* Return 0 if permission is granted.
* @inode_getattr:
@@ -1264,7 +1265,8 @@ struct security_operations {
int (*inode_readlink) (struct dentry *dentry);
int (*inode_follow_link) (struct dentry *dentry, struct nameidata *nd);
int (*inode_permission) (struct inode *inode, int mask, struct nameidata *nd);
- int (*inode_setattr) (struct dentry *dentry, struct iattr *attr);
+ int (*inode_setattr) (struct dentry *dentry, struct vfsmount *mnt,
+ struct iattr *attr);
int (*inode_getattr) (struct vfsmount *mnt, struct dentry *dentry);
void (*inode_delete) (struct inode *inode);
int (*inode_setxattr) (struct dentry *dentry, char *name, void *value,
@@ -1519,7 +1521,8 @@ int security_inode_rename(struct inode *
int security_inode_readlink(struct dentry *dentry);
int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd);
int security_inode_permission(struct inode *inode, int mask, struct nameidata *nd);
-int security_inode_setattr(struct dentry *dentry, struct iattr *attr);
+int security_inode_setattr(struct dentry *dentry, struct vfsmount *mnt,
+ struct iattr *attr);
int security_inode_getattr(struct vfsmount *mnt, struct dentry *dentry);
void security_inode_delete(struct inode *inode);
int security_inode_setxattr(struct dentry *dentry, char *name,
@@ -1887,6 +1890,7 @@ static inline int security_inode_permiss
}
static inline int security_inode_setattr (struct dentry *dentry,
+ struct vfsmount *mnt,
struct iattr *attr)
{
return 0;
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -325,7 +325,8 @@ static int dummy_inode_permission (struc
return 0;
}
-static int dummy_inode_setattr (struct dentry *dentry, struct iattr *iattr)
+static int dummy_inode_setattr (struct dentry *dentry, struct vfsmount *mnt,
+ struct iattr *iattr)
{
return 0;
}
--- a/security/security.c
+++ b/security/security.c
@@ -411,11 +411,12 @@ int security_inode_permission(struct ino
return security_ops->inode_permission(inode, mask, nd);
}
-int security_inode_setattr(struct dentry *dentry, struct iattr *attr)
+int security_inode_setattr(struct dentry *dentry, struct vfsmount *mnt,
+ struct iattr *attr)
{
if (unlikely(IS_PRIVATE(dentry->d_inode)))
return 0;
- return security_ops->inode_setattr(dentry, attr);
+ return security_ops->inode_setattr(dentry, mnt, attr);
}
int security_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2275,11 +2275,12 @@ static int selinux_inode_permission(stru
file_mask_to_av(inode->i_mode, mask), NULL);
}
-static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
+static int selinux_inode_setattr(struct dentry *dentry, struct vfsmount *mnt,
+ struct iattr *iattr)
{
int rc;
- rc = secondary_ops->inode_setattr(dentry, iattr);
+ rc = secondary_ops->inode_setattr(dentry, mnt, iattr);
if (rc)
return rc;

View file

@ -1,210 +0,0 @@
From: Tony Jones <tonyj@suse.de>
Subject: Pass struct vfsmount to the inode_setxattr LSM hook
This is needed for computing pathnames in the AppArmor LSM.
Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
fs/xattr.c | 4 ++--
include/linux/security.h | 35 +++++++++++++++++++++--------------
security/commoncap.c | 4 ++--
security/dummy.c | 9 ++++++---
security/security.c | 14 ++++++++------
security/selinux/hooks.c | 8 ++++++--
6 files changed, 45 insertions(+), 29 deletions(-)
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -79,7 +79,7 @@ vfs_setxattr(struct dentry *dentry, stru
return error;
mutex_lock(&inode->i_mutex);
- error = security_inode_setxattr(dentry, name, value, size, flags);
+ error = security_inode_setxattr(dentry, mnt, name, value, size, flags);
if (error)
goto out;
error = -EOPNOTSUPP;
@@ -87,7 +87,7 @@ vfs_setxattr(struct dentry *dentry, stru
error = inode->i_op->setxattr(dentry, name, value, size, flags);
if (!error) {
fsnotify_xattr(dentry);
- security_inode_post_setxattr(dentry, name, value,
+ security_inode_post_setxattr(dentry, mnt, name, value,
size, flags);
}
} else if (!strncmp(name, XATTR_SECURITY_PREFIX,
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -56,7 +56,7 @@ extern void cap_capset_set (struct task_
extern int cap_bprm_set_security (struct linux_binprm *bprm);
extern void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe);
extern int cap_bprm_secureexec(struct linux_binprm *bprm);
-extern int cap_inode_setxattr(struct dentry *dentry, char *name, void *value, size_t size, int flags);
+extern int cap_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt, char *name, void *value, size_t size, int flags);
extern int cap_inode_removexattr(struct dentry *dentry, char *name);
extern int cap_inode_need_killpriv(struct dentry *dentry);
extern int cap_inode_killpriv(struct dentry *dentry);
@@ -398,11 +398,11 @@ struct request_sock;
* inode.
* @inode_setxattr:
* Check permission before setting the extended attributes
- * @value identified by @name for @dentry.
+ * @value identified by @name for @dentry and @mnt.
* Return 0 if permission is granted.
* @inode_post_setxattr:
* Update inode security field after successful setxattr operation.
- * @value identified by @name for @dentry.
+ * @value identified by @name for @dentry and @mnt.
* @inode_getxattr:
* Check permission before obtaining the extended attributes
* identified by @name for @dentry.
@@ -1285,9 +1285,11 @@ struct security_operations {
struct iattr *attr);
int (*inode_getattr) (struct vfsmount *mnt, struct dentry *dentry);
void (*inode_delete) (struct inode *inode);
- int (*inode_setxattr) (struct dentry *dentry, char *name, void *value,
- size_t size, int flags);
- void (*inode_post_setxattr) (struct dentry *dentry, char *name, void *value,
+ int (*inode_setxattr) (struct dentry *dentry, struct vfsmount *mnt,
+ char *name, void *value, size_t size, int flags);
+ void (*inode_post_setxattr) (struct dentry *dentry,
+ struct vfsmount *mnt,
+ char *name, void *value,
size_t size, int flags);
int (*inode_getxattr) (struct dentry *dentry, char *name);
int (*inode_listxattr) (struct dentry *dentry);
@@ -1547,10 +1549,11 @@ int security_inode_setattr(struct dentry
struct iattr *attr);
int security_inode_getattr(struct vfsmount *mnt, struct dentry *dentry);
void security_inode_delete(struct inode *inode);
-int security_inode_setxattr(struct dentry *dentry, char *name,
- void *value, size_t size, int flags);
-void security_inode_post_setxattr(struct dentry *dentry, char *name,
- void *value, size_t size, int flags);
+int security_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
+ char *name, void *value, size_t size, int flags);
+void security_inode_post_setxattr(struct dentry *dentry, struct vfsmount *mnt,
+ char *name, void *value, size_t size,
+ int flags);
int security_inode_getxattr(struct dentry *dentry, char *name);
int security_inode_listxattr(struct dentry *dentry);
int security_inode_removexattr(struct dentry *dentry, char *name);
@@ -1937,14 +1940,18 @@ static inline int security_inode_getattr
static inline void security_inode_delete (struct inode *inode)
{ }
-static inline int security_inode_setxattr (struct dentry *dentry, char *name,
+static inline int security_inode_setxattr (struct dentry *dentry,
+ struct vfsmount *mnt, char *name,
void *value, size_t size, int flags)
{
- return cap_inode_setxattr(dentry, name, value, size, flags);
+ return cap_inode_setxattr(dentry, mnt, name, value, size, flags);
}
-static inline void security_inode_post_setxattr (struct dentry *dentry, char *name,
- void *value, size_t size, int flags)
+static inline void security_inode_post_setxattr (struct dentry *dentry,
+ struct vfsmount *mnt,
+ char *name,
+ void *value, size_t size,
+ int flags)
{ }
static inline int security_inode_getxattr (struct dentry *dentry, char *name)
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -368,8 +368,8 @@ int cap_bprm_secureexec (struct linux_bi
current->egid != current->gid);
}
-int cap_inode_setxattr(struct dentry *dentry, char *name, void *value,
- size_t size, int flags)
+int cap_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt, char *name,
+ void *value, size_t size, int flags)
{
if (!strcmp(name, XATTR_NAME_CAPS)) {
if (!capable(CAP_SETFCAP))
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -347,8 +347,9 @@ static void dummy_inode_delete (struct i
return;
}
-static int dummy_inode_setxattr (struct dentry *dentry, char *name, void *value,
- size_t size, int flags)
+static int dummy_inode_setxattr (struct dentry *dentry, struct vfsmount *mnt,
+ char *name, void *value, size_t size,
+ int flags)
{
if (!strncmp(name, XATTR_SECURITY_PREFIX,
sizeof(XATTR_SECURITY_PREFIX) - 1) &&
@@ -357,7 +358,9 @@ static int dummy_inode_setxattr (struct
return 0;
}
-static void dummy_inode_post_setxattr (struct dentry *dentry, char *name, void *value,
+static void dummy_inode_post_setxattr (struct dentry *dentry,
+ struct vfsmount *mnt,
+ char *name, void *value,
size_t size, int flags)
{
}
--- a/security/security.c
+++ b/security/security.c
@@ -440,20 +440,22 @@ void security_inode_delete(struct inode
security_ops->inode_delete(inode);
}
-int security_inode_setxattr(struct dentry *dentry, char *name,
- void *value, size_t size, int flags)
+int security_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
+ char *name, void *value, size_t size, int flags)
{
if (unlikely(IS_PRIVATE(dentry->d_inode)))
return 0;
- return security_ops->inode_setxattr(dentry, name, value, size, flags);
+ return security_ops->inode_setxattr(dentry, mnt, name, value, size,
+ flags);
}
-void security_inode_post_setxattr(struct dentry *dentry, char *name,
- void *value, size_t size, int flags)
+void security_inode_post_setxattr(struct dentry *dentry, struct vfsmount *mnt,
+ char *name, void *value, size_t size,
+ int flags)
{
if (unlikely(IS_PRIVATE(dentry->d_inode)))
return;
- security_ops->inode_post_setxattr(dentry, name, value, size, flags);
+ security_ops->inode_post_setxattr(dentry, mnt, name, value, size, flags);
}
int security_inode_getxattr(struct dentry *dentry, char *name)
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2332,7 +2332,9 @@ static int selinux_inode_setotherxattr(s
return dentry_has_perm(current, NULL, dentry, FILE__SETATTR);
}
-static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value, size_t size, int flags)
+static int selinux_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
+ char *name, void *value, size_t size,
+ int flags)
{
struct task_security_struct *tsec = current->security;
struct inode *inode = dentry->d_inode;
@@ -2381,7 +2383,9 @@ static int selinux_inode_setxattr(struct
&ad);
}
-static void selinux_inode_post_setxattr(struct dentry *dentry, char *name,
+static void selinux_inode_post_setxattr(struct dentry *dentry,
+ struct vfsmount *mnt,
+ char *name,
void *value, size_t size, int flags)
{
struct inode *inode = dentry->d_inode;

View file

@ -1,105 +0,0 @@
From: Tony Jones <tonyj@suse.de>
Subject: Pass struct vfsmount to the inode_symlink LSM hook
This is needed for computing pathnames in the AppArmor LSM.
Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
fs/namei.c | 2 +-
include/linux/security.h | 8 +++++---
security/dummy.c | 2 +-
security/security.c | 4 ++--
security/selinux/hooks.c | 3 ++-
5 files changed, 11 insertions(+), 8 deletions(-)
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2277,7 +2277,7 @@ int vfs_symlink(struct inode *dir, struc
if (!dir->i_op || !dir->i_op->symlink)
return -EPERM;
- error = security_inode_symlink(dir, dentry, oldname);
+ error = security_inode_symlink(dir, dentry, mnt, oldname);
if (error)
return error;
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -315,6 +315,7 @@ struct request_sock;
* Check the permission to create a symbolic link to a file.
* @dir contains the inode structure of parent directory of the symbolic link.
* @dentry contains the dentry structure of the symbolic link.
+ * @mnt is the vfsmount corresponding to @dentry (may be NULL).
* @old_name contains the pathname of file.
* Return 0 if permission is granted.
* @inode_mkdir:
@@ -1256,8 +1257,8 @@ struct security_operations {
int (*inode_link) (struct dentry *old_dentry,
struct inode *dir, struct dentry *new_dentry);
int (*inode_unlink) (struct inode *dir, struct dentry *dentry);
- int (*inode_symlink) (struct inode *dir,
- struct dentry *dentry, const char *old_name);
+ int (*inode_symlink) (struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt, const char *old_name);
int (*inode_mkdir) (struct inode *dir, struct dentry *dentry,
struct vfsmount *mnt, int mode);
int (*inode_rmdir) (struct inode *dir, struct dentry *dentry);
@@ -1515,7 +1516,7 @@ int security_inode_link(struct dentry *o
struct dentry *new_dentry);
int security_inode_unlink(struct inode *dir, struct dentry *dentry);
int security_inode_symlink(struct inode *dir, struct dentry *dentry,
- const char *old_name);
+ struct vfsmount *mnt, const char *old_name);
int security_inode_mkdir(struct inode *dir, struct dentry *dentry,
struct vfsmount *mnt, int mode);
int security_inode_rmdir(struct inode *dir, struct dentry *dentry);
@@ -1844,6 +1845,7 @@ static inline int security_inode_unlink
static inline int security_inode_symlink (struct inode *dir,
struct dentry *dentry,
+ struct vfsmount *mnt,
const char *old_name)
{
return 0;
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -279,7 +279,7 @@ static int dummy_inode_unlink (struct in
}
static int dummy_inode_symlink (struct inode *inode, struct dentry *dentry,
- const char *name)
+ struct vfsmount *mnt, const char *name)
{
return 0;
}
--- a/security/security.c
+++ b/security/security.c
@@ -352,11 +352,11 @@ int security_inode_unlink(struct inode *
}
int security_inode_symlink(struct inode *dir, struct dentry *dentry,
- const char *old_name)
+ struct vfsmount *mnt, const char *old_name)
{
if (unlikely(IS_PRIVATE(dir)))
return 0;
- return security_ops->inode_symlink(dir, dentry, old_name);
+ return security_ops->inode_symlink(dir, dentry, mnt, old_name);
}
int security_inode_mkdir(struct inode *dir, struct dentry *dentry,
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2210,7 +2210,8 @@ static int selinux_inode_unlink(struct i
return may_link(dir, dentry, MAY_UNLINK);
}
-static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name)
+static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt, const char *name)
{
return may_create(dir, dentry, SECCLASS_LNK_FILE);
}

View file

@ -1,114 +0,0 @@
From: Tony Jones <tonyj@suse.de>
Subject: Pass struct vfsmount to the inode_unlink LSM hook
This is needed for computing pathnames in the AppArmor LSM.
Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
fs/namei.c | 2 +-
include/linux/security.h | 10 +++++++---
security/dummy.c | 3 ++-
security/security.c | 5 +++--
security/selinux/hooks.c | 5 +++--
5 files changed, 16 insertions(+), 9 deletions(-)
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2184,7 +2184,7 @@ int vfs_unlink(struct inode *dir, struct
if (d_mountpoint(dentry))
error = -EBUSY;
else {
- error = security_inode_unlink(dir, dentry);
+ error = security_inode_unlink(dir, dentry, mnt);
if (!error)
error = dir->i_op->unlink(dir, dentry);
}
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -312,6 +312,7 @@ struct request_sock;
* Check the permission to remove a hard link to a file.
* @dir contains the inode structure of parent directory of the file.
* @dentry contains the dentry structure for file to be unlinked.
+ * @mnt is the vfsmount corresponding to @dentry (may be NULL).
* Return 0 if permission is granted.
* @inode_symlink:
* Check the permission to create a symbolic link to a file.
@@ -1261,7 +1262,8 @@ struct security_operations {
int (*inode_link) (struct dentry *old_dentry, struct vfsmount *old_mnt,
struct inode *dir, struct dentry *new_dentry,
struct vfsmount *new_mnt);
- int (*inode_unlink) (struct inode *dir, struct dentry *dentry);
+ int (*inode_unlink) (struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt);
int (*inode_symlink) (struct inode *dir, struct dentry *dentry,
struct vfsmount *mnt, const char *old_name);
int (*inode_mkdir) (struct inode *dir, struct dentry *dentry,
@@ -1521,7 +1523,8 @@ int security_inode_create(struct inode *
int security_inode_link(struct dentry *old_dentry, struct vfsmount *old_mnt,
struct inode *dir, struct dentry *new_dentry,
struct vfsmount *new_mnt);
-int security_inode_unlink(struct inode *dir, struct dentry *dentry);
+int security_inode_unlink(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt);
int security_inode_symlink(struct inode *dir, struct dentry *dentry,
struct vfsmount *mnt, const char *old_name);
int security_inode_mkdir(struct inode *dir, struct dentry *dentry,
@@ -1848,7 +1851,8 @@ static inline int security_inode_link (s
}
static inline int security_inode_unlink (struct inode *dir,
- struct dentry *dentry)
+ struct dentry *dentry,
+ struct vfsmount *mnt)
{
return 0;
}
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -275,7 +275,8 @@ static int dummy_inode_link (struct dent
return 0;
}
-static int dummy_inode_unlink (struct inode *inode, struct dentry *dentry)
+static int dummy_inode_unlink (struct inode *inode, struct dentry *dentry,
+ struct vfsmount *mnt)
{
return 0;
}
--- a/security/security.c
+++ b/security/security.c
@@ -346,11 +346,12 @@ int security_inode_link(struct dentry *o
new_dentry, new_mnt);
}
-int security_inode_unlink(struct inode *dir, struct dentry *dentry)
+int security_inode_unlink(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt)
{
if (unlikely(IS_PRIVATE(dentry->d_inode)))
return 0;
- return security_ops->inode_unlink(dir, dentry);
+ return security_ops->inode_unlink(dir, dentry, mnt);
}
int security_inode_symlink(struct inode *dir, struct dentry *dentry,
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2205,11 +2205,12 @@ static int selinux_inode_link(struct den
return may_link(dir, old_dentry, MAY_LINK);
}
-static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
+static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt)
{
int rc;
- rc = secondary_ops->inode_unlink(dir, dentry);
+ rc = secondary_ops->inode_unlink(dir, dentry, mnt);
if (rc)
return rc;
return may_link(dir, dentry, MAY_UNLINK);

View file

@ -1,540 +0,0 @@
From: Andreas Gruenbacher <agruen@suse.de>
Subject: Pass struct file down the inode_*xattr security LSM hooks
This allows LSMs to also distinguish between file descriptor and path
access for the xattr operations. (The other relevant operations are
covered by the setattr hook.)
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
fs/xattr.c | 58 ++++++++++++++++++++++++-----------------------
include/linux/security.h | 40 +++++++++++++++++++-------------
include/linux/xattr.h | 8 +++---
security/commoncap.c | 4 +--
security/dummy.c | 10 ++++----
security/security.c | 21 +++++++++--------
security/selinux/hooks.c | 10 ++++----
7 files changed, 84 insertions(+), 67 deletions(-)
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -69,7 +69,7 @@ xattr_permission(struct inode *inode, co
int
vfs_setxattr(struct dentry *dentry, struct vfsmount *mnt, char *name,
- void *value, size_t size, int flags)
+ void *value, size_t size, int flags, struct file *file)
{
struct inode *inode = dentry->d_inode;
int error;
@@ -79,7 +79,7 @@ vfs_setxattr(struct dentry *dentry, stru
return error;
mutex_lock(&inode->i_mutex);
- error = security_inode_setxattr(dentry, mnt, name, value, size, flags);
+ error = security_inode_setxattr(dentry, mnt, name, value, size, flags, file);
if (error)
goto out;
error = -EOPNOTSUPP;
@@ -106,7 +106,7 @@ EXPORT_SYMBOL_GPL(vfs_setxattr);
ssize_t
vfs_getxattr(struct dentry *dentry, struct vfsmount *mnt, char *name,
- void *value, size_t size)
+ void *value, size_t size, struct file *file)
{
struct inode *inode = dentry->d_inode;
int error;
@@ -115,7 +115,7 @@ vfs_getxattr(struct dentry *dentry, stru
if (error)
return error;
- error = security_inode_getxattr(dentry, mnt, name);
+ error = security_inode_getxattr(dentry, mnt, name, file);
if (error)
return error;
@@ -143,12 +143,12 @@ EXPORT_SYMBOL_GPL(vfs_getxattr);
ssize_t
vfs_listxattr(struct dentry *dentry, struct vfsmount *mnt, char *list,
- size_t size)
+ size_t size, struct file *file)
{
struct inode *inode = dentry->d_inode;
ssize_t error;
- error = security_inode_listxattr(dentry, mnt);
+ error = security_inode_listxattr(dentry, mnt, file);
if (error)
return error;
error = -EOPNOTSUPP;
@@ -164,7 +164,8 @@ vfs_listxattr(struct dentry *dentry, str
EXPORT_SYMBOL_GPL(vfs_listxattr);
int
-vfs_removexattr(struct dentry *dentry, struct vfsmount *mnt, char *name)
+vfs_removexattr(struct dentry *dentry, struct vfsmount *mnt, char *name,
+ struct file *file)
{
struct inode *inode = dentry->d_inode;
int error;
@@ -176,7 +177,7 @@ vfs_removexattr(struct dentry *dentry, s
if (error)
return error;
- error = security_inode_removexattr(dentry, mnt, name);
+ error = security_inode_removexattr(dentry, mnt, name, file);
if (error)
return error;
@@ -196,7 +197,7 @@ EXPORT_SYMBOL_GPL(vfs_removexattr);
*/
static long
setxattr(struct dentry *dentry, struct vfsmount *mnt, char __user *name,
- void __user *value, size_t size, int flags)
+ void __user *value, size_t size, int flags, struct file *file)
{
int error;
void *kvalue = NULL;
@@ -223,7 +224,7 @@ setxattr(struct dentry *dentry, struct v
}
}
- error = vfs_setxattr(dentry, mnt, kname, kvalue, size, flags);
+ error = vfs_setxattr(dentry, mnt, kname, kvalue, size, flags, file);
kfree(kvalue);
return error;
}
@@ -238,7 +239,7 @@ sys_setxattr(char __user *path, char __u
error = user_path_walk(path, &nd);
if (error)
return error;
- error = setxattr(nd.dentry, nd.mnt, name, value, size, flags);
+ error = setxattr(nd.dentry, nd.mnt, name, value, size, flags, NULL);
path_release(&nd);
return error;
}
@@ -253,7 +254,7 @@ sys_lsetxattr(char __user *path, char __
error = user_path_walk_link(path, &nd);
if (error)
return error;
- error = setxattr(nd.dentry, nd.mnt, name, value, size, flags);
+ error = setxattr(nd.dentry, nd.mnt, name, value, size, flags, NULL);
path_release(&nd);
return error;
}
@@ -271,7 +272,7 @@ sys_fsetxattr(int fd, char __user *name,
return error;
dentry = f->f_path.dentry;
audit_inode(NULL, dentry);
- error = setxattr(dentry, f->f_vfsmnt, name, value, size, flags);
+ error = setxattr(dentry, f->f_vfsmnt, name, value, size, flags, f);
fput(f);
return error;
}
@@ -281,7 +282,7 @@ sys_fsetxattr(int fd, char __user *name,
*/
static ssize_t
getxattr(struct dentry *dentry, struct vfsmount *mnt, char __user *name,
- void __user *value, size_t size)
+ void __user *value, size_t size, struct file *file)
{
ssize_t error;
void *kvalue = NULL;
@@ -301,7 +302,7 @@ getxattr(struct dentry *dentry, struct v
return -ENOMEM;
}
- error = vfs_getxattr(dentry, mnt, kname, kvalue, size);
+ error = vfs_getxattr(dentry, mnt, kname, kvalue, size, file);
if (error > 0) {
if (size && copy_to_user(value, kvalue, error))
error = -EFAULT;
@@ -324,7 +325,7 @@ sys_getxattr(char __user *path, char __u
error = user_path_walk(path, &nd);
if (error)
return error;
- error = getxattr(nd.dentry, nd.mnt, name, value, size);
+ error = getxattr(nd.dentry, nd.mnt, name, value, size, NULL);
path_release(&nd);
return error;
}
@@ -339,7 +340,7 @@ sys_lgetxattr(char __user *path, char __
error = user_path_walk_link(path, &nd);
if (error)
return error;
- error = getxattr(nd.dentry, nd.mnt, name, value, size);
+ error = getxattr(nd.dentry, nd.mnt, name, value, size, NULL);
path_release(&nd);
return error;
}
@@ -354,7 +355,7 @@ sys_fgetxattr(int fd, char __user *name,
if (!f)
return error;
audit_inode(NULL, f->f_path.dentry);
- error = getxattr(f->f_path.dentry, f->f_path.mnt, name, value, size);
+ error = getxattr(f->f_path.dentry, f->f_path.mnt, name, value, size, f);
fput(f);
return error;
}
@@ -364,7 +365,7 @@ sys_fgetxattr(int fd, char __user *name,
*/
static ssize_t
listxattr(struct dentry *dentry, struct vfsmount *mnt, char __user *list,
- size_t size)
+ size_t size, struct file *file)
{
ssize_t error;
char *klist = NULL;
@@ -377,7 +378,7 @@ listxattr(struct dentry *dentry, struct
return -ENOMEM;
}
- error = vfs_listxattr(dentry, mnt, klist, size);
+ error = vfs_listxattr(dentry, mnt, klist, size, file);
if (error > 0) {
if (size && copy_to_user(list, klist, error))
error = -EFAULT;
@@ -399,7 +400,7 @@ sys_listxattr(char __user *path, char __
error = user_path_walk(path, &nd);
if (error)
return error;
- error = listxattr(nd.dentry, nd.mnt, list, size);
+ error = listxattr(nd.dentry, nd.mnt, list, size, NULL);
path_release(&nd);
return error;
}
@@ -413,7 +414,7 @@ sys_llistxattr(char __user *path, char _
error = user_path_walk_link(path, &nd);
if (error)
return error;
- error = listxattr(nd.dentry, nd.mnt, list, size);
+ error = listxattr(nd.dentry, nd.mnt, list, size, NULL);
path_release(&nd);
return error;
}
@@ -428,7 +429,7 @@ sys_flistxattr(int fd, char __user *list
if (!f)
return error;
audit_inode(NULL, f->f_path.dentry);
- error = listxattr(f->f_path.dentry, f->f_path.mnt, list, size);
+ error = listxattr(f->f_path.dentry, f->f_path.mnt, list, size, f);
fput(f);
return error;
}
@@ -437,7 +438,8 @@ sys_flistxattr(int fd, char __user *list
* Extended attribute REMOVE operations
*/
static long
-removexattr(struct dentry *dentry, struct vfsmount *mnt, char __user *name)
+removexattr(struct dentry *dentry, struct vfsmount *mnt, char __user *name,
+ struct file *file)
{
int error;
char kname[XATTR_NAME_MAX + 1];
@@ -448,7 +450,7 @@ removexattr(struct dentry *dentry, struc
if (error < 0)
return error;
- return vfs_removexattr(dentry, mnt, kname);
+ return vfs_removexattr(dentry, mnt, kname, file);
}
asmlinkage long
@@ -460,7 +462,7 @@ sys_removexattr(char __user *path, char
error = user_path_walk(path, &nd);
if (error)
return error;
- error = removexattr(nd.dentry, nd.mnt, name);
+ error = removexattr(nd.dentry, nd.mnt, name, NULL);
path_release(&nd);
return error;
}
@@ -474,7 +476,7 @@ sys_lremovexattr(char __user *path, char
error = user_path_walk_link(path, &nd);
if (error)
return error;
- error = removexattr(nd.dentry, nd.mnt, name);
+ error = removexattr(nd.dentry, nd.mnt, name, NULL);
path_release(&nd);
return error;
}
@@ -491,7 +493,7 @@ sys_fremovexattr(int fd, char __user *na
return error;
dentry = f->f_path.dentry;
audit_inode(NULL, dentry);
- error = removexattr(dentry, f->f_path.mnt, name);
+ error = removexattr(dentry, f->f_path.mnt, name, f);
fput(f);
return error;
}
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -56,8 +56,8 @@ extern void cap_capset_set (struct task_
extern int cap_bprm_set_security (struct linux_binprm *bprm);
extern void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe);
extern int cap_bprm_secureexec(struct linux_binprm *bprm);
-extern int cap_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt, char *name, void *value, size_t size, int flags);
-extern int cap_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt, char *name);
+extern int cap_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt, char *name, void *value, size_t size, int flags, struct file *file);
+extern int cap_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt, char *name, struct file *file);
extern int cap_inode_need_killpriv(struct dentry *dentry);
extern int cap_inode_killpriv(struct dentry *dentry);
extern int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid, int flags);
@@ -1286,16 +1286,18 @@ struct security_operations {
int (*inode_getattr) (struct vfsmount *mnt, struct dentry *dentry);
void (*inode_delete) (struct inode *inode);
int (*inode_setxattr) (struct dentry *dentry, struct vfsmount *mnt,
- char *name, void *value, size_t size, int flags);
+ char *name, void *value, size_t size, int flags,
+ struct file *file);
void (*inode_post_setxattr) (struct dentry *dentry,
struct vfsmount *mnt,
char *name, void *value,
size_t size, int flags);
int (*inode_getxattr) (struct dentry *dentry, struct vfsmount *mnt,
- char *name);
- int (*inode_listxattr) (struct dentry *dentry, struct vfsmount *mnt);
+ char *name, struct file *file);
+ int (*inode_listxattr) (struct dentry *dentry, struct vfsmount *mnt,
+ struct file *file);
int (*inode_removexattr) (struct dentry *dentry, struct vfsmount *mnt,
- char *name);
+ char *name, struct file *file);
int (*inode_need_killpriv) (struct dentry *dentry);
int (*inode_killpriv) (struct dentry *dentry);
int (*inode_getsecurity)(const struct inode *inode, const char *name, void *buffer, size_t size, int err);
@@ -1552,15 +1554,17 @@ int security_inode_setattr(struct dentry
int security_inode_getattr(struct vfsmount *mnt, struct dentry *dentry);
void security_inode_delete(struct inode *inode);
int security_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
- char *name, void *value, size_t size, int flags);
+ char *name, void *value, size_t size, int flags,
+ struct file *file);
void security_inode_post_setxattr(struct dentry *dentry, struct vfsmount *mnt,
char *name, void *value, size_t size,
int flags);
int security_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
- char *name);
-int security_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt);
+ char *name, struct file *file);
+int security_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt,
+ struct file *file);
int security_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt,
- char *name);
+ char *name, struct file *file);
int security_inode_need_killpriv(struct dentry *dentry);
int security_inode_killpriv(struct dentry *dentry);
int security_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err);
@@ -1946,9 +1950,10 @@ static inline void security_inode_delete
static inline int security_inode_setxattr (struct dentry *dentry,
struct vfsmount *mnt, char *name,
- void *value, size_t size, int flags)
+ void *value, size_t size, int flags,
+ struct file *file)
{
- return cap_inode_setxattr(dentry, mnt, name, value, size, flags);
+ return cap_inode_setxattr(dentry, mnt, name, value, size, flags, file);
}
static inline void security_inode_post_setxattr (struct dentry *dentry,
@@ -1959,21 +1964,24 @@ static inline void security_inode_post_s
{ }
static inline int security_inode_getxattr (struct dentry *dentry,
- struct vfsmount *mnt, char *name)
+ struct vfsmount *mnt, char *name,
+ struct file *file)
{
return 0;
}
static inline int security_inode_listxattr (struct dentry *dentry,
- struct vfsmount *mnt)
+ struct vfsmount *mnt,
+ struct file *file)
{
return 0;
}
static inline int security_inode_removexattr (struct dentry *dentry,
- struct vfsmount *mnt, char *name)
+ struct vfsmount *mnt, char *name,
+ struct file *file)
{
- return cap_inode_removexattr(dentry, mnt, name);
+ return cap_inode_removexattr(dentry, mnt, name, file);
}
static inline int security_inode_need_killpriv(struct dentry *dentry)
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -47,12 +47,12 @@ struct xattr_handler {
};
ssize_t vfs_getxattr(struct dentry *, struct vfsmount *, char *, void *,
- size_t);
+ size_t, struct file *);
ssize_t vfs_listxattr(struct dentry *d, struct vfsmount *, char *list,
- size_t size);
+ size_t size, struct file *);
int vfs_setxattr(struct dentry *, struct vfsmount *, char *, void *, size_t,
- int);
-int vfs_removexattr(struct dentry *, struct vfsmount *, char *);
+ int, struct file *);
+int vfs_removexattr(struct dentry *, struct vfsmount *, char *, struct file *);
ssize_t generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size);
ssize_t generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size);
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -369,7 +369,7 @@ int cap_bprm_secureexec (struct linux_bi
}
int cap_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt, char *name,
- void *value, size_t size, int flags)
+ void *value, size_t size, int flags, struct file *file)
{
if (!strcmp(name, XATTR_NAME_CAPS)) {
if (!capable(CAP_SETFCAP))
@@ -383,7 +383,7 @@ int cap_inode_setxattr(struct dentry *de
}
int cap_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt,
- char *name)
+ char *name, struct file *file)
{
if (!strcmp(name, XATTR_NAME_CAPS)) {
if (!capable(CAP_SETFCAP))
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -349,7 +349,7 @@ static void dummy_inode_delete (struct i
static int dummy_inode_setxattr (struct dentry *dentry, struct vfsmount *mnt,
char *name, void *value, size_t size,
- int flags)
+ int flags, struct file *file)
{
if (!strncmp(name, XATTR_SECURITY_PREFIX,
sizeof(XATTR_SECURITY_PREFIX) - 1) &&
@@ -366,18 +366,20 @@ static void dummy_inode_post_setxattr (s
}
static int dummy_inode_getxattr (struct dentry *dentry,
- struct vfsmount *mnt, char *name)
+ struct vfsmount *mnt, char *name,
+ struct file *file)
{
return 0;
}
-static int dummy_inode_listxattr (struct dentry *dentry, struct vfsmount *mnt)
+static int dummy_inode_listxattr (struct dentry *dentry, struct vfsmount *mnt,
+ struct file *file)
{
return 0;
}
static int dummy_inode_removexattr (struct dentry *dentry, struct vfsmount *mnt,
- char *name)
+ char *name, struct file *file)
{
if (!strncmp(name, XATTR_SECURITY_PREFIX,
sizeof(XATTR_SECURITY_PREFIX) - 1) &&
--- a/security/security.c
+++ b/security/security.c
@@ -441,12 +441,13 @@ void security_inode_delete(struct inode
}
int security_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
- char *name, void *value, size_t size, int flags)
+ char *name, void *value, size_t size, int flags,
+ struct file *file)
{
if (unlikely(IS_PRIVATE(dentry->d_inode)))
return 0;
return security_ops->inode_setxattr(dentry, mnt, name, value, size,
- flags);
+ flags, file);
}
void security_inode_post_setxattr(struct dentry *dentry, struct vfsmount *mnt,
@@ -455,30 +456,32 @@ void security_inode_post_setxattr(struct
{
if (unlikely(IS_PRIVATE(dentry->d_inode)))
return;
- security_ops->inode_post_setxattr(dentry, mnt, name, value, size, flags);
+ security_ops->inode_post_setxattr(dentry, mnt, name, value, size,
+ flags);
}
int security_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
- char *name)
+ char *name, struct file *file)
{
if (unlikely(IS_PRIVATE(dentry->d_inode)))
return 0;
- return security_ops->inode_getxattr(dentry, mnt, name);
+ return security_ops->inode_getxattr(dentry, mnt, name, file);
}
-int security_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt)
+int security_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt,
+ struct file *file)
{
if (unlikely(IS_PRIVATE(dentry->d_inode)))
return 0;
- return security_ops->inode_listxattr(dentry, mnt);
+ return security_ops->inode_listxattr(dentry, mnt, file);
}
int security_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt,
- char *name)
+ char *name, struct file *file)
{
if (unlikely(IS_PRIVATE(dentry->d_inode)))
return 0;
- return security_ops->inode_removexattr(dentry, mnt, name);
+ return security_ops->inode_removexattr(dentry, mnt, name, file);
}
int security_inode_need_killpriv(struct dentry *dentry)
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2334,7 +2334,7 @@ static int selinux_inode_setotherxattr(s
static int selinux_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
char *name, void *value, size_t size,
- int flags)
+ int flags, struct file *file)
{
struct task_security_struct *tsec = current->security;
struct inode *inode = dentry->d_inode;
@@ -2410,18 +2410,20 @@ static void selinux_inode_post_setxattr(
}
static int selinux_inode_getxattr (struct dentry *dentry, struct vfsmount *mnt,
- char *name)
+ char *name, struct file *file)
{
return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
}
-static int selinux_inode_listxattr (struct dentry *dentry, struct vfsmount *mnt)
+static int selinux_inode_listxattr (struct dentry *dentry, struct vfsmount *mnt,
+ struct file *file)
{
return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
}
static int selinux_inode_removexattr (struct dentry *dentry,
- struct vfsmount *mnt, char *name)
+ struct vfsmount *mnt, char *name,
+ struct file *file)
{
if (strcmp(name, XATTR_NAME_SELINUX))
return selinux_inode_setotherxattr(dentry, name);

View file

@ -1,85 +0,0 @@
Index: linux-2.6/fs/open.c
===================================================================
--- linux-2.6.orig/fs/open.c
+++ linux-2.6/fs/open.c
@@ -483,6 +483,10 @@ asmlinkage long sys_chroot(const char __
if (!capable(CAP_SYS_CHROOT))
goto dput_and_out;
+ error = security_chroot(&nd);
+ if (error)
+ goto dput_and_out;
+
set_fs_root(current->fs, nd.mnt, nd.dentry);
set_fs_altroot();
error = 0;
Index: linux-2.6/include/linux/security.h
===================================================================
--- linux-2.6.orig/include/linux/security.h
+++ linux-2.6/include/linux/security.h
@@ -247,6 +247,9 @@ struct request_sock;
* Update module state after a successful pivot.
* @old_nd contains the nameidata structure for the old root.
* @new_nd contains the nameidata structure for the new root.
+ * @sb_chroot:
+ * Check permission before chroot to chroot to point named by @nd
+ * @nd contains the nameidata object for the new root
*
* Security hooks for inode operations.
*
@@ -1211,6 +1214,7 @@ struct security_operations {
struct nameidata * new_nd);
void (*sb_post_pivotroot) (struct nameidata * old_nd,
struct nameidata * new_nd);
+ int (*sb_chroot) (struct nameidata * nd);
int (*inode_alloc_security) (struct inode *inode);
void (*inode_free_security) (struct inode *inode);
@@ -1610,6 +1614,11 @@ static inline void security_sb_post_pivo
security_ops->sb_post_pivotroot (old_nd, new_nd);
}
+static inline int security_chroot (struct nameidata *nd)
+{
+ return security_ops->sb_chroot (nd);
+}
+
static inline int security_inode_alloc (struct inode *inode)
{
inode->i_security = NULL;
@@ -2362,6 +2371,11 @@ static inline void security_sb_post_pivo
struct nameidata *new_nd)
{ }
+static inline int security_sb_chroot (struct nameidata *nd)
+{
+ return 0;
+}
+
static inline int security_inode_alloc (struct inode *inode)
{
return 0;
Index: linux-2.6/security/dummy.c
===================================================================
--- linux-2.6.orig/security/dummy.c
+++ linux-2.6/security/dummy.c
@@ -248,6 +248,11 @@ static void dummy_sb_post_pivotroot (str
return;
}
+static int dummy_sb_chroot (struct nameidata *nd)
+{
+ return 0;
+}
+
static int dummy_inode_alloc_security (struct inode *inode)
{
return 0;
@@ -1004,6 +1009,7 @@ void security_fixup_ops (struct security
set_to_dummy_if_null(ops, sb_post_addmount);
set_to_dummy_if_null(ops, sb_pivotroot);
set_to_dummy_if_null(ops, sb_post_pivotroot);
+ set_to_dummy_if_null(ops, sb_chroot);
set_to_dummy_if_null(ops, inode_alloc_security);
set_to_dummy_if_null(ops, inode_free_security);
set_to_dummy_if_null(ops, inode_init_security);

View file

@ -1,123 +0,0 @@
#unionfs-2.2.2_for_2.6.24-rc7.diff
#unionfs-2.1.11_for_2.6.24-rc4.diff
security-create.diff
remove_suid.diff
vfs-notify_change.diff
#should_remove_suid.diff
security-setattr.diff
vfs-mkdir.diff
security-mkdir.diff
vfs-mknod.diff
security-mknod.diff
vfs-symlink.diff
security-symlink.diff
security-readlink.diff
vfs-link.diff
security-link.diff
vfs-rmdir.diff
security-rmdir.diff
fix-vfs_rmdir.diff
vfs-unlink.diff
security-unlink.diff
vfs-rename.diff
security-rename.diff
vfs-setxattr.diff
security-setxattr.diff
vfs-getxattr.diff
security-getxattr.diff
vfs-listxattr.diff
security-listxattr.diff
vfs-removexattr.diff
security-removexattr.diff
unambiguous-__d_path.diff
mount-consistent-__d_path.diff
d_namespace_path.diff
__d_path-keep-connected.diff
fsetattr.diff
#fix-fuse.diff
fsetattr-reintro-ATTR_FILE.diff
file-handle-ops.diff
security-xattr-file.diff
sysctl-pathname.diff
parent-permission.diff
do_path_lookup-nameidata.diff
sys_fchdir-nameidata.diff
file_permission-nameidata.diff
apparmor-audit.diff
apparmor-main.diff
apparmor-lsm.diff
apparmor-module_interface.diff
apparmor-misc.diff
apparmor-intree.diff
#fix-rcu-deref.diff
#fix-name-errorpath.diff
#change-profile-kernel-v2.diff
#expand-dfa.diff
#slash-null-dfa.diff
#profile-namespaces.diff
#owner-perm-set.diff
#apparmor-link-pairs.diff
#apparmor-bootdisable.diff
#apparmor-builtin-only.diff
#apparmor-security-goal.diff
#apparmor-features.diff
#split_init.diff
#apparmor-fix-sysctl-refcount.diff
#apparmor-fix-lock-letter.diff
#fix-link-subset.diff
#hat_perm.diff
#extend-x-mods.diff
#no-safex-link-subset.diff
#apparmor-create-append.diff
#apparmor-failed-name-error.diff
#audit-uid.diff
#apparmor-secondary-accept.diff
#apparmor-audit-flags2.diff
#fix-profile-namespaces.diff
#fix-dfa.diff
#cap-set.diff
#foobar.diff
# # NOT YET
# ecryptfs-d_revalidate.diff
# nfs-nameidata-check.diff
# # statvfs.diff
# # statvfs-2.diff
# # fix-getcwd.diff
# # proc-mounts-cleanup.diff
# # proc-mounts-check-d_path-result.diff
# # fix-d_path.diff
##split-up-nameidata.diff
##vfs_create-nameidata.diff
##xattr_permission.diff
##nfsd_permission-nameidata.diff
# vfs_create-args.diff
# vfs_mknod-args.diff
# vfs_mkdir-args.diff
# vfs_symlink-args.diff
# vfs_link-args.diff
# vfs_rename-args.diff
# may_create-args.diff
# vfs_rmdir-args.diff
# vfs_unlink-args.diff
# may_delete-args.diff
#fix-change_profile-namespace.diff
#audit_denied.diff
#apparmor-audit-flags.diff
#FS2.2.2_fix-unionfs-with-AppArmor.patch
#FS2.1.3_fix-unionfs-with-AppArmor.patch
#named-transitions.diff
apparmor-network.diff
#fix-net.diff
apparmor-rlimits.diff
audit-log-type-in-syslog.diff
#fix-named-transitions.diff
#apparmor-xmods-accept-entry.diff
#apparmor-split-audit-deny.diff
#apparmor-cond-uid.diff
#apparmor-quiet-control.diff
#apparmor-direct-complain.diff

View file

@ -1,96 +0,0 @@
From: Andreas Gruenbacher <agruen@suse.de>
Subject: Pass struct file down to should_remove_suid and children
Pass struct path to should_remove_suid instead of only the dentry.
To make should_remove_suid consistent with changes made to
remove_suid.
Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
fs/ocfs2/file.c | 2 +-
fs/open.c | 5 ++++-
fs/splice.c | 2 +-
include/linux/fs.h | 2 +-
mm/filemap.c | 6 +++---
5 files changed, 10 insertions(+), 7 deletions(-)
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -1191,7 +1191,7 @@ static int ocfs2_prepare_inode_for_write
* inode. There's also the dinode i_size state which
* can be lost via setattr during extending writes (we
* set inode->i_size at the end of a write. */
- if (should_remove_suid(path->dentry)) {
+ if (should_remove_suid(path)) {
if (meta_level == 0) {
ocfs2_meta_unlock(inode, meta_level);
meta_level = 1;
--- a/fs/open.c
+++ b/fs/open.c
@@ -198,6 +198,7 @@ int do_truncate(struct dentry *dentry, s
{
int err;
struct iattr newattrs;
+ struct path path;
/* Not pretty: "inode->i_size" shouldn't really be signed. But it is. */
if (length < 0)
@@ -211,7 +212,9 @@ int do_truncate(struct dentry *dentry, s
}
/* Remove suid/sgid on truncate too */
- newattrs.ia_valid |= should_remove_suid(dentry);
+ path.dentry = dentry;
+ path.mnt = mnt;
+ newattrs.ia_valid |= should_remove_suid(&path);
mutex_lock(&dentry->d_inode->i_mutex);
err = notify_change(dentry, mnt, &newattrs);
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -842,7 +842,7 @@ generic_file_splice_write(struct pipe_in
ssize_t ret;
int err;
- err = should_remove_suid(out->f_path.dentry);
+ err = should_remove_suid(&out->f_path);
if (unlikely(err)) {
mutex_lock(&inode->i_mutex);
err = __remove_suid(&out->f_path, err);
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1698,7 +1698,7 @@ extern void clear_inode(struct inode *);
extern void destroy_inode(struct inode *);
extern struct inode *new_inode(struct super_block *);
extern int __remove_suid(struct path *, int);
-extern int should_remove_suid(struct dentry *);
+extern int should_remove_suid(struct path *);
extern int remove_suid(struct path *);
extern void __insert_inode_hash(struct inode *, unsigned long hashval);
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1882,9 +1882,9 @@ repeat:
* if suid or (sgid and xgrp)
* remove privs
*/
-int should_remove_suid(struct dentry *dentry)
+int should_remove_suid(struct path *path)
{
- mode_t mode = dentry->d_inode->i_mode;
+ mode_t mode = path->dentry->d_inode->i_mode;
int kill = 0;
/* suid always must be killed */
@@ -1915,7 +1915,7 @@ int __remove_suid(struct path *path, int
int remove_suid(struct path *path)
{
- int kill = should_remove_suid(path->dentry);
+ int kill = should_remove_suid(path);
if (unlikely(kill))
return __remove_suid(path, kill);

View file

@ -1,40 +0,0 @@
convert the null transition from using the 0 character to "//" until
the parser gets updated so that it can add a null character transition.
---
security/apparmor/match.c | 24 +-----------------------
1 file changed, 1 insertion(+), 23 deletions(-)
--- a/security/apparmor/match.c
+++ b/security/apparmor/match.c
@@ -262,29 +262,7 @@ unsigned int aa_dfa_next_state(struct aa
*/
unsigned int aa_dfa_null_transition(struct aa_dfa *dfa, unsigned int start)
{
- u16 *def = DEFAULT_TABLE(dfa);
- u32 *base = BASE_TABLE(dfa);
- u16 *next = NEXT_TABLE(dfa);
- u16 *check = CHECK_TABLE(dfa);
- unsigned int state = start, pos;
-
- /* current state is <state>, matching character *str */
- if (dfa->tables[YYTD_ID_EC - 1]) {
- u8 *equiv = EQUIV_TABLE(dfa);
- pos = base[state] + equiv[0];
- if (check[pos] == state)
- state = next[pos];
- else
- state = def[state];
- } else {
- pos = base[state] + 0;
- if (check[pos] == state)
- state = next[pos];
- else
- state = def[state];
- }
-
- return state;
+ return aa_dfa_next_state(dfa, start, "//");
}
/**

File diff suppressed because it is too large Load diff

View file

@ -1,215 +0,0 @@
---
security/apparmor/Kconfig | 15 ++++++
security/apparmor/apparmor.h | 5 ++
security/apparmor/apparmorfs.c | 8 +++
security/apparmor/lsm.c | 95 ++++++++++++++++++++++++++++++++++-------
4 files changed, 109 insertions(+), 14 deletions(-)
--- a/security/apparmor/Kconfig
+++ b/security/apparmor/Kconfig
@@ -25,3 +25,18 @@ config SECURITY_APPARMOR_BOOTPARAM_VALUE
bootup.
If you are unsure how to answer this question, answer 1.
+
+config SECURITY_APPARMOR_DISABLE
+ bool "AppArmor runtime disable"
+ depends on SECURITY_APPARMOR
+ default n
+ help
+ This option enables writing to a apparmorfs node 'disable', which
+ allows AppArmor to be disabled at runtime prior to the policy load.
+ AppArmor will then remain disabled until the next boot.
+ This option is similar to the apparmor.enabled=0 boot parameter,
+ but is to support runtime disabling of AppArmor, e.g. from
+ /sbin/init, for portability across platforms where boot
+ parameters are difficult to employ.
+
+ If you are unsure how to answer this question, answer N.
--- a/security/apparmor/apparmor.h
+++ b/security/apparmor/apparmor.h
@@ -284,6 +284,11 @@ extern int aa_net_perm(struct aa_profile
int family, int type, int protocol);
extern int aa_revalidate_sk(struct sock *sk, char *operation);
+/* lsm.c */
+extern int apparmor_initialized;
+extern void info_message(const char *str);
+extern void apparmor_disable(void);
+
/* list.c */
extern struct aa_namespace *__aa_find_namespace(const char *name,
struct list_head *list);
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -231,6 +231,9 @@ int create_apparmorfs(void)
{
int error;
+ if (!apparmor_initialized)
+ return 0;
+
if (apparmor_dentry) {
AA_ERROR("%s: AppArmor securityfs already exists\n",
__FUNCTION__);
@@ -262,11 +265,16 @@ int create_apparmorfs(void)
if (error)
goto error;
+ /* Report that AppArmor fs is enabled */
+ info_message("AppArmor Filesystem Enabled");
return 0;
error:
destroy_apparmorfs();
AA_ERROR("Error creating AppArmor securityfs\n");
+ apparmor_disable();
return error;
}
+fs_initcall(create_apparmorfs);
+
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -23,16 +23,8 @@
#include "apparmor.h"
#include "inline.h"
-/* Boot time disable flag */
-int apparmor_enabled = CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE;
-
-static int __init apparmor_enabled_setup(char *str)
-{
- apparmor_enabled = simple_strtol(str, NULL, 0);
- return 1;
-}
-__setup("apparmor=", apparmor_enabled_setup);
-
+/* Flag indicating whether initialization completed */
+int apparmor_initialized = 0;
static int param_set_aabool(const char *val, struct kernel_param *kp);
static int param_get_aabool(char *buffer, struct kernel_param *kp);
@@ -75,6 +67,25 @@ unsigned int apparmor_path_max = 2 * PAT
module_param_named(path_max, apparmor_path_max, aauint, S_IRUSR | S_IWUSR);
MODULE_PARM_DESC(apparmor_path_max, "Maximum pathname length allowed");
+/* Boot time disable flag */
+#ifdef CONFIG_SECURITY_APPARMOR_DISABLE
+#define AA_ENABLED_PERMS 0600
+#else
+#define AA_ENABLED_PERMS 0400
+#endif
+static int param_set_aa_enabled(const char *val, struct kernel_param *kp);
+unsigned int apparmor_enabled = CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE;
+module_param_call(enabled, param_set_aa_enabled, param_get_aauint,
+ &apparmor_enabled, AA_ENABLED_PERMS);
+MODULE_PARM_DESC(apparmor_enabled, "Enable/Disable Apparmor on boot");
+
+static int __init apparmor_enabled_setup(char *str)
+{
+ apparmor_enabled = simple_strtol(str, NULL, 0);
+ return 1;
+}
+__setup("apparmor=", apparmor_enabled_setup);
+
static int param_set_aabool(const char *val, struct kernel_param *kp)
{
if (aa_task_context(current))
@@ -103,6 +114,35 @@ static int param_get_aauint(char *buffer
return param_get_uint(buffer, kp);
}
+/* allow run time disabling of apparmor */
+static int param_set_aa_enabled(const char *val, struct kernel_param *kp)
+{
+ char *endp;
+ unsigned long l;
+
+ if (!apparmor_initialized) {
+ apparmor_enabled = 0;
+ return 0;
+ }
+
+ if (aa_task_context(current))
+ return -EPERM;
+
+ if (!apparmor_enabled)
+ return -EINVAL;
+
+ if (!val)
+ return -EINVAL;
+
+ l = simple_strtoul(val, &endp, 0);
+ if (endp == val || l != 0)
+ return -EINVAL;
+
+ apparmor_enabled = 0;
+ apparmor_disable();
+ return 0;
+}
+
static int aa_reject_syscall(struct task_struct *task, gfp_t flags,
const char *name)
{
@@ -879,14 +919,15 @@ struct security_operations apparmor_ops
.socket_shutdown = apparmor_socket_shutdown,
};
-static void info_message(const char *str)
+void info_message(const char *str)
{
struct aa_audit sa;
memset(&sa, 0, sizeof(sa));
sa.gfp_mask = GFP_KERNEL;
sa.info = str;
- printk(KERN_INFO "AppArmor: %s", str);
- aa_audit_message(NULL, &sa, AUDIT_APPARMOR_STATUS);
+ printk(KERN_INFO "AppArmor: %s\n", str);
+ if (audit_enabled)
+ aa_audit_message(NULL, &sa, AUDIT_APPARMOR_STATUS);
}
static int __init apparmor_init(void)
@@ -913,6 +954,8 @@ static int __init apparmor_init(void)
goto register_security_out;
}
+ /* Report that AppArmor successfully initialized */
+ apparmor_initialized = 1;
if (apparmor_complain)
info_message("AppArmor initialized: complainmode enabled");
else
@@ -931,7 +974,31 @@ createfs_out:
}
-module_init(apparmor_init);
+security_initcall(apparmor_init);
+
+void apparmor_disable(void)
+{
+ /* Remove and release all the profiles on the profile list. */
+ mutex_lock(&aa_interface_lock);
+ aa_profile_ns_list_release();
+
+ /* FIXME: cleanup profiles references on files */
+ free_default_namespace();
+
+ /*
+ * Delay for an rcu cycle to make sure that all active task
+ * context readers have finished, and all profiles have been
+ * freed by their rcu callbacks.
+ */
+ synchronize_rcu();
+
+ destroy_apparmorfs();
+ mutex_unlock(&aa_interface_lock);
+
+ apparmor_initialized = 0;
+
+ info_message("AppArmor protection removed");
+}
MODULE_DESCRIPTION("AppArmor process confinement");
MODULE_AUTHOR("Novell/Immunix, http://bugs.opensuse.org");

View file

@ -1,494 +0,0 @@
---
arch/alpha/kernel/osf_sys.c | 11 ++++----
arch/mips/kernel/sysirix.c | 12 ++++-----
arch/parisc/hpux/sys_hpux.c | 11 ++++----
arch/sparc64/solaris/fs.c | 16 ++++--------
fs/compat.c | 13 +++++-----
fs/ecryptfs/super.c | 5 +++-
fs/nfsd/nfs4xdr.c | 2 -
fs/nfsd/vfs.c | 2 -
fs/open.c | 53 ++++++++++++++++++++++++++++++++++---------
include/asm-arm/statfs.h | 6 +++-
include/asm-generic/statfs.h | 9 ++++---
include/asm-ia64/compat.h | 3 +-
include/asm-ia64/statfs.h | 9 ++++---
include/asm-parisc/compat.h | 3 +-
include/asm-parisc/statfs.h | 9 ++++---
include/asm-powerpc/compat.h | 3 +-
include/asm-powerpc/statfs.h | 9 ++++---
include/asm-s390/compat.h | 3 +-
include/asm-s390/statfs.h | 9 ++++---
include/asm-sparc64/compat.h | 3 +-
include/asm-sparc64/statfs.h | 9 ++++---
include/asm-x86_64/compat.h | 3 +-
include/asm-x86_64/statfs.h | 9 ++++---
include/linux/fs.h | 2 -
include/linux/statfs.h | 13 +++++++++-
kernel/acct.c | 2 -
26 files changed, 151 insertions(+), 78 deletions(-)
Index: linux-2.6-apparmor/arch/alpha/kernel/osf_sys.c
===================================================================
--- linux-2.6-apparmor.orig/arch/alpha/kernel/osf_sys.c
+++ linux-2.6-apparmor/arch/alpha/kernel/osf_sys.c
@@ -244,11 +244,11 @@ linux_to_osf_statfs(struct kstatfs *linu
}
static int
-do_osf_statfs(struct dentry * dentry, struct osf_statfs __user *buffer,
- unsigned long bufsiz)
+do_osf_statfs(struct dentry * dentry, struct vfsmount *mnt,
+ struct osf_statfs __user *buffer, unsigned long bufsiz)
{
struct kstatfs linux_stat;
- int error = vfs_statfs(dentry, &linux_stat);
+ int error = vfs_statfs(dentry, mnt, &linux_stat);
if (!error)
error = linux_to_osf_statfs(&linux_stat, buffer, bufsiz);
return error;
@@ -262,7 +262,7 @@ osf_statfs(char __user *path, struct osf
retval = user_path_walk(path, &nd);
if (!retval) {
- retval = do_osf_statfs(nd.dentry, buffer, bufsiz);
+ retval = do_osf_statfs(nd.dentry, nd.mnt, buffer, bufsiz);
path_release(&nd);
}
return retval;
@@ -277,7 +277,8 @@ osf_fstatfs(unsigned long fd, struct osf
retval = -EBADF;
file = fget(fd);
if (file) {
- retval = do_osf_statfs(file->f_path.dentry, buffer, bufsiz);
+ retval = do_osf_statfs(file->f_path.dentry, file->f_path.mnt,
+ buffer, bufsiz);
fput(file);
}
return retval;
Index: linux-2.6-apparmor/arch/mips/kernel/sysirix.c
===================================================================
--- linux-2.6-apparmor.orig/arch/mips/kernel/sysirix.c
+++ linux-2.6-apparmor/arch/mips/kernel/sysirix.c
@@ -694,7 +694,7 @@ asmlinkage int irix_statfs(const char __
if (error)
goto out;
- error = vfs_statfs(nd.dentry, &kbuf);
+ error = vfs_statfs(nd.dentry, nd.mnt, &kbuf);
if (error)
goto dput_and_out;
@@ -732,7 +732,7 @@ asmlinkage int irix_fstatfs(unsigned int
goto out;
}
- error = vfs_statfs(file->f_path.dentry, &kbuf);
+ error = vfs_statfs(file->f_path.dentry, file->f_path.mnt, &kbuf);
if (error)
goto out_f;
@@ -1360,7 +1360,7 @@ asmlinkage int irix_statvfs(char __user
error = user_path_walk(fname, &nd);
if (error)
goto out;
- error = vfs_statfs(nd.dentry, &kbuf);
+ error = vfs_statfs(nd.dentry, nd.mnt, &kbuf);
if (error)
goto dput_and_out;
@@ -1406,7 +1406,7 @@ asmlinkage int irix_fstatvfs(int fd, str
error = -EBADF;
goto out;
}
- error = vfs_statfs(file->f_path.dentry, &kbuf);
+ error = vfs_statfs(file->f_path.dentry, file->f_path.mnt, &kbuf);
if (error)
goto out_f;
@@ -1611,7 +1611,7 @@ asmlinkage int irix_statvfs64(char __use
error = user_path_walk(fname, &nd);
if (error)
goto out;
- error = vfs_statfs(nd.dentry, &kbuf);
+ error = vfs_statfs(nd.dentry, nd.mnt, &kbuf);
if (error)
goto dput_and_out;
@@ -1658,7 +1658,7 @@ asmlinkage int irix_fstatvfs64(int fd, s
error = -EBADF;
goto out;
}
- error = vfs_statfs(file->f_path.dentry, &kbuf);
+ error = vfs_statfs(file->f_path.dentry, file->f_path.mnt, &kbuf);
if (error)
goto out_f;
Index: linux-2.6-apparmor/arch/parisc/hpux/sys_hpux.c
===================================================================
--- linux-2.6-apparmor.orig/arch/parisc/hpux/sys_hpux.c
+++ linux-2.6-apparmor/arch/parisc/hpux/sys_hpux.c
@@ -145,7 +145,7 @@ static int hpux_ustat(dev_t dev, struct
s = user_get_super(dev);
if (s == NULL)
goto out;
- err = vfs_statfs(s->s_root, &sbuf);
+ err = vfs_statfs(s->s_root, NULL, &sbuf);
drop_super(s);
if (err)
goto out;
@@ -186,12 +186,13 @@ struct hpux_statfs {
int16_t f_pad;
};
-static int vfs_statfs_hpux(struct dentry *dentry, struct hpux_statfs *buf)
+static int vfs_statfs_hpux(struct dentry *dentry, struct vfsmount *mnt,
+ struct hpux_statfs *buf)
{
struct kstatfs st;
int retval;
- retval = vfs_statfs(dentry, &st);
+ retval = vfs_statfs(dentry, mnt, &st);
if (retval)
return retval;
@@ -219,7 +220,7 @@ asmlinkage long hpux_statfs(const char _
error = user_path_walk(path, &nd);
if (!error) {
struct hpux_statfs tmp;
- error = vfs_statfs_hpux(nd.dentry, &tmp);
+ error = vfs_statfs_hpux(nd.dentry, nd.mnt, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
path_release(&nd);
@@ -237,7 +238,7 @@ asmlinkage long hpux_fstatfs(unsigned in
file = fget(fd);
if (!file)
goto out;
- error = vfs_statfs_hpux(file->f_path.dentry, &tmp);
+ error = vfs_statfs_hpux(file->f_path.dentry, file->f_path.mnt, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
fput(file);
Index: linux-2.6-apparmor/arch/sparc64/solaris/fs.c
===================================================================
--- linux-2.6-apparmor.orig/arch/sparc64/solaris/fs.c
+++ linux-2.6-apparmor/arch/sparc64/solaris/fs.c
@@ -361,15 +361,12 @@ static int report_statvfs(struct vfsmoun
int error;
struct sol_statvfs __user *ss = A(buf);
- error = vfs_statfs(mnt->mnt_root, &s);
+ error = vfs_statfs(mnt->mnt_root, mnt, &s);
if (!error) {
const char *p = mnt->mnt_sb->s_type->name;
- int i = 0;
int j = strlen (p);
if (j > 15) j = 15;
- if (IS_RDONLY(inode)) i = 1;
- if (mnt->mnt_flags & MNT_NOSUID) i |= 2;
if (!sysv_valid_dev(inode->i_sb->s_dev))
return -EOVERFLOW;
if (put_user (s.f_bsize, &ss->f_bsize) ||
@@ -384,7 +381,8 @@ static int report_statvfs(struct vfsmoun
__copy_to_user (ss->f_basetype,p,j) ||
__put_user (0, (char __user *)&ss->f_basetype[j]) ||
__put_user (s.f_namelen, &ss->f_namemax) ||
- __put_user (i, &ss->f_flag) ||
+ __put_user (s.s_flag & (ST_RDONLY | ST_NOSUID),
+ &ss->f_flag) ||
__clear_user (&ss->f_fstr, 32))
return -EFAULT;
}
@@ -397,15 +395,12 @@ static int report_statvfs64(struct vfsmo
int error;
struct sol_statvfs64 __user *ss = A(buf);
- error = vfs_statfs(mnt->mnt_root, &s);
+ error = vfs_statfs(mnt->mnt_root, mnt, &s);
if (!error) {
const char *p = mnt->mnt_sb->s_type->name;
- int i = 0;
int j = strlen (p);
if (j > 15) j = 15;
- if (IS_RDONLY(inode)) i = 1;
- if (mnt->mnt_flags & MNT_NOSUID) i |= 2;
if (!sysv_valid_dev(inode->i_sb->s_dev))
return -EOVERFLOW;
if (put_user (s.f_bsize, &ss->f_bsize) ||
@@ -420,7 +415,8 @@ static int report_statvfs64(struct vfsmo
__copy_to_user (ss->f_basetype,p,j) ||
__put_user (0, (char __user *)&ss->f_basetype[j]) ||
__put_user (s.f_namelen, &ss->f_namemax) ||
- __put_user (i, &ss->f_flag) ||
+ __put_user (s.s_flag & (ST_RDONLY | ST_NOSUID),
+ &ss->f_flag) ||
__clear_user (&ss->f_fstr, 32))
return -EFAULT;
}
Index: linux-2.6-apparmor/include/asm-arm/statfs.h
===================================================================
--- linux-2.6-apparmor.orig/include/asm-arm/statfs.h
+++ linux-2.6-apparmor/include/asm-arm/statfs.h
@@ -17,7 +17,8 @@ struct statfs {
__kernel_fsid_t f_fsid;
__u32 f_namelen;
__u32 f_frsize;
- __u32 f_spare[5];
+ __u32 f_flag;
+ __u32 f_spare[4];
};
/*
@@ -36,7 +37,8 @@ struct statfs64 {
__kernel_fsid_t f_fsid;
__u32 f_namelen;
__u32 f_frsize;
- __u32 f_spare[5];
+ __u32 f_flag;
+ __u32 f_spare[4];
} __attribute__ ((packed,aligned(4)));
#endif
Index: linux-2.6-apparmor/include/asm-ia64/compat.h
===================================================================
--- linux-2.6-apparmor.orig/include/asm-ia64/compat.h
+++ linux-2.6-apparmor/include/asm-ia64/compat.h
@@ -102,7 +102,8 @@ struct compat_statfs {
compat_fsid_t f_fsid;
int f_namelen; /* SunOS ignores this field. */
int f_frsize;
- int f_spare[5];
+ int f_flag;
+ int f_spare[4];
};
#define COMPAT_RLIM_OLD_INFINITY 0x7fffffff
Index: linux-2.6-apparmor/include/asm-ia64/statfs.h
===================================================================
--- linux-2.6-apparmor.orig/include/asm-ia64/statfs.h
+++ linux-2.6-apparmor/include/asm-ia64/statfs.h
@@ -27,7 +27,8 @@ struct statfs {
__kernel_fsid_t f_fsid;
long f_namelen;
long f_frsize;
- long f_spare[5];
+ long f_flag;
+ long f_spare[4];
};
@@ -42,7 +43,8 @@ struct statfs64 {
__kernel_fsid_t f_fsid;
long f_namelen;
long f_frsize;
- long f_spare[5];
+ long f_flag;
+ long f_spare[4];
};
struct compat_statfs64 {
@@ -56,7 +58,8 @@ struct compat_statfs64 {
__kernel_fsid_t f_fsid;
__u32 f_namelen;
__u32 f_frsize;
- __u32 f_spare[5];
+ __u32 f_flag;
+ __u32 f_spare[4];
} __attribute__((packed));
#endif /* _ASM_IA64_STATFS_H */
Index: linux-2.6-apparmor/include/asm-parisc/compat.h
===================================================================
--- linux-2.6-apparmor.orig/include/asm-parisc/compat.h
+++ linux-2.6-apparmor/include/asm-parisc/compat.h
@@ -102,7 +102,8 @@ struct compat_statfs {
__kernel_fsid_t f_fsid;
s32 f_namelen;
s32 f_frsize;
- s32 f_spare[5];
+ s32 f_flag;
+ s32 f_spare[4];
};
struct compat_sigcontext {
Index: linux-2.6-apparmor/include/asm-parisc/statfs.h
===================================================================
--- linux-2.6-apparmor.orig/include/asm-parisc/statfs.h
+++ linux-2.6-apparmor/include/asm-parisc/statfs.h
@@ -24,7 +24,8 @@ struct statfs {
__kernel_fsid_t f_fsid;
long f_namelen;
long f_frsize;
- long f_spare[5];
+ long f_flag;
+ long f_spare[4];
};
struct statfs64 {
@@ -38,7 +39,8 @@ struct statfs64 {
__kernel_fsid_t f_fsid;
long f_namelen;
long f_frsize;
- long f_spare[5];
+ long f_flag;
+ long f_spare[4];
};
struct compat_statfs64 {
@@ -52,7 +54,8 @@ struct compat_statfs64 {
__kernel_fsid_t f_fsid;
__u32 f_namelen;
__u32 f_frsize;
- __u32 f_spare[5];
+ __u32 f_flag;
+ __u32 f_spare[4];
};
#endif
Index: linux-2.6-apparmor/include/asm-powerpc/compat.h
===================================================================
--- linux-2.6-apparmor.orig/include/asm-powerpc/compat.h
+++ linux-2.6-apparmor/include/asm-powerpc/compat.h
@@ -97,7 +97,8 @@ struct compat_statfs {
compat_fsid_t f_fsid;
int f_namelen; /* SunOS ignores this field. */
int f_frsize;
- int f_spare[5];
+ int f_flag;
+ int f_spare[4];
};
#define COMPAT_RLIM_OLD_INFINITY 0x7fffffff
Index: linux-2.6-apparmor/include/asm-powerpc/statfs.h
===================================================================
--- linux-2.6-apparmor.orig/include/asm-powerpc/statfs.h
+++ linux-2.6-apparmor/include/asm-powerpc/statfs.h
@@ -26,7 +26,8 @@ struct statfs {
__kernel_fsid_t f_fsid;
long f_namelen;
long f_frsize;
- long f_spare[5];
+ long f_flag;
+ long f_spare[4];
};
struct statfs64 {
@@ -40,7 +41,8 @@ struct statfs64 {
__kernel_fsid_t f_fsid;
long f_namelen;
long f_frsize;
- long f_spare[5];
+ long f_flag;
+ long f_spare[4];
};
struct compat_statfs64 {
@@ -54,7 +56,8 @@ struct compat_statfs64 {
__kernel_fsid_t f_fsid;
__u32 f_namelen;
__u32 f_frsize;
- __u32 f_spare[5];
+ __u32 f_flag;
+ __u32 f_spare[4];
};
#endif /* ! __powerpc64__ */
#endif
Index: linux-2.6-apparmor/include/asm-s390/compat.h
===================================================================
--- linux-2.6-apparmor.orig/include/asm-s390/compat.h
+++ linux-2.6-apparmor/include/asm-s390/compat.h
@@ -127,7 +127,8 @@ struct compat_statfs {
compat_fsid_t f_fsid;
s32 f_namelen;
s32 f_frsize;
- s32 f_spare[6];
+ s32 f_flag;
+ s32 f_spare[5];
};
#define COMPAT_RLIM_OLD_INFINITY 0x7fffffff
Index: linux-2.6-apparmor/include/asm-s390/statfs.h
===================================================================
--- linux-2.6-apparmor.orig/include/asm-s390/statfs.h
+++ linux-2.6-apparmor/include/asm-s390/statfs.h
@@ -36,7 +36,8 @@ struct statfs {
__kernel_fsid_t f_fsid;
int f_namelen;
int f_frsize;
- int f_spare[5];
+ int f_flag;
+ int f_spare[4];
};
struct statfs64 {
@@ -50,7 +51,8 @@ struct statfs64 {
__kernel_fsid_t f_fsid;
int f_namelen;
int f_frsize;
- int f_spare[5];
+ int f_flag;
+ int f_spare[4];
};
struct compat_statfs64 {
@@ -64,7 +66,8 @@ struct compat_statfs64 {
__kernel_fsid_t f_fsid;
__u32 f_namelen;
__u32 f_frsize;
- __u32 f_spare[5];
+ __u32 f_flag;
+ __u32 f_spare[4];
};
#endif /* __s390x__ */
Index: linux-2.6-apparmor/include/asm-sparc64/compat.h
===================================================================
--- linux-2.6-apparmor.orig/include/asm-sparc64/compat.h
+++ linux-2.6-apparmor/include/asm-sparc64/compat.h
@@ -131,7 +131,8 @@ struct compat_statfs {
compat_fsid_t f_fsid;
int f_namelen; /* SunOS ignores this field. */
int f_frsize;
- int f_spare[5];
+ int f_flag;
+ int f_spare[4];
};
#define COMPAT_RLIM_INFINITY 0x7fffffff
Index: linux-2.6-apparmor/include/asm-sparc64/statfs.h
===================================================================
--- linux-2.6-apparmor.orig/include/asm-sparc64/statfs.h
+++ linux-2.6-apparmor/include/asm-sparc64/statfs.h
@@ -21,7 +21,8 @@ struct statfs {
__kernel_fsid_t f_fsid;
long f_namelen;
long f_frsize;
- long f_spare[5];
+ long f_flag;
+ long f_spare[4];
};
struct statfs64 {
@@ -35,7 +36,8 @@ struct statfs64 {
__kernel_fsid_t f_fsid;
long f_namelen;
long f_frsize;
- long f_spare[5];
+ long f_flag;
+ long f_spare[4];
};
struct compat_statfs64 {
@@ -49,7 +51,8 @@ struct compat_statfs64 {
__kernel_fsid_t f_fsid;
__u32 f_namelen;
__u32 f_frsize;
- __u32 f_spare[5];
+ __u32 f_flag;
+ __u32 f_spare[4];
};
#endif

View file

@ -1,370 +0,0 @@
---
fs/compat.c | 13 +++++-----
fs/ecryptfs/super.c | 5 +++-
fs/nfsd/nfs4xdr.c | 2 -
fs/nfsd/vfs.c | 2 -
fs/open.c | 53 ++++++++++++++++++++++++++++++++++---------
fs/super.c | 2 -
include/asm-generic/statfs.h | 9 ++++---
include/asm-x86_64/compat.h | 3 +-
include/asm-x86_64/statfs.h | 9 ++++---
include/linux/fs.h | 2 -
include/linux/statfs.h | 13 +++++++++-
kernel/acct.c | 2 -
12 files changed, 84 insertions(+), 31 deletions(-)
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -194,7 +194,7 @@ static int put_compat_statfs(struct comp
__put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) ||
__put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]) ||
__put_user(kbuf->f_frsize, &ubuf->f_frsize) ||
- __put_user(0, &ubuf->f_spare[0]) ||
+ __put_user(kbuf->f_flag, &ubuf->f_flag) ||
__put_user(0, &ubuf->f_spare[1]) ||
__put_user(0, &ubuf->f_spare[2]) ||
__put_user(0, &ubuf->f_spare[3]) ||
@@ -215,7 +215,7 @@ asmlinkage long compat_sys_statfs(const
error = user_path_walk(path, &nd);
if (!error) {
struct kstatfs tmp;
- error = vfs_statfs(nd.dentry, &tmp);
+ error = vfs_statfs(nd.dentry, nd.mnt, &tmp);
if (!error)
error = put_compat_statfs(buf, &tmp);
path_release(&nd);
@@ -233,7 +233,7 @@ asmlinkage long compat_sys_fstatfs(unsig
file = fget(fd);
if (!file)
goto out;
- error = vfs_statfs(file->f_path.dentry, &tmp);
+ error = vfs_statfs(file->f_path.dentry, file->f_path.mnt, &tmp);
if (!error)
error = put_compat_statfs(buf, &tmp);
fput(file);
@@ -267,7 +267,8 @@ static int put_compat_statfs64(struct co
__put_user(kbuf->f_namelen, &ubuf->f_namelen) ||
__put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) ||
__put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]) ||
- __put_user(kbuf->f_frsize, &ubuf->f_frsize))
+ __put_user(kbuf->f_frsize, &ubuf->f_frsize) ||
+ __put_user(kbuf->f_flag, &ubuf->f_flag))
return -EFAULT;
return 0;
}
@@ -283,7 +284,7 @@ asmlinkage long compat_sys_statfs64(cons
error = user_path_walk(path, &nd);
if (!error) {
struct kstatfs tmp;
- error = vfs_statfs(nd.dentry, &tmp);
+ error = vfs_statfs(nd.dentry, nd.mnt, &tmp);
if (!error)
error = put_compat_statfs64(buf, &tmp);
path_release(&nd);
@@ -304,7 +305,7 @@ asmlinkage long compat_sys_fstatfs64(uns
file = fget(fd);
if (!file)
goto out;
- error = vfs_statfs(file->f_path.dentry, &tmp);
+ error = vfs_statfs(file->f_path.dentry, file->f_path.mnt, &tmp);
if (!error)
error = put_compat_statfs64(buf, &tmp);
fput(file);
--- a/fs/ecryptfs/super.c
+++ b/fs/ecryptfs/super.c
@@ -119,7 +119,10 @@ static void ecryptfs_put_super(struct su
*/
static int ecryptfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
- return vfs_statfs(ecryptfs_dentry_to_lower(dentry), buf);
+ struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
+
+ return vfs_statfs(lower_dentry, lower_mnt, buf);
}
/**
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1457,7 +1457,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL)) ||
(bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE |
FATTR4_WORD1_SPACE_TOTAL))) {
- err = vfs_statfs(dentry, &statfs);
+ err = vfs_statfs(dentry, exp->ex_mnt, &statfs);
if (err)
goto out_nfserr;
}
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1767,7 +1767,7 @@ __be32
nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat)
{
__be32 err = fh_verify(rqstp, fhp, 0, MAY_NOP);
- if (!err && vfs_statfs(fhp->fh_dentry,stat))
+ if (!err && vfs_statfs(fhp->fh_dentry, fhp->fh_export->ex_mnt, stat))
err = nfserr_io;
return err;
}
--- a/fs/open.c
+++ b/fs/open.c
@@ -28,7 +28,7 @@
#include <linux/rcupdate.h>
#include <linux/audit.h>
-int vfs_statfs(struct dentry *dentry, struct kstatfs *buf)
+int vfs_statfs(struct dentry *dentry, struct vfsmount *mnt, struct kstatfs *buf)
{
int retval = -ENODEV;
@@ -40,8 +40,35 @@ int vfs_statfs(struct dentry *dentry, st
if (retval)
return retval;
retval = dentry->d_sb->s_op->statfs(dentry, buf);
- if (retval == 0 && buf->f_frsize == 0)
- buf->f_frsize = buf->f_bsize;
+ if (retval == 0) {
+ unsigned long f_flag = ST_IN_USE;
+ unsigned long x;
+
+ if (buf->f_frsize == 0)
+ buf->f_frsize = buf->f_bsize;
+
+ x = dentry->d_inode->i_sb->s_flags;
+ if (x & MS_RDONLY)
+ f_flag |= ST_RDONLY;
+ if (x & MS_SYNCHRONOUS)
+ f_flag |= ST_SYNCHRONOUS;
+ if (x & MS_MANDLOCK)
+ f_flag |= ST_MANDLOCK;
+
+ if (mnt) {
+ int x = mnt->mnt_flags;
+
+ if (x & MNT_NOSUID)
+ f_flag |= ST_NOSUID;
+ if (x & MNT_NODEV)
+ f_flag |= ST_NODEV;
+ if (x & MNT_NOATIME)
+ f_flag |= ST_NOATIME;
+ if (x & MNT_NODIRATIME)
+ f_flag |= ST_NODIRATIME;
+ }
+ buf->f_flag = f_flag;
+ }
}
}
return retval;
@@ -49,12 +76,13 @@ int vfs_statfs(struct dentry *dentry, st
EXPORT_SYMBOL(vfs_statfs);
-static int vfs_statfs_native(struct dentry *dentry, struct statfs *buf)
+static int vfs_statfs_native(struct dentry *dentry, struct vfsmount *mnt,
+ struct statfs *buf)
{
struct kstatfs st;
int retval;
- retval = vfs_statfs(dentry, &st);
+ retval = vfs_statfs(dentry, mnt, &st);
if (retval)
return retval;
@@ -87,17 +115,19 @@ static int vfs_statfs_native(struct dent
buf->f_fsid = st.f_fsid;
buf->f_namelen = st.f_namelen;
buf->f_frsize = st.f_frsize;
+ buf->f_flag = st.f_flag;
memset(buf->f_spare, 0, sizeof(buf->f_spare));
}
return 0;
}
-static int vfs_statfs64(struct dentry *dentry, struct statfs64 *buf)
+static int vfs_statfs64(struct dentry *dentry, struct vfsmount *mnt,
+ struct statfs64 *buf)
{
struct kstatfs st;
int retval;
- retval = vfs_statfs(dentry, &st);
+ retval = vfs_statfs(dentry, mnt, &st);
if (retval)
return retval;
@@ -114,6 +144,7 @@ static int vfs_statfs64(struct dentry *d
buf->f_fsid = st.f_fsid;
buf->f_namelen = st.f_namelen;
buf->f_frsize = st.f_frsize;
+ buf->f_flag = st.f_flag;
memset(buf->f_spare, 0, sizeof(buf->f_spare));
}
return 0;
@@ -127,7 +158,7 @@ asmlinkage long sys_statfs(const char __
error = user_path_walk(path, &nd);
if (!error) {
struct statfs tmp;
- error = vfs_statfs_native(nd.dentry, &tmp);
+ error = vfs_statfs_native(nd.dentry, nd.mnt, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
path_release(&nd);
@@ -146,7 +177,7 @@ asmlinkage long sys_statfs64(const char
error = user_path_walk(path, &nd);
if (!error) {
struct statfs64 tmp;
- error = vfs_statfs64(nd.dentry, &tmp);
+ error = vfs_statfs64(nd.dentry, nd.mnt, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
path_release(&nd);
@@ -165,7 +196,7 @@ asmlinkage long sys_fstatfs(unsigned int
file = fget(fd);
if (!file)
goto out;
- error = vfs_statfs_native(file->f_path.dentry, &tmp);
+ error = vfs_statfs_native(file->f_path.dentry, file->f_path.mnt, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
fput(file);
@@ -186,7 +217,7 @@ asmlinkage long sys_fstatfs64(unsigned i
file = fget(fd);
if (!file)
goto out;
- error = vfs_statfs64(file->f_path.dentry, &tmp);
+ error = vfs_statfs64(file->f_path.dentry, file->f_path.mnt, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
fput(file);
--- a/fs/super.c
+++ b/fs/super.c
@@ -542,7 +542,7 @@ asmlinkage long sys_ustat(unsigned dev,
s = user_get_super(new_decode_dev(dev));
if (s == NULL)
goto out;
- err = vfs_statfs(s->s_root, &sbuf);
+ err = vfs_statfs(s->s_root, NULL, &sbuf);
drop_super(s);
if (err)
goto out;
--- a/include/asm-generic/statfs.h
+++ b/include/asm-generic/statfs.h
@@ -17,7 +17,8 @@ struct statfs {
__kernel_fsid_t f_fsid;
__u32 f_namelen;
__u32 f_frsize;
- __u32 f_spare[5];
+ __u32 f_flag;
+ __u32 f_spare[4];
};
struct statfs64 {
@@ -31,7 +32,8 @@ struct statfs64 {
__kernel_fsid_t f_fsid;
__u32 f_namelen;
__u32 f_frsize;
- __u32 f_spare[5];
+ __u32 f_flag;
+ __u32 f_spare[4];
};
struct compat_statfs64 {
@@ -45,7 +47,8 @@ struct compat_statfs64 {
__kernel_fsid_t f_fsid;
__u32 f_namelen;
__u32 f_frsize;
- __u32 f_spare[5];
+ __u32 f_flag;
+ __u32 f_spare[4];
};
#endif
--- a/include/asm-x86_64/compat.h
+++ b/include/asm-x86_64/compat.h
@@ -104,7 +104,8 @@ struct compat_statfs {
compat_fsid_t f_fsid;
int f_namelen; /* SunOS ignores this field. */
int f_frsize;
- int f_spare[5];
+ int f_flag;
+ int f_spare[4];
};
#define COMPAT_RLIM_OLD_INFINITY 0x7fffffff
--- a/include/asm-x86_64/statfs.h
+++ b/include/asm-x86_64/statfs.h
@@ -24,7 +24,8 @@ struct statfs {
__kernel_fsid_t f_fsid;
long f_namelen;
long f_frsize;
- long f_spare[5];
+ long f_flag;
+ long f_spare[4];
};
struct statfs64 {
@@ -38,7 +39,8 @@ struct statfs64 {
__kernel_fsid_t f_fsid;
long f_namelen;
long f_frsize;
- long f_spare[5];
+ long f_flag;
+ long f_spare[4];
};
struct compat_statfs64 {
@@ -52,7 +54,8 @@ struct compat_statfs64 {
__kernel_fsid_t f_fsid;
__u32 f_namelen;
__u32 f_frsize;
- __u32 f_spare[5];
+ __u32 f_flag;
+ __u32 f_spare[4];
} __attribute__((packed));
#endif
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1408,7 +1408,7 @@ extern struct vfsmount *copy_tree(struct
extern void mnt_set_mountpoint(struct vfsmount *, struct dentry *,
struct vfsmount *);
-extern int vfs_statfs(struct dentry *, struct kstatfs *);
+extern int vfs_statfs(struct dentry *, struct vfsmount *, struct kstatfs *);
/* /sys/fs */
extern struct subsystem fs_subsys;
--- a/include/linux/statfs.h
+++ b/include/linux/statfs.h
@@ -16,7 +16,18 @@ struct kstatfs {
__kernel_fsid_t f_fsid;
long f_namelen;
long f_frsize;
- long f_spare[5];
+ unsigned long f_flag;
+ long f_spare[4];
};
+#define ST_RDONLY 1
+#define ST_NOSUID 2
+#define ST_NODEV 4
+#define ST_NOEXEC 8
+#define ST_SYNCHRONOUS 16
+#define ST_MANDLOCK 64
+#define ST_NOATIME 1024
+#define ST_NODIRATIME 2048
+#define ST_IN_USE (1 << 31)
+
#endif
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -118,7 +118,7 @@ static int check_free_space(struct file
spin_unlock(&acct_globals.lock);
/* May block */
- if (vfs_statfs(file->f_path.dentry, &sbuf))
+ if (vfs_statfs(file->f_path.dentry, file->f_path.mnt, &sbuf))
return res;
suspend = sbuf.f_blocks * SUSPEND;
resume = sbuf.f_blocks * RESUME;

View file

@ -1,5 +0,0 @@
struct_path-nameidata.diff
struct_path-vfs_getattr.diff
struct_path-getattr-iop.diff
struct_path-security-getattr.diff
struct_path-nfsfh.diff

View file

@ -1,504 +0,0 @@
Index: linux-2.6/fs/9p/vfs_inode.c
===================================================================
--- linux-2.6.orig/fs/9p/vfs_inode.c
+++ linux-2.6/fs/9p/vfs_inode.c
@@ -824,16 +824,15 @@ Release_lock:
/**
* v9fs_vfs_getattr - retrieve file metadata
- * @mnt - mount information
- * @dentry - file to get attributes on
+ * @path - file to get attributes on
* @stat - metadata structure to populate
*
*/
static int
-v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
- struct kstat *stat)
+v9fs_vfs_getattr(struct path *path, struct kstat *stat)
{
+ struct dentry *dentry = path->dentry;
struct v9fs_fcall *fcall = NULL;
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode);
struct v9fs_fid *fid = v9fs_fid_clone(dentry);
Index: linux-2.6/fs/afs/inode.c
===================================================================
--- linux-2.6.orig/fs/afs/inode.c
+++ linux-2.6/fs/afs/inode.c
@@ -218,15 +218,13 @@ inline int afs_iget(struct super_block *
/*
* read the attributes of an inode
*/
-int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry,
- struct kstat *stat)
+int afs_inode_getattr(struct path *path, struct kstat *stat)
{
+ struct dentry *dentry = path->dentry;
+ struct inode *inode = dentry->d_inode;
struct afs_vnode *vnode;
- struct inode *inode;
int ret;
- inode = dentry->d_inode;
-
_enter("{ ino=%lu v=%lu }", inode->i_ino, inode->i_version);
vnode = AFS_FS_I(inode);
Index: linux-2.6/fs/afs/internal.h
===================================================================
--- linux-2.6.orig/fs/afs/internal.h
+++ linux-2.6/fs/afs/internal.h
@@ -82,8 +82,7 @@ extern int afs_cache_get_page_cookie(str
*/
extern int afs_iget(struct super_block *sb, struct afs_fid *fid,
struct inode **_inode);
-extern int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry,
- struct kstat *stat);
+extern int afs_inode_getattr(struct path *path, struct kstat *stat);
extern void afs_clear_inode(struct inode *inode);
/*
Index: linux-2.6/fs/bad_inode.c
===================================================================
--- linux-2.6.orig/fs/bad_inode.c
+++ linux-2.6/fs/bad_inode.c
@@ -257,8 +257,7 @@ static int bad_inode_permission(struct i
return -EIO;
}
-static int bad_inode_getattr(struct vfsmount *mnt, struct dentry *dentry,
- struct kstat *stat)
+static int bad_inode_getattr(struct path *path, struct kstat *stat)
{
return -EIO;
}
Index: linux-2.6/fs/cifs/cifsfs.h
===================================================================
--- linux-2.6.orig/fs/cifs/cifsfs.h
+++ linux-2.6/fs/cifs/cifsfs.h
@@ -55,7 +55,7 @@ extern int cifs_rmdir(struct inode *, st
extern int cifs_rename(struct inode *, struct dentry *, struct inode *,
struct dentry *);
extern int cifs_revalidate(struct dentry *);
-extern int cifs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
+extern int cifs_getattr(struct path *, struct kstat *);
extern int cifs_setattr(struct dentry *, struct iattr *);
extern struct inode_operations cifs_file_inode_ops;
Index: linux-2.6/fs/cifs/inode.c
===================================================================
--- linux-2.6.orig/fs/cifs/inode.c
+++ linux-2.6/fs/cifs/inode.c
@@ -1091,9 +1091,9 @@ int cifs_revalidate(struct dentry *diren
return rc;
}
-int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
- struct kstat *stat)
+int cifs_getattr(struct path *path, struct kstat *stat)
{
+ struct dentry *dentry = path->dentry;
int err = cifs_revalidate(dentry);
if (!err) {
generic_fillattr(dentry->d_inode, stat);
Index: linux-2.6/fs/coda/inode.c
===================================================================
--- linux-2.6.orig/fs/coda/inode.c
+++ linux-2.6/fs/coda/inode.c
@@ -236,8 +236,9 @@ static void coda_clear_inode(struct inod
coda_cache_clear_inode(inode);
}
-int coda_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+int coda_getattr(struct path *path, struct kstat *stat)
{
+ struct dentry *dentry = path->dentry;
int err = coda_revalidate_inode(dentry);
if (!err)
generic_fillattr(dentry->d_inode, stat);
Index: linux-2.6/fs/fat/file.c
===================================================================
--- linux-2.6.orig/fs/fat/file.c
+++ linux-2.6/fs/fat/file.c
@@ -303,8 +303,9 @@ void fat_truncate(struct inode *inode)
fat_flush_inodes(inode->i_sb, inode, NULL);
}
-int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+int fat_getattr(struct path *path, struct kstat *stat)
{
+ struct dentry *dentry = path->dentry;
struct inode *inode = dentry->d_inode;
generic_fillattr(inode, stat);
stat->blksize = MSDOS_SB(inode->i_sb)->cluster_size;
Index: linux-2.6/fs/fuse/dir.c
===================================================================
--- linux-2.6.orig/fs/fuse/dir.c
+++ linux-2.6/fs/fuse/dir.c
@@ -1067,11 +1067,11 @@ static int fuse_setattr(struct dentry *e
return err;
}
-static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
- struct kstat *stat)
+static int fuse_getattr(struct path *path, struct kstat *stat)
{
- struct inode *inode = entry->d_inode;
- int err = fuse_revalidate(entry);
+ struct dentry *dentry = path->dentry;
+ struct inode *inode = dentry->d_inode;
+ int err = fuse_revalidate(dentry);
if (!err)
generic_fillattr(inode, stat);
Index: linux-2.6/fs/gfs2/ops_inode.c
===================================================================
--- linux-2.6.orig/fs/gfs2/ops_inode.c
+++ linux-2.6/fs/gfs2/ops_inode.c
@@ -1001,9 +1001,9 @@ out:
* Returns: errno
*/
-static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry,
- struct kstat *stat)
+static int gfs2_getattr(struct path *path, struct kstat *stat)
{
+ struct dentry *dentry = path->dentry;
struct inode *inode = dentry->d_inode;
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_holder gh;
Index: linux-2.6/fs/hostfs/hostfs_kern.c
===================================================================
--- linux-2.6.orig/fs/hostfs/hostfs_kern.c
+++ linux-2.6/fs/hostfs/hostfs_kern.c
@@ -873,10 +873,9 @@ int hostfs_setattr(struct dentry *dentry
return(inode_setattr(dentry->d_inode, attr));
}
-int hostfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
- struct kstat *stat)
+int hostfs_getattr(struct path *path, struct kstat *stat)
{
- generic_fillattr(dentry->d_inode, stat);
+ generic_fillattr(path->dentry->d_inode, stat);
return(0);
}
Index: linux-2.6/fs/libfs.c
===================================================================
--- linux-2.6.orig/fs/libfs.c
+++ linux-2.6/fs/libfs.c
@@ -11,10 +11,9 @@
#include <asm/uaccess.h>
-int simple_getattr(struct vfsmount *mnt, struct dentry *dentry,
- struct kstat *stat)
+int simple_getattr(struct path *path, struct kstat *stat)
{
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = path->dentry->d_inode;
generic_fillattr(inode, stat);
stat->blocks = inode->i_mapping->nrpages << (PAGE_CACHE_SHIFT - 9);
return 0;
Index: linux-2.6/fs/minix/inode.c
===================================================================
--- linux-2.6.orig/fs/minix/inode.c
+++ linux-2.6/fs/minix/inode.c
@@ -535,8 +535,9 @@ int minix_sync_inode(struct inode * inod
return err;
}
-int minix_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+int minix_getattr(struct path *path, struct kstat *stat)
{
+ struct dentry *dentry = path->dentry;
generic_fillattr(dentry->d_inode, stat);
if (INODE_VERSION(dentry->d_inode) == MINIX_V1)
stat->blocks = (BLOCK_SIZE / 512) * V1_minix_blocks(stat->size);
Index: linux-2.6/fs/minix/minix.h
===================================================================
--- linux-2.6.orig/fs/minix/minix.h
+++ linux-2.6/fs/minix/minix.h
@@ -55,7 +55,7 @@ extern int minix_new_block(struct inode
extern void minix_free_block(struct inode * inode, int block);
extern unsigned long minix_count_free_blocks(struct minix_sb_info *sbi);
-extern int minix_getattr(struct vfsmount *, struct dentry *, struct kstat *);
+extern int minix_getattr(struct path *, struct kstat *);
extern void V2_minix_truncate(struct inode *);
extern void V1_minix_truncate(struct inode *);
Index: linux-2.6/fs/nfs/inode.c
===================================================================
--- linux-2.6.orig/fs/nfs/inode.c
+++ linux-2.6/fs/nfs/inode.c
@@ -415,9 +415,9 @@ static void nfs_wake_up_inode(struct ino
wake_up_bit(&nfsi->flags, NFS_INO_REVALIDATING);
}
-int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+int nfs_getattr(struct path *path, struct kstat *stat)
{
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = path->dentry->d_inode;
int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME;
int err;
@@ -433,8 +433,8 @@ int nfs_getattr(struct vfsmount *mnt, st
* - NFS never sets MS_NOATIME or MS_NODIRATIME so there is
* no point in checking those.
*/
- if ((mnt->mnt_flags & MNT_NOATIME) ||
- ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode)))
+ if ((path->mnt->mnt_flags & MNT_NOATIME) ||
+ ((path->mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode)))
need_atime = 0;
if (need_atime)
Index: linux-2.6/fs/ocfs2/file.c
===================================================================
--- linux-2.6.orig/fs/ocfs2/file.c
+++ linux-2.6/fs/ocfs2/file.c
@@ -935,10 +935,9 @@ bail:
return status;
}
-int ocfs2_getattr(struct vfsmount *mnt,
- struct dentry *dentry,
- struct kstat *stat)
+int ocfs2_getattr(struct path *path, struct kstat *stat)
{
+ struct dentry *dentry = path->dentry;
struct inode *inode = dentry->d_inode;
struct super_block *sb = dentry->d_inode->i_sb;
struct ocfs2_super *osb = sb->s_fs_info;
Index: linux-2.6/fs/ocfs2/file.h
===================================================================
--- linux-2.6.orig/fs/ocfs2/file.h
+++ linux-2.6/fs/ocfs2/file.h
@@ -46,8 +46,7 @@ int ocfs2_do_extend_allocation(struct oc
struct ocfs2_alloc_context *meta_ac,
enum ocfs2_alloc_restarted *reason);
int ocfs2_setattr(struct dentry *dentry, struct iattr *attr);
-int ocfs2_getattr(struct vfsmount *mnt, struct dentry *dentry,
- struct kstat *stat);
+int ocfs2_getattr(struct path *path, struct kstat *stat);
int ocfs2_permission(struct inode *inode, int mask,
struct nameidata *nd);
Index: linux-2.6/fs/proc/base.c
===================================================================
--- linux-2.6.orig/fs/proc/base.c
+++ linux-2.6/fs/proc/base.c
@@ -1045,9 +1045,9 @@ out_unlock:
return NULL;
}
-static int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+static int pid_getattr(struct path *path, struct kstat *stat)
{
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = path->dentry->d_inode;
struct task_struct *task;
generic_fillattr(inode, stat);
@@ -2379,9 +2379,9 @@ out_no_task:
return retval;
}
-static int proc_task_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+static int proc_task_getattr(struct path *path, struct kstat *stat)
{
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = path->dentry->d_inode;
struct task_struct *p = get_proc_task(inode);
generic_fillattr(inode, stat);
Index: linux-2.6/fs/proc/generic.c
===================================================================
--- linux-2.6.orig/fs/proc/generic.c
+++ linux-2.6/fs/proc/generic.c
@@ -253,10 +253,9 @@ out:
return error;
}
-static int proc_getattr(struct vfsmount *mnt, struct dentry *dentry,
- struct kstat *stat)
+static int proc_getattr(struct path *path, struct kstat *stat)
{
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = path->dentry->d_inode;
struct proc_dir_entry *de = PROC_I(inode)->pde;
if (de && de->nlink)
inode->i_nlink = de->nlink;
Index: linux-2.6/fs/proc/root.c
===================================================================
--- linux-2.6.orig/fs/proc/root.c
+++ linux-2.6/fs/proc/root.c
@@ -92,10 +92,9 @@ void __init proc_root_init(void)
proc_bus = proc_mkdir("bus", NULL);
}
-static int proc_root_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat
-)
+static int proc_root_getattr(struct path *path, struct kstat *stat)
{
- generic_fillattr(dentry->d_inode, stat);
+ generic_fillattr(path->dentry->d_inode, stat);
stat->nlink = proc_root.nlink + nr_processes();
return 0;
}
Index: linux-2.6/fs/smbfs/inode.c
===================================================================
--- linux-2.6.orig/fs/smbfs/inode.c
+++ linux-2.6/fs/smbfs/inode.c
@@ -653,8 +653,9 @@ smb_statfs(struct dentry *dentry, struct
return result;
}
-int smb_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+int smb_getattr(struct path *path, struct kstat *stat)
{
+ struct dentry *dentry = path->dentry;
int err = smb_revalidate_inode(dentry);
if (!err)
generic_fillattr(dentry->d_inode, stat);
Index: linux-2.6/fs/smbfs/proto.h
===================================================================
--- linux-2.6.orig/fs/smbfs/proto.h
+++ linux-2.6/fs/smbfs/proto.h
@@ -60,7 +60,7 @@ extern void smb_get_inode_attr(struct in
extern void smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr);
extern void smb_invalidate_inodes(struct smb_sb_info *server);
extern int smb_revalidate_inode(struct dentry *dentry);
-extern int smb_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat);
+extern int smb_getattr(struct path *path, struct kstat *stat);
extern int smb_notify_change(struct dentry *dentry, struct iattr *attr);
/* file.c */
extern const struct address_space_operations smb_file_aops;
Index: linux-2.6/fs/stat.c
===================================================================
--- linux-2.6.orig/fs/stat.c
+++ linux-2.6/fs/stat.c
@@ -48,7 +48,7 @@ int vfs_getattr(struct path *path, struc
return retval;
if (inode->i_op->getattr)
- return inode->i_op->getattr(path->mnt, path->dentry, stat);
+ return inode->i_op->getattr(path, stat);
generic_fillattr(inode, stat);
return 0;
Index: linux-2.6/fs/sysv/itree.c
===================================================================
--- linux-2.6.orig/fs/sysv/itree.c
+++ linux-2.6/fs/sysv/itree.c
@@ -440,10 +440,10 @@ static unsigned sysv_nblocks(struct supe
return blocks;
}
-int sysv_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+int sysv_getattr(struct path *path, struct kstat *stat)
{
- struct super_block *s = mnt->mnt_sb;
- generic_fillattr(dentry->d_inode, stat);
+ struct super_block *s = path->mnt->mnt_sb;
+ generic_fillattr(path->dentry->d_inode, stat);
stat->blocks = (s->s_blocksize / 512) * sysv_nblocks(s, stat->size);
stat->blksize = s->s_blocksize;
return 0;
Index: linux-2.6/fs/sysv/sysv.h
===================================================================
--- linux-2.6.orig/fs/sysv/sysv.h
+++ linux-2.6/fs/sysv/sysv.h
@@ -142,7 +142,7 @@ extern int sysv_write_inode(struct inode
extern int sysv_sync_inode(struct inode *);
extern int sysv_sync_file(struct file *, struct dentry *, int);
extern void sysv_set_inode(struct inode *, dev_t);
-extern int sysv_getattr(struct vfsmount *, struct dentry *, struct kstat *);
+extern int sysv_getattr(struct path *, struct kstat *);
extern int sysv_init_icache(void);
extern void sysv_destroy_icache(void);
Index: linux-2.6/fs/xfs/linux-2.6/xfs_iops.c
===================================================================
--- linux-2.6.orig/fs/xfs/linux-2.6/xfs_iops.c
+++ linux-2.6/fs/xfs/linux-2.6/xfs_iops.c
@@ -617,11 +617,10 @@ xfs_vn_permission(
STATIC int
xfs_vn_getattr(
- struct vfsmount *mnt,
- struct dentry *dentry,
+ struct path *path,
struct kstat *stat)
{
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = path->dentry->d_inode;
bhv_vnode_t *vp = vn_from_inode(inode);
bhv_vattr_t vattr = { .va_mask = XFS_AT_STAT };
int error;
Index: linux-2.6/include/linux/coda_linux.h
===================================================================
--- linux-2.6.orig/include/linux/coda_linux.h
+++ linux-2.6/include/linux/coda_linux.h
@@ -40,7 +40,7 @@ int coda_flush(struct file *f, fl_owner_
int coda_release(struct inode *i, struct file *f);
int coda_permission(struct inode *inode, int mask, struct nameidata *nd);
int coda_revalidate_inode(struct dentry *);
-int coda_getattr(struct vfsmount *, struct dentry *, struct kstat *);
+int coda_getattr(struct path *, struct kstat *);
int coda_setattr(struct dentry *, struct iattr *);
/* global variables */
Index: linux-2.6/include/linux/fs.h
===================================================================
--- linux-2.6.orig/include/linux/fs.h
+++ linux-2.6/include/linux/fs.h
@@ -1118,7 +1118,7 @@ struct inode_operations {
void (*truncate) (struct inode *);
int (*permission) (struct inode *, int, struct nameidata *);
int (*setattr) (struct dentry *, struct iattr *);
- int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
+ int (*getattr) (struct path *path, struct kstat *);
int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
ssize_t (*listxattr) (struct dentry *, char *, size_t);
@@ -1850,7 +1850,7 @@ extern int dcache_dir_open(struct inode
extern int dcache_dir_close(struct inode *, struct file *);
extern loff_t dcache_dir_lseek(struct file *, loff_t, int);
extern int dcache_readdir(struct file *, void *, filldir_t);
-extern int simple_getattr(struct vfsmount *, struct dentry *, struct kstat *);
+extern int simple_getattr(struct path *, struct kstat *);
extern int simple_statfs(struct dentry *, struct kstatfs *);
extern int simple_link(struct dentry *, struct inode *, struct dentry *);
extern int simple_unlink(struct inode *, struct dentry *);
Index: linux-2.6/include/linux/msdos_fs.h
===================================================================
--- linux-2.6.orig/include/linux/msdos_fs.h
+++ linux-2.6/include/linux/msdos_fs.h
@@ -402,8 +402,7 @@ extern const struct file_operations fat_
extern struct inode_operations fat_file_inode_operations;
extern int fat_notify_change(struct dentry * dentry, struct iattr * attr);
extern void fat_truncate(struct inode *inode);
-extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry,
- struct kstat *stat);
+extern int fat_getattr(struct path *path, struct kstat *stat);
/* fat/inode.c */
extern void fat_attach(struct inode *inode, loff_t i_pos);
Index: linux-2.6/include/linux/nfs_fs.h
===================================================================
--- linux-2.6.orig/include/linux/nfs_fs.h
+++ linux-2.6/include/linux/nfs_fs.h
@@ -297,7 +297,7 @@ extern struct inode *nfs_fhget(struct su
struct nfs_fattr *);
extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr);
-extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
+extern int nfs_getattr(struct path *, struct kstat *);
extern int nfs_permission(struct inode *, int, struct nameidata *);
extern int nfs_access_get_cached(struct inode *, struct rpc_cred *, struct nfs_access_entry *);
extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *);

View file

@ -1,920 +0,0 @@
Index: linux-2.6/fs/nfsd/nfs2acl.c
===================================================================
--- linux-2.6.orig/fs/nfsd/nfs2acl.c
+++ linux-2.6/fs/nfsd/nfs2acl.c
@@ -62,7 +62,7 @@ static __be32 nfsacld_proc_getacl(struct
if (acl == NULL) {
/* Solaris returns the inode's minimum ACL. */
- struct inode *inode = fh->fh_dentry->d_inode;
+ struct inode *inode = fh->fh_path.dentry->d_inode;
acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
}
resp->acl_access = acl;
@@ -220,7 +220,7 @@ static int nfsaclsvc_decode_accessargs(s
static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_getaclres *resp)
{
- struct dentry *dentry = resp->fh.fh_dentry;
+ struct dentry *dentry = resp->fh.fh_path.dentry;
struct inode *inode = dentry->d_inode;
struct kvec *head = rqstp->rq_res.head;
unsigned int base;
Index: linux-2.6/fs/nfsd/nfs3acl.c
===================================================================
--- linux-2.6.orig/fs/nfsd/nfs3acl.c
+++ linux-2.6/fs/nfsd/nfs3acl.c
@@ -58,7 +58,7 @@ static __be32 nfsd3_proc_getacl(struct s
if (acl == NULL) {
/* Solaris returns the inode's minimum ACL. */
- struct inode *inode = fh->fh_dentry->d_inode;
+ struct inode *inode = fh->fh_path.dentry->d_inode;
acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
}
resp->acl_access = acl;
@@ -166,7 +166,7 @@ static int nfs3svc_decode_setaclargs(str
static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_getaclres *resp)
{
- struct dentry *dentry = resp->fh.fh_dentry;
+ struct dentry *dentry = resp->fh.fh_path.dentry;
p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh);
if (resp->status == 0 && dentry && dentry->d_inode) {
Index: linux-2.6/fs/nfsd/nfs3proc.c
===================================================================
--- linux-2.6.orig/fs/nfsd/nfs3proc.c
+++ linux-2.6/fs/nfsd/nfs3proc.c
@@ -58,7 +58,6 @@ nfsd3_proc_getattr(struct svc_rqst *rqst
{
int err;
__be32 nfserr;
- struct path path;
dprintk("nfsd: GETATTR(3) %s\n",
SVCFH_fmt(&argp->fh));
@@ -68,9 +67,7 @@ nfsd3_proc_getattr(struct svc_rqst *rqst
if (nfserr)
RETURN_STATUS(nfserr);
- path.mnt = resp->fh.fh_export->ex_mnt;
- path.dentry = resp->fh.fh_dentry;
- err = vfs_getattr(&path, &resp->stat);
+ err = vfs_getattr(&resp->fh.fh_path, &resp->stat);
nfserr = nfserrno(err);
RETURN_STATUS(nfserr);
@@ -187,7 +184,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp,
rqstp->rq_vec, argp->vlen,
&resp->count);
if (nfserr == 0) {
- struct inode *inode = resp->fh.fh_dentry->d_inode;
+ struct inode *inode = resp->fh.fh_path.dentry->d_inode;
resp->eof = (argp->offset + resp->count) >= inode->i_size;
}
@@ -566,7 +563,7 @@ nfsd3_proc_fsinfo(struct svc_rqst * rqst
* different read/write sizes for file systems known to have
* problems with large blocks */
if (nfserr == 0) {
- struct super_block *sb = argp->fh.fh_dentry->d_inode->i_sb;
+ struct super_block *sb = argp->fh.fh_path.dentry->d_inode->i_sb;
/* Note that we don't care for remote fs's here */
if (sb->s_magic == 0x4d44 /* MSDOS_SUPER_MAGIC */) {
@@ -602,7 +599,7 @@ nfsd3_proc_pathconf(struct svc_rqst * rq
nfserr = fh_verify(rqstp, &argp->fh, 0, MAY_NOP);
if (nfserr == 0) {
- struct super_block *sb = argp->fh.fh_dentry->d_inode->i_sb;
+ struct super_block *sb = argp->fh.fh_path.dentry->d_inode->i_sb;
/* Note that we don't care for remote fs's here */
switch (sb->s_magic) {
Index: linux-2.6/fs/nfsd/nfs3xdr.c
===================================================================
--- linux-2.6.orig/fs/nfsd/nfs3xdr.c
+++ linux-2.6/fs/nfsd/nfs3xdr.c
@@ -153,7 +153,7 @@ static __be32 *
encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
struct kstat *stat)
{
- struct dentry *dentry = fhp->fh_dentry;
+ struct dentry *dentry = fhp->fh_path.dentry;
struct timespec time;
*p++ = htonl(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]);
@@ -185,7 +185,7 @@ encode_fattr3(struct svc_rqst *rqstp, __
static __be32 *
encode_saved_post_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
{
- struct inode *inode = fhp->fh_dentry->d_inode;
+ struct inode *inode = fhp->fh_path.dentry->d_inode;
/* Attributes to follow */
*p++ = xdr_one;
@@ -223,15 +223,13 @@ encode_saved_post_attr(struct svc_rqst *
static __be32 *
encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
{
- struct path path;
+ struct dentry *dentry = fhp->fh_path.dentry;
- path.dentry = fhp->fh_dentry;
- if (path.dentry && path.dentry->d_inode != NULL) {
+ if (dentry && dentry->d_inode != NULL) {
int err;
struct kstat stat;
- path.mnt = fhp->fh_export->ex_mnt;
- err = vfs_getattr(&path, &stat);
+ err = vfs_getattr(&fhp->fh_path, &stat);
if (!err) {
*p++ = xdr_one; /* attributes follow */
return encode_fattr3(rqstp, p, fhp, &stat);
@@ -254,7 +252,7 @@ nfs3svc_encode_post_op_attr(struct svc_r
static __be32 *
encode_wcc_data(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
{
- struct dentry *dentry = fhp->fh_dentry;
+ struct dentry *dentry = fhp->fh_path.dentry;
if (dentry && dentry->d_inode && fhp->fh_post_saved) {
if (fhp->fh_pre_saved) {
@@ -808,7 +806,7 @@ compose_entry_fh(struct nfsd3_readdirres
struct dentry *dparent, *dchild;
int rv = 0;
- dparent = cd->fh.fh_dentry;
+ dparent = cd->fh.fh_path.dentry;
exp = cd->fh.fh_export;
fh_init(fhp, NFS3_FHSIZE);
Index: linux-2.6/fs/nfsd/nfs4proc.c
===================================================================
--- linux-2.6.orig/fs/nfsd/nfs4proc.c
+++ linux-2.6/fs/nfsd/nfs4proc.c
@@ -54,7 +54,7 @@ static inline void
fh_dup2(struct svc_fh *dst, struct svc_fh *src)
{
fh_put(dst);
- dget(src->fh_dentry);
+ dget(src->fh_path.dentry);
if (src->fh_export)
cache_get(&src->fh_export->h);
*dst = *src;
@@ -261,7 +261,7 @@ static __be32
nfsd4_getfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct svc_fh **getfh)
{
- if (!cstate->current_fh.fh_dentry)
+ if (!cstate->current_fh.fh_path.dentry)
return nfserr_nofilehandle;
*getfh = &cstate->current_fh;
@@ -295,7 +295,7 @@ static __be32
nfsd4_restorefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
void *arg)
{
- if (!cstate->save_fh.fh_dentry)
+ if (!cstate->save_fh.fh_path.dentry)
return nfserr_restorefh;
fh_dup2(&cstate->current_fh, &cstate->save_fh);
@@ -306,7 +306,7 @@ static __be32
nfsd4_savefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
void *arg)
{
- if (!cstate->current_fh.fh_dentry)
+ if (!cstate->current_fh.fh_path.dentry)
return nfserr_nofilehandle;
fh_dup2(&cstate->save_fh, &cstate->current_fh);
@@ -457,7 +457,7 @@ nfsd4_link(struct svc_rqst *rqstp, struc
{
__be32 status = nfserr_nofilehandle;
- if (!cstate->save_fh.fh_dentry)
+ if (!cstate->save_fh.fh_path.dentry)
return status;
status = nfsd_link(rqstp, &cstate->current_fh,
link->li_name, link->li_namelen, &cstate->save_fh);
@@ -477,7 +477,7 @@ nfsd4_lookupp(struct svc_rqst *rqstp, st
if((ret = exp_pseudoroot(rqstp->rq_client, &tmp_fh,
&rqstp->rq_chandle)) != 0)
return ret;
- if (tmp_fh.fh_dentry == cstate->current_fh.fh_dentry) {
+ if (tmp_fh.fh_path.dentry == cstate->current_fh.fh_path.dentry) {
fh_put(&tmp_fh);
return nfserr_noent;
}
@@ -583,7 +583,7 @@ nfsd4_rename(struct svc_rqst *rqstp, str
{
__be32 status = nfserr_nofilehandle;
- if (!cstate->save_fh.fh_dentry)
+ if (!cstate->save_fh.fh_path.dentry)
return status;
if (nfs4_in_grace() && !(cstate->save_fh.fh_export->ex_flags
& NFSEXP_NOSUBTREECHECK))
@@ -597,8 +597,8 @@ nfsd4_rename(struct svc_rqst *rqstp, str
if (status == nfserr_isdir)
status = nfserr_exist;
else if ((status == nfserr_notdir) &&
- (S_ISDIR(cstate->save_fh.fh_dentry->d_inode->i_mode) &&
- S_ISDIR(cstate->current_fh.fh_dentry->d_inode->i_mode)))
+ (S_ISDIR(cstate->save_fh.fh_path.dentry->d_inode->i_mode) &&
+ S_ISDIR(cstate->current_fh.fh_path.dentry->d_inode->i_mode)))
status = nfserr_exist;
else if (status == nfserr_symlink)
status = nfserr_notdir;
@@ -716,7 +716,7 @@ _nfsd4_verify(struct svc_rqst *rqstp, st
status = nfsd4_encode_fattr(&cstate->current_fh,
cstate->current_fh.fh_export,
- cstate->current_fh.fh_dentry, buf,
+ &cstate->current_fh.fh_path, buf,
&count, verify->ve_bmval,
rqstp);
@@ -876,7 +876,7 @@ nfsd4_proc_compound(struct svc_rqst *rqs
opdesc = &nfsd4_ops[op->opnum];
- if (!cstate->current_fh.fh_dentry) {
+ if (!cstate->current_fh.fh_path.dentry) {
if (!(opdesc->op_flags & ALLOWED_WITHOUT_FH)) {
op->status = nfserr_nofilehandle;
goto encode_op;
Index: linux-2.6/fs/nfsd/nfs4state.c
===================================================================
--- linux-2.6.orig/fs/nfsd/nfs4state.c
+++ linux-2.6/fs/nfsd/nfs4state.c
@@ -1286,7 +1286,7 @@ test_share(struct nfs4_stateid *stp, str
static __be32
nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
{
- struct inode *ino = current_fh->fh_dentry->d_inode;
+ struct inode *ino = current_fh->fh_path.dentry->d_inode;
struct nfs4_file *fp;
struct nfs4_stateid *stp;
__be32 ret;
@@ -1745,7 +1745,7 @@ __be32
nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
{
struct nfs4_file *fp = NULL;
- struct inode *ino = current_fh->fh_dentry->d_inode;
+ struct inode *ino = current_fh->fh_path.dentry->d_inode;
struct nfs4_stateid *stp = NULL;
struct nfs4_delegation *dp = NULL;
__be32 status;
@@ -1969,7 +1969,7 @@ search_close_lru(u32 st_id, int flags)
static inline int
nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp)
{
- return fhp->fh_dentry->d_inode != stp->st_vfs_file->f_path.dentry->d_inode;
+ return fhp->fh_path.dentry->d_inode != stp->st_vfs_file->f_path.dentry->d_inode;
}
static int
@@ -2052,7 +2052,7 @@ nfs4_preprocess_stateid_op(struct svc_fh
struct nfs4_stateid *stp = NULL;
struct nfs4_delegation *dp = NULL;
stateid_t *stidp;
- struct inode *ino = current_fh->fh_dentry->d_inode;
+ struct inode *ino = current_fh->fh_path.dentry->d_inode;
__be32 status;
dprintk("NFSD: preprocess_stateid_op: stateid = (%08x/%08x/%08x/%08x)\n",
@@ -2253,8 +2253,8 @@ nfsd4_open_confirm(struct svc_rqst *rqst
struct nfs4_stateid *stp;
dprintk("NFSD: nfsd4_open_confirm on file %.*s\n",
- (int)cstate->current_fh.fh_dentry->d_name.len,
- cstate->current_fh.fh_dentry->d_name.name);
+ (int)cstate->current_fh.fh_path.dentry->d_name.len,
+ cstate->current_fh.fh_path.dentry->d_name.name);
status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0);
if (status)
@@ -2324,8 +2324,8 @@ nfsd4_open_downgrade(struct svc_rqst *rq
unsigned int share_access;
dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n",
- (int)cstate->current_fh.fh_dentry->d_name.len,
- cstate->current_fh.fh_dentry->d_name.name);
+ (int)cstate->current_fh.fh_path.dentry->d_name.len,
+ cstate->current_fh.fh_path.dentry->d_name.name);
if (!access_valid(od->od_share_access)
|| !deny_valid(od->od_share_deny))
@@ -2380,8 +2380,8 @@ nfsd4_close(struct svc_rqst *rqstp, stru
struct nfs4_stateid *stp;
dprintk("NFSD: nfsd4_close on file %.*s\n",
- (int)cstate->current_fh.fh_dentry->d_name.len,
- cstate->current_fh.fh_dentry->d_name.name);
+ (int)cstate->current_fh.fh_path.dentry->d_name.len,
+ cstate->current_fh.fh_path.dentry->d_name.name);
nfs4_lock_state();
/* check close_lru for replay */
@@ -2837,7 +2837,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, stru
goto out;
}
- inode = cstate->current_fh.fh_dentry->d_inode;
+ inode = cstate->current_fh.fh_path.dentry->d_inode;
locks_init_lock(&file_lock);
switch (lockt->lt_type) {
case NFS4_READ_LT:
@@ -2876,7 +2876,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, stru
* only the dentry:inode set.
*/
memset(&file, 0, sizeof (struct file));
- file.f_path.dentry = cstate->current_fh.fh_dentry;
+ file.f_path.dentry = cstate->current_fh.fh_path.dentry;
status = nfs_ok;
if (posix_test_lock(&file, &file_lock, &conflock)) {
Index: linux-2.6/fs/nfsd/nfs4xdr.c
===================================================================
--- linux-2.6.orig/fs/nfsd/nfs4xdr.c
+++ linux-2.6/fs/nfsd/nfs4xdr.c
@@ -1424,7 +1424,7 @@ static __be32 fattr_handle_absent_fs(u32
*/
__be32
nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
- struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval,
+ struct path *path, __be32 *buffer, int *countp, u32 *bmval,
struct svc_rqst *rqstp)
{
u32 bmval0 = bmval[0];
@@ -1442,7 +1442,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
int err;
int aclsupport = 0;
struct nfs4_acl *acl = NULL;
- struct path path;
+ struct dentry *dentry = path->dentry;
BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1);
BUG_ON(bmval0 & ~NFSD_SUPPORTED_ATTRS_WORD0);
@@ -1454,9 +1454,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
goto out;
}
- path.mnt = exp->ex_mnt;
- path.dentry = dentry;
- err = vfs_getattr(&path, &stat);
+ err = vfs_getattr(path, &stat);
if (err)
goto out_nfserr;
if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL)) ||
@@ -1839,28 +1837,29 @@ nfsd4_encode_dirent_fattr(struct nfsd4_r
const char *name, int namlen, __be32 *p, int *buflen)
{
struct svc_export *exp = cd->rd_fhp->fh_export;
- struct dentry *dentry;
+ struct path path;
__be32 nfserr;
- dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen);
- if (IS_ERR(dentry))
- return nfserrno(PTR_ERR(dentry));
+ path.dentry = lookup_one_len(name, cd->rd_fhp->fh_path.dentry, namlen);
+ if (IS_ERR(path.dentry))
+ return nfserrno(PTR_ERR(path.dentry));
exp_get(exp);
- if (d_mountpoint(dentry)) {
+ if (d_mountpoint(path.dentry)) {
int err;
- err = nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp);
+ err = nfsd_cross_mnt(cd->rd_rqstp, &path.dentry, &exp);
if (err) {
nfserr = nfserrno(err);
goto out_put;
}
}
- nfserr = nfsd4_encode_fattr(NULL, exp, dentry, p, buflen, cd->rd_bmval,
+ path.mnt = exp->ex_mnt;
+ nfserr = nfsd4_encode_fattr(NULL, exp, &path, p, buflen, cd->rd_bmval,
cd->rd_rqstp);
out_put:
- dput(dentry);
+ dput(path.dentry);
exp_put(exp);
return nfserr;
}
@@ -2010,7 +2009,7 @@ nfsd4_encode_getattr(struct nfsd4_compou
return nfserr;
buflen = resp->end - resp->p - (COMPOUND_ERR_SLACK_SPACE >> 2);
- nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, fhp->fh_dentry,
+ nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, &fhp->fh_path,
resp->p, &buflen, getattr->ga_bmval,
resp->rqstp);
if (!nfserr)
@@ -2248,7 +2247,7 @@ nfsd4_encode_read(struct nfsd4_compoundr
if (nfserr)
return nfserr;
eof = (read->rd_offset + maxcount >=
- read->rd_fhp->fh_dentry->d_inode->i_size);
+ read->rd_fhp->fh_path.dentry->d_inode->i_size);
WRITE32(eof);
WRITE32(maxcount);
Index: linux-2.6/fs/nfsd/nfsfh.c
===================================================================
--- linux-2.6.orig/fs/nfsd/nfsfh.c
+++ linux-2.6/fs/nfsd/nfsfh.c
@@ -123,7 +123,7 @@ fh_verify(struct svc_rqst *rqstp, struct
/* keep this filehandle for possible reference when encoding attributes */
rqstp->rq_reffh = fh;
- if (!fhp->fh_dentry) {
+ if (!fhp->fh_path.dentry) {
__u32 *datap=NULL;
__u32 tfh[3]; /* filehandle fragment for oldstyle filehandles */
int fileid_type;
@@ -238,7 +238,7 @@ fh_verify(struct svc_rqst *rqstp, struct
}
#endif
- fhp->fh_dentry = dentry;
+ fhp->fh_path.dentry = dentry;
fhp->fh_export = exp;
nfsd_nr_verified++;
} else {
@@ -246,7 +246,7 @@ fh_verify(struct svc_rqst *rqstp, struct
* (e.g. nfsproc_create calls fh_verify, then nfsd_create does as well)
*/
dprintk("nfsd: fh_verify - just checking\n");
- dentry = fhp->fh_dentry;
+ dentry = fhp->fh_path.dentry;
exp = fhp->fh_export;
/* Set user creds for this exportpoint; necessary even
* in the "just checking" case because this may be a
@@ -372,7 +372,7 @@ fh_compose(struct svc_fh *fhp, struct sv
if (ref_fh == fhp)
fh_put(ref_fh);
- if (fhp->fh_locked || fhp->fh_dentry) {
+ if (fhp->fh_locked || fhp->fh_path.dentry) {
printk(KERN_ERR "fh_compose: fh %s/%s not initialized!\n",
parent->d_name.name, dentry->d_name.name);
}
@@ -380,7 +380,8 @@ fh_compose(struct svc_fh *fhp, struct sv
printk(KERN_ERR "fh_compose: called with maxsize %d! %s/%s\n",
fhp->fh_maxsize, parent->d_name.name, dentry->d_name.name);
- fhp->fh_dentry = dget(dentry); /* our internal copy */
+ fhp->fh_path.mnt = exp->ex_mnt; /* FIXME: can this get released while we still keep the copy here? Probably not... */
+ fhp->fh_path.dentry = dget(dentry); /* our internal copy */
fhp->fh_export = exp;
cache_get(&exp->h);
@@ -459,10 +460,10 @@ fh_update(struct svc_fh *fhp)
struct dentry *dentry;
__u32 *datap;
- if (!fhp->fh_dentry)
+ if (!fhp->fh_path.dentry)
goto out_bad;
- dentry = fhp->fh_dentry;
+ dentry = fhp->fh_path.dentry;
if (!dentry->d_inode)
goto out_negative;
if (fhp->fh_handle.fh_version != 1) {
@@ -498,11 +499,11 @@ out_negative:
void
fh_put(struct svc_fh *fhp)
{
- struct dentry * dentry = fhp->fh_dentry;
+ struct dentry * dentry = fhp->fh_path.dentry;
struct svc_export * exp = fhp->fh_export;
if (dentry) {
fh_unlock(fhp);
- fhp->fh_dentry = NULL;
+ fhp->fh_path.dentry = NULL;
dput(dentry);
#ifdef CONFIG_NFSD_V3
fhp->fh_pre_saved = 0;
Index: linux-2.6/fs/nfsd/nfsproc.c
===================================================================
--- linux-2.6.orig/fs/nfsd/nfsproc.c
+++ linux-2.6/fs/nfsd/nfsproc.c
@@ -39,25 +39,17 @@ nfsd_proc_null(struct svc_rqst *rqstp, v
static __be32
nfsd_return_attrs(__be32 err, struct nfsd_attrstat *resp)
{
- struct path path;
-
if (err)
return err;
- path.mnt = resp->fh.fh_export->ex_mnt;
- path.dentry = resp->fh.fh_dentry;
- return nfserrno(vfs_getattr(&path, &resp->stat));
+ return nfserrno(vfs_getattr(&resp->fh.fh_path, &resp->stat));
}
static __be32
nfsd_return_dirop(__be32 err, struct nfsd_diropres *resp)
{
- struct path path;
-
if (err)
return err;
- path.mnt = resp->fh.fh_export->ex_mnt;
- path.dentry = resp->fh.fh_dentry;
- return nfserrno(vfs_getattr(&path, &resp->stat));
+ return nfserrno(vfs_getattr(&resp->fh.fh_path, &resp->stat));
}
/*
* Get a file's attributes
@@ -143,7 +135,6 @@ static __be32
nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp,
struct nfsd_readres *resp)
{
- struct path path;
__be32 nfserr;
dprintk("nfsd: READ %s %d bytes at %d\n",
@@ -172,9 +163,7 @@ nfsd_proc_read(struct svc_rqst *rqstp, s
if (nfserr)
return nfserr;
- path.mnt = resp->fh.fh_export->ex_mnt;
- path.dentry = resp->fh.fh_dentry;
- return nfserrno(vfs_getattr(&path, &resp->stat));
+ return nfserrno(vfs_getattr(&resp->fh.fh_path, &resp->stat));
}
/*
@@ -236,7 +225,7 @@ nfsd_proc_create(struct svc_rqst *rqstp,
if (isdotent(argp->name, argp->len))
goto done;
fh_lock_nested(dirfhp, I_MUTEX_PARENT);
- dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len);
+ dchild = lookup_one_len(argp->name, dirfhp->fh_path.dentry, argp->len);
if (IS_ERR(dchild)) {
nfserr = nfserrno(PTR_ERR(dchild));
goto out_unlock;
@@ -254,14 +243,14 @@ nfsd_proc_create(struct svc_rqst *rqstp,
* whether the file exists or not. Time to bail ...
*/
nfserr = nfserr_acces;
- if (!newfhp->fh_dentry) {
+ if (!newfhp->fh_path.dentry) {
printk(KERN_WARNING
"nfsd_proc_create: file handle not verified\n");
goto out_unlock;
}
}
- inode = newfhp->fh_dentry->d_inode;
+ inode = newfhp->fh_path.dentry->d_inode;
/* Unfudge the mode bits */
if (attr->ia_valid & ATTR_MODE) {
@@ -286,9 +275,10 @@ nfsd_proc_create(struct svc_rqst *rqstp,
* echo thing > device-special-file-or-pipe
* by doing a CREATE with type==0
*/
- nfserr = nfsd_permission(newfhp->fh_export,
- newfhp->fh_dentry,
- MAY_WRITE|MAY_LOCAL_ACCESS);
+ nfserr = nfsd_permission(
+ newfhp->fh_export,
+ newfhp->fh_path.dentry,
+ MAY_WRITE|MAY_LOCAL_ACCESS);
if (nfserr && nfserr != nfserr_rofs)
goto out_unlock;
}
@@ -448,7 +438,7 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp,
dprintk("nfsd: MKDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
- if (resp->fh.fh_dentry) {
+ if (resp->fh.fh_path.dentry) {
printk(KERN_WARNING
"nfsd_proc_mkdir: response already verified??\n");
}
Index: linux-2.6/fs/nfsd/nfsxdr.c
===================================================================
--- linux-2.6.orig/fs/nfsd/nfsxdr.c
+++ linux-2.6/fs/nfsd/nfsxdr.c
@@ -150,7 +150,7 @@ static __be32 *
encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
struct kstat *stat)
{
- struct dentry *dentry = fhp->fh_dentry;
+ struct dentry *dentry = fhp->fh_path.dentry;
int type;
struct timespec time;
@@ -193,11 +193,8 @@ encode_fattr(struct svc_rqst *rqstp, __b
__be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
{
struct kstat stat;
- struct path path;
- path.mnt = fhp->fh_export->ex_mnt;
- path.dentry = fhp->fh_dentry;
- vfs_getattr(&path, &stat);
+ vfs_getattr(&fhp->fh_path, &stat);
return encode_fattr(rqstp, p, fhp, &stat);
}
Index: linux-2.6/fs/nfsd/vfs.c
===================================================================
--- linux-2.6.orig/fs/nfsd/vfs.c
+++ linux-2.6/fs/nfsd/vfs.c
@@ -165,7 +165,7 @@ nfsd_lookup(struct svc_rqst *rqstp, stru
if (err)
return err;
- dparent = fhp->fh_dentry;
+ dparent = fhp->fh_path.dentry;
exp = fhp->fh_export;
exp_get(exp);
@@ -268,7 +268,7 @@ nfsd_setattr(struct svc_rqst *rqstp, str
if (err)
goto out;
- dentry = fhp->fh_dentry;
+ dentry = fhp->fh_path.dentry;
inode = dentry->d_inode;
/* Ignore any mode updates on symlinks */
@@ -438,7 +438,7 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqst
if (error)
goto out;
- dentry = fhp->fh_dentry;
+ dentry = fhp->fh_path.dentry;
inode = dentry->d_inode;
if (S_ISDIR(inode->i_mode))
flags = NFS4_ACL_DIR;
@@ -588,7 +588,7 @@ nfsd_access(struct svc_rqst *rqstp, stru
goto out;
export = fhp->fh_export;
- dentry = fhp->fh_dentry;
+ dentry = fhp->fh_path.dentry;
if (S_ISREG(dentry->d_inode->i_mode))
map = nfs3_regaccess;
@@ -659,7 +659,7 @@ nfsd_open(struct svc_rqst *rqstp, struct
if (err)
goto out;
- dentry = fhp->fh_dentry;
+ dentry = fhp->fh_path.dentry;
inode = dentry->d_inode;
/* Disallow write access to files with the append-only bit set
@@ -1016,7 +1016,7 @@ nfsd_read(struct svc_rqst *rqstp, struct
__be32 err;
if (file) {
- err = nfsd_permission(fhp->fh_export, fhp->fh_dentry,
+ err = nfsd_permission(fhp->fh_export, fhp->fh_path.dentry,
MAY_READ|MAY_OWNER_OVERRIDE);
if (err)
goto out;
@@ -1045,7 +1045,7 @@ nfsd_write(struct svc_rqst *rqstp, struc
__be32 err = 0;
if (file) {
- err = nfsd_permission(fhp->fh_export, fhp->fh_dentry,
+ err = nfsd_permission(fhp->fh_export, fhp->fh_path.dentry,
MAY_WRITE|MAY_OWNER_OVERRIDE);
if (err)
goto out;
@@ -1128,7 +1128,7 @@ nfsd_create(struct svc_rqst *rqstp, stru
if (err)
goto out;
- dentry = fhp->fh_dentry;
+ dentry = fhp->fh_path.dentry;
dirp = dentry->d_inode;
err = nfserr_notdir;
@@ -1138,7 +1138,7 @@ nfsd_create(struct svc_rqst *rqstp, stru
* Check whether the response file handle has been verified yet.
* If it has, the parent directory should already be locked.
*/
- if (!resfhp->fh_dentry) {
+ if (!resfhp->fh_path.dentry) {
/* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */
fh_lock_nested(fhp, I_MUTEX_PARENT);
dchild = lookup_one_len(fname, dentry, flen);
@@ -1150,7 +1150,7 @@ nfsd_create(struct svc_rqst *rqstp, stru
goto out;
} else {
/* called from nfsd_proc_create */
- dchild = dget(resfhp->fh_dentry);
+ dchild = dget(resfhp->fh_path.dentry);
if (!fhp->fh_locked) {
/* not actually possible */
printk(KERN_ERR
@@ -1258,7 +1258,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, s
if (err)
goto out;
- dentry = fhp->fh_dentry;
+ dentry = fhp->fh_path.dentry;
dirp = dentry->d_inode;
/* Get all the sanity checks out of the way before
@@ -1391,7 +1391,7 @@ nfsd_readlink(struct svc_rqst *rqstp, st
if (err)
goto out;
- dentry = fhp->fh_dentry;
+ dentry = fhp->fh_path.dentry;
inode = dentry->d_inode;
err = nfserr_inval;
@@ -1446,7 +1446,7 @@ nfsd_symlink(struct svc_rqst *rqstp, str
if (err)
goto out;
fh_lock(fhp);
- dentry = fhp->fh_dentry;
+ dentry = fhp->fh_path.dentry;
dnew = lookup_one_len(fname, dentry, flen);
host_err = PTR_ERR(dnew);
if (IS_ERR(dnew))
@@ -1516,7 +1516,7 @@ nfsd_link(struct svc_rqst *rqstp, struct
goto out;
fh_lock_nested(ffhp, I_MUTEX_PARENT);
- ddir = ffhp->fh_dentry;
+ ddir = ffhp->fh_path.dentry;
dirp = ddir->d_inode;
dnew = lookup_one_len(name, ddir, len);
@@ -1524,7 +1524,7 @@ nfsd_link(struct svc_rqst *rqstp, struct
if (IS_ERR(dnew))
goto out_nfserr;
- dold = tfhp->fh_dentry;
+ dold = tfhp->fh_path.dentry;
dest = dold->d_inode;
host_err = vfs_link(dold, dirp, dnew);
@@ -1572,10 +1572,10 @@ nfsd_rename(struct svc_rqst *rqstp, stru
if (err)
goto out;
- fdentry = ffhp->fh_dentry;
+ fdentry = ffhp->fh_path.dentry;
fdir = fdentry->d_inode;
- tdentry = tfhp->fh_dentry;
+ tdentry = tfhp->fh_path.dentry;
tdir = tdentry->d_inode;
err = (rqstp->rq_vers == 2) ? nfserr_acces : nfserr_xdev;
@@ -1668,7 +1668,7 @@ nfsd_unlink(struct svc_rqst *rqstp, stru
goto out;
fh_lock_nested(fhp, I_MUTEX_PARENT);
- dentry = fhp->fh_dentry;
+ dentry = fhp->fh_path.dentry;
dirp = dentry->d_inode;
rdentry = lookup_one_len(fname, dentry, flen);
@@ -1765,7 +1765,7 @@ __be32
nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat)
{
__be32 err = fh_verify(rqstp, fhp, 0, MAY_NOP);
- if (!err && vfs_statfs(fhp->fh_dentry,stat))
+ if (!err && vfs_statfs(fhp->fh_path.dentry,stat))
err = nfserr_io;
return err;
}
@@ -1904,7 +1904,7 @@ nfsd_racache_init(int cache_size)
struct posix_acl *
nfsd_get_posix_acl(struct svc_fh *fhp, int type)
{
- struct inode *inode = fhp->fh_dentry->d_inode;
+ struct inode *inode = fhp->fh_path.dentry->d_inode;
char *name;
void *value = NULL;
ssize_t size;
@@ -1924,7 +1924,7 @@ nfsd_get_posix_acl(struct svc_fh *fhp, i
return ERR_PTR(-EOPNOTSUPP);
}
- size = nfsd_getxattr(fhp->fh_dentry, name, &value);
+ size = nfsd_getxattr(fhp->fh_path.dentry, name, &value);
if (size < 0)
return ERR_PTR(size);
@@ -1936,7 +1936,7 @@ nfsd_get_posix_acl(struct svc_fh *fhp, i
int
nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl)
{
- struct inode *inode = fhp->fh_dentry->d_inode;
+ struct inode *inode = fhp->fh_path.dentry->d_inode;
char *name;
void *value = NULL;
size_t size;
@@ -1969,12 +1969,12 @@ nfsd_set_posix_acl(struct svc_fh *fhp, i
size = 0;
if (size)
- error = vfs_setxattr(fhp->fh_dentry, name, value, size, 0);
+ error = vfs_setxattr(fhp->fh_path.dentry, name, value, size, 0);
else {
if (!S_ISDIR(inode->i_mode) && type == ACL_TYPE_DEFAULT)
error = 0;
else {
- error = vfs_removexattr(fhp->fh_dentry, name);
+ error = vfs_removexattr(fhp->fh_path.dentry, name);
if (error == -ENODATA)
error = 0;
}
Index: linux-2.6/include/linux/nfsd/nfsfh.h
===================================================================
--- linux-2.6.orig/include/linux/nfsd/nfsfh.h
+++ linux-2.6/include/linux/nfsd/nfsfh.h
@@ -134,7 +134,7 @@ static inline ino_t u32_to_ino_t(__u32 u
*/
typedef struct svc_fh {
struct knfsd_fh fh_handle; /* FH data */
- struct dentry * fh_dentry; /* validated dentry */
+ struct path fh_path; /* validated path */
struct svc_export * fh_export; /* export pointer */
int fh_maxsize; /* max size for fh_handle */
@@ -217,7 +217,7 @@ void fh_put(struct svc_fh *);
static __inline__ struct svc_fh *
fh_copy(struct svc_fh *dst, struct svc_fh *src)
{
- WARN_ON(src->fh_dentry || src->fh_locked);
+ WARN_ON(src->fh_path.dentry || src->fh_locked);
*dst = *src;
return dst;
@@ -240,7 +240,7 @@ fill_pre_wcc(struct svc_fh *fhp)
{
struct inode *inode;
- inode = fhp->fh_dentry->d_inode;
+ inode = fhp->fh_path.dentry->d_inode;
if (!fhp->fh_pre_saved) {
fhp->fh_pre_mtime = inode->i_mtime;
fhp->fh_pre_ctime = inode->i_ctime;
@@ -255,7 +255,7 @@ fill_pre_wcc(struct svc_fh *fhp)
static inline void
fill_post_wcc(struct svc_fh *fhp)
{
- struct inode *inode = fhp->fh_dentry->d_inode;
+ struct inode *inode = fhp->fh_path.dentry->d_inode;
if (fhp->fh_post_saved)
printk("nfsd: inode locked twice during operation.\n");
@@ -290,7 +290,7 @@ fill_post_wcc(struct svc_fh *fhp)
static inline void
fh_lock_nested(struct svc_fh *fhp, unsigned int subclass)
{
- struct dentry *dentry = fhp->fh_dentry;
+ struct dentry *dentry = fhp->fh_path.dentry;
struct inode *inode;
dfprintk(FILEOP, "nfsd: fh_lock(%s) locked = %d\n",
@@ -322,11 +322,11 @@ fh_lock(struct svc_fh *fhp)
static inline void
fh_unlock(struct svc_fh *fhp)
{
- BUG_ON(!fhp->fh_dentry);
+ BUG_ON(!fhp->fh_path.dentry);
if (fhp->fh_locked) {
fill_post_wcc(fhp);
- mutex_unlock(&fhp->fh_dentry->d_inode->i_mutex);
+ mutex_unlock(&fhp->fh_path.dentry->d_inode->i_mutex);
fhp->fh_locked = 0;
}
}
Index: linux-2.6/include/linux/nfsd/xdr4.h
===================================================================
--- linux-2.6.orig/include/linux/nfsd/xdr4.h
+++ linux-2.6/include/linux/nfsd/xdr4.h
@@ -433,7 +433,7 @@ int nfs4svc_encode_compoundres(struct sv
void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *);
void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op);
__be32 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
- struct dentry *dentry, __be32 *buffer, int *countp,
+ struct path *path, __be32 *buffer, int *countp,
u32 *bmval, struct svc_rqst *);
extern __be32 nfsd4_setclientid(struct svc_rqst *rqstp,
struct nfsd4_compound_state *,

View file

@ -1,91 +0,0 @@
Index: linux-2.6/include/linux/security.h
===================================================================
--- linux-2.6.orig/include/linux/security.h
+++ linux-2.6/include/linux/security.h
@@ -361,8 +361,7 @@ struct request_sock;
* Return 0 if permission is granted.
* @inode_getattr:
* Check permission before obtaining file attributes.
- * @mnt is the vfsmount where the dentry was looked up
- * @dentry contains the dentry structure for the file.
+ * @path contains the vfsmount and dentry of the file.
* Return 0 if permission is granted.
* @inode_delete:
* @inode contains the inode structure for deleted inode.
@@ -1221,7 +1220,7 @@ struct security_operations {
int (*inode_follow_link) (struct dentry *dentry, struct nameidata *nd);
int (*inode_permission) (struct inode *inode, int mask, struct nameidata *nd);
int (*inode_setattr) (struct dentry *dentry, struct iattr *attr);
- int (*inode_getattr) (struct vfsmount *mnt, struct dentry *dentry);
+ int (*inode_getattr) (struct path *path);
void (*inode_delete) (struct inode *inode);
int (*inode_setxattr) (struct dentry *dentry, char *name, void *value,
size_t size, int flags);
@@ -1713,12 +1712,11 @@ static inline int security_inode_setattr
return security_ops->inode_setattr (dentry, attr);
}
-static inline int security_inode_getattr (struct vfsmount *mnt,
- struct dentry *dentry)
+static inline int security_inode_getattr (struct path *path)
{
- if (unlikely (IS_PRIVATE (dentry->d_inode)))
+ if (unlikely (IS_PRIVATE (path->dentry->d_inode)))
return 0;
- return security_ops->inode_getattr (mnt, dentry);
+ return security_ops->inode_getattr (path);
}
static inline void security_inode_delete (struct inode *inode)
@@ -2414,8 +2412,7 @@ static inline int security_inode_setattr
return 0;
}
-static inline int security_inode_getattr (struct vfsmount *mnt,
- struct dentry *dentry)
+static inline int security_inode_getattr (struct path *path)
{
return 0;
}
Index: linux-2.6/security/dummy.c
===================================================================
--- linux-2.6.orig/security/dummy.c
+++ linux-2.6/security/dummy.c
@@ -333,7 +333,7 @@ static int dummy_inode_setattr (struct d
return 0;
}
-static int dummy_inode_getattr (struct vfsmount *mnt, struct dentry *dentry)
+static int dummy_inode_getattr (struct path *path)
{
return 0;
}
Index: linux-2.6/security/selinux/hooks.c
===================================================================
--- linux-2.6.orig/security/selinux/hooks.c
+++ linux-2.6/security/selinux/hooks.c
@@ -2243,9 +2243,9 @@ static int selinux_inode_setattr(struct
return dentry_has_perm(current, NULL, dentry, FILE__WRITE);
}
-static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
+static int selinux_inode_getattr(struct path *path)
{
- return dentry_has_perm(current, mnt, dentry, FILE__GETATTR);
+ return dentry_has_perm(current, path->mnt, path->dentry, FILE__GETATTR);
}
static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value, size_t size, int flags)
Index: linux-2.6/fs/stat.c
===================================================================
--- linux-2.6.orig/fs/stat.c
+++ linux-2.6/fs/stat.c
@@ -43,7 +43,7 @@ int vfs_getattr(struct path *path, struc
struct inode *inode = path->dentry->d_inode;
int retval;
- retval = security_inode_getattr(path->mnt, path->dentry);
+ retval = security_inode_getattr(path);
if (retval)
return retval;

View file

@ -1,241 +0,0 @@
Index: linux-2.6/drivers/block/loop.c
===================================================================
--- linux-2.6.orig/drivers/block/loop.c
+++ linux-2.6/drivers/block/loop.c
@@ -1000,7 +1000,7 @@ loop_get_status(struct loop_device *lo,
if (lo->lo_state != Lo_bound)
return -ENXIO;
- error = vfs_getattr(file->f_path.mnt, file->f_path.dentry, &stat);
+ error = vfs_getattr(&file->f_path, &stat);
if (error)
return error;
memset(info, 0, sizeof(*info));
Index: linux-2.6/fs/gfs2/ops_fstype.c
===================================================================
--- linux-2.6.orig/fs/gfs2/ops_fstype.c
+++ linux-2.6/fs/gfs2/ops_fstype.c
@@ -827,7 +827,7 @@ static struct super_block* get_gfs2_sb(c
dev_name);
goto out;
}
- error = vfs_getattr(nd.path.mnt, nd.path.dentry, &stat);
+ error = vfs_getattr(&nd.path, &stat);
fstype = get_fs_type("gfs2");
list_for_each(l, &fstype->fs_supers) {
Index: linux-2.6/fs/nfsd/nfs3proc.c
===================================================================
--- linux-2.6.orig/fs/nfsd/nfs3proc.c
+++ linux-2.6/fs/nfsd/nfs3proc.c
@@ -58,6 +58,7 @@ nfsd3_proc_getattr(struct svc_rqst *rqst
{
int err;
__be32 nfserr;
+ struct path path;
dprintk("nfsd: GETATTR(3) %s\n",
SVCFH_fmt(&argp->fh));
@@ -67,8 +68,9 @@ nfsd3_proc_getattr(struct svc_rqst *rqst
if (nfserr)
RETURN_STATUS(nfserr);
- err = vfs_getattr(resp->fh.fh_export->ex_mnt,
- resp->fh.fh_dentry, &resp->stat);
+ path.mnt = resp->fh.fh_export->ex_mnt;
+ path.dentry = resp->fh.fh_dentry;
+ err = vfs_getattr(&path, &resp->stat);
nfserr = nfserrno(err);
RETURN_STATUS(nfserr);
Index: linux-2.6/fs/nfsd/nfs3xdr.c
===================================================================
--- linux-2.6.orig/fs/nfsd/nfs3xdr.c
+++ linux-2.6/fs/nfsd/nfs3xdr.c
@@ -223,12 +223,15 @@ encode_saved_post_attr(struct svc_rqst *
static __be32 *
encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
{
- struct dentry *dentry = fhp->fh_dentry;
- if (dentry && dentry->d_inode != NULL) {
+ struct path path;
+
+ path.dentry = fhp->fh_dentry;
+ if (path.dentry && path.dentry->d_inode != NULL) {
int err;
struct kstat stat;
- err = vfs_getattr(fhp->fh_export->ex_mnt, dentry, &stat);
+ path.mnt = fhp->fh_export->ex_mnt;
+ err = vfs_getattr(&path, &stat);
if (!err) {
*p++ = xdr_one; /* attributes follow */
return encode_fattr3(rqstp, p, fhp, &stat);
Index: linux-2.6/fs/nfsd/nfs4xdr.c
===================================================================
--- linux-2.6.orig/fs/nfsd/nfs4xdr.c
+++ linux-2.6/fs/nfsd/nfs4xdr.c
@@ -1442,6 +1442,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
int err;
int aclsupport = 0;
struct nfs4_acl *acl = NULL;
+ struct path path;
BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1);
BUG_ON(bmval0 & ~NFSD_SUPPORTED_ATTRS_WORD0);
@@ -1453,7 +1454,9 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
goto out;
}
- err = vfs_getattr(exp->ex_mnt, dentry, &stat);
+ path.mnt = exp->ex_mnt;
+ path.dentry = dentry;
+ err = vfs_getattr(&path, &stat);
if (err)
goto out_nfserr;
if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL)) ||
Index: linux-2.6/fs/nfsd/nfsproc.c
===================================================================
--- linux-2.6.orig/fs/nfsd/nfsproc.c
+++ linux-2.6/fs/nfsd/nfsproc.c
@@ -39,18 +39,25 @@ nfsd_proc_null(struct svc_rqst *rqstp, v
static __be32
nfsd_return_attrs(__be32 err, struct nfsd_attrstat *resp)
{
- if (err) return err;
- return nfserrno(vfs_getattr(resp->fh.fh_export->ex_mnt,
- resp->fh.fh_dentry,
- &resp->stat));
+ struct path path;
+
+ if (err)
+ return err;
+ path.mnt = resp->fh.fh_export->ex_mnt;
+ path.dentry = resp->fh.fh_dentry;
+ return nfserrno(vfs_getattr(&path, &resp->stat));
}
+
static __be32
nfsd_return_dirop(__be32 err, struct nfsd_diropres *resp)
{
- if (err) return err;
- return nfserrno(vfs_getattr(resp->fh.fh_export->ex_mnt,
- resp->fh.fh_dentry,
- &resp->stat));
+ struct path path;
+
+ if (err)
+ return err;
+ path.mnt = resp->fh.fh_export->ex_mnt;
+ path.dentry = resp->fh.fh_dentry;
+ return nfserrno(vfs_getattr(&path, &resp->stat));
}
/*
* Get a file's attributes
@@ -136,6 +143,7 @@ static __be32
nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp,
struct nfsd_readres *resp)
{
+ struct path path;
__be32 nfserr;
dprintk("nfsd: READ %s %d bytes at %d\n",
@@ -162,10 +170,11 @@ nfsd_proc_read(struct svc_rqst *rqstp, s
rqstp->rq_vec, argp->vlen,
&resp->count);
- if (nfserr) return nfserr;
- return nfserrno(vfs_getattr(resp->fh.fh_export->ex_mnt,
- resp->fh.fh_dentry,
- &resp->stat));
+ if (nfserr)
+ return nfserr;
+ path.mnt = resp->fh.fh_export->ex_mnt;
+ path.dentry = resp->fh.fh_dentry;
+ return nfserrno(vfs_getattr(&path, &resp->stat));
}
/*
Index: linux-2.6/fs/nfsd/nfsxdr.c
===================================================================
--- linux-2.6.orig/fs/nfsd/nfsxdr.c
+++ linux-2.6/fs/nfsd/nfsxdr.c
@@ -193,7 +193,11 @@ encode_fattr(struct svc_rqst *rqstp, __b
__be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
{
struct kstat stat;
- vfs_getattr(fhp->fh_export->ex_mnt, fhp->fh_dentry, &stat);
+ struct path path;
+
+ path.mnt = fhp->fh_export->ex_mnt;
+ path.dentry = fhp->fh_dentry;
+ vfs_getattr(&path, &stat);
return encode_fattr(rqstp, p, fhp, &stat);
}
Index: linux-2.6/fs/stat.c
===================================================================
--- linux-2.6.orig/fs/stat.c
+++ linux-2.6/fs/stat.c
@@ -38,17 +38,17 @@ void generic_fillattr(struct inode *inod
EXPORT_SYMBOL(generic_fillattr);
-int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+int vfs_getattr(struct path *path, struct kstat *stat)
{
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = path->dentry->d_inode;
int retval;
- retval = security_inode_getattr(mnt, dentry);
+ retval = security_inode_getattr(path->mnt, path->dentry);
if (retval)
return retval;
if (inode->i_op->getattr)
- return inode->i_op->getattr(mnt, dentry, stat);
+ return inode->i_op->getattr(path->mnt, path->dentry, stat);
generic_fillattr(inode, stat);
return 0;
@@ -63,7 +63,7 @@ int vfs_stat_fd(int dfd, char __user *na
error = __user_walk_fd(dfd, name, LOOKUP_FOLLOW, &nd);
if (!error) {
- error = vfs_getattr(nd.path.mnt, nd.path.dentry, stat);
+ error = vfs_getattr(&nd.path, stat);
path_release(&nd);
}
return error;
@@ -83,7 +83,7 @@ int vfs_lstat_fd(int dfd, char __user *n
error = __user_walk_fd(dfd, name, 0, &nd);
if (!error) {
- error = vfs_getattr(nd.path.mnt, nd.path.dentry, stat);
+ error = vfs_getattr(&nd.path, stat);
path_release(&nd);
}
return error;
@@ -102,7 +102,7 @@ int vfs_fstat(unsigned int fd, struct ks
int error = -EBADF;
if (f) {
- error = vfs_getattr(f->f_path.mnt, f->f_path.dentry, stat);
+ error = vfs_getattr(&f->f_path, stat);
fput(f);
}
return error;
Index: linux-2.6/include/linux/fs.h
===================================================================
--- linux-2.6.orig/include/linux/fs.h
+++ linux-2.6/include/linux/fs.h
@@ -1825,7 +1825,7 @@ extern int page_symlink(struct inode *in
extern struct inode_operations page_symlink_inode_operations;
extern int generic_readlink(struct dentry *, char __user *, int);
extern void generic_fillattr(struct inode *, struct kstat *);
-extern int vfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
+extern int vfs_getattr(struct path *, struct kstat *);
void inode_add_bytes(struct inode *inode, loff_t bytes);
void inode_sub_bytes(struct inode *inode, loff_t bytes);
loff_t inode_get_bytes(struct inode *inode);

View file

@ -1,51 +0,0 @@
From: Andreas Gruenbacher <agruen@suse.de>
Subject: Switch to vfs_permission() in sys_fchdir()
Switch from file_permission() to vfs_permission() in sys_fchdir(): this
avoids calling permission() with a NULL nameidata here.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
fs/open.c | 16 +++++++---------
1 file changed, 7 insertions(+), 9 deletions(-)
--- a/fs/open.c
+++ b/fs/open.c
@@ -501,10 +501,8 @@ out:
asmlinkage long sys_fchdir(unsigned int fd)
{
+ struct nameidata nd;
struct file *file;
- struct dentry *dentry;
- struct inode *inode;
- struct vfsmount *mnt;
int error;
error = -EBADF;
@@ -512,17 +510,17 @@ asmlinkage long sys_fchdir(unsigned int
if (!file)
goto out;
- dentry = file->f_path.dentry;
- mnt = file->f_path.mnt;
- inode = dentry->d_inode;
+ nd.dentry = file->f_path.dentry;
+ nd.mnt = file->f_path.mnt;
+ nd.flags = 0;
error = -ENOTDIR;
- if (!S_ISDIR(inode->i_mode))
+ if (!S_ISDIR(nd.dentry->d_inode->i_mode))
goto out_putf;
- error = file_permission(file, MAY_EXEC);
+ error = vfs_permission(&nd, MAY_EXEC);
if (!error)
- set_fs_pwd(current->fs, mnt, dentry);
+ set_fs_pwd(current->fs, nd.mnt, nd.dentry);
out_putf:
fput(file);
out:

View file

@ -1,111 +0,0 @@
From: Andreas Gruenbacher <agruen@suse.de>
Subject: Factor out sysctl pathname code
Convert the selinux sysctl pathname computation code into a standalone
function.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
Reviewed-by: James Morris <jmorris@namei.org>
---
include/linux/sysctl.h | 2 ++
kernel/sysctl.c | 27 +++++++++++++++++++++++++++
security/selinux/hooks.c | 35 +++++------------------------------
3 files changed, 34 insertions(+), 30 deletions(-)
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -983,6 +983,8 @@ extern int proc_doulongvec_minmax(struct
extern int proc_doulongvec_ms_jiffies_minmax(struct ctl_table *table, int,
struct file *, void __user *, size_t *, loff_t *);
+extern char *sysctl_pathname(ctl_table *, char *, int);
+
extern int do_sysctl (int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen);
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1327,6 +1327,33 @@ struct ctl_table_header *sysctl_head_nex
return NULL;
}
+char *sysctl_pathname(ctl_table *table, char *buffer, int buflen)
+{
+ if (buflen < 1)
+ return NULL;
+ buffer += --buflen;
+ *buffer = '\0';
+
+ while (table) {
+ int namelen = strlen(table->procname);
+
+ if (buflen < namelen + 1)
+ return NULL;
+ buflen -= namelen + 1;
+ buffer -= namelen;
+ memcpy(buffer, table->procname, namelen);
+ *--buffer = '/';
+ table = table->parent;
+ }
+ if (buflen < 4)
+ return NULL;
+ buffer -= 4;
+ memcpy(buffer, "/sys", 4);
+
+ return buffer;
+}
+EXPORT_SYMBOL(sysctl_pathname);
+
#ifdef CONFIG_SYSCTL_SYSCALL
int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1431,40 +1431,15 @@ static int selinux_capable(struct task_s
static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid)
{
- int buflen, rc;
- char *buffer, *path, *end;
+ char *buffer, *path;
+ int rc = -ENOMEM;
- rc = -ENOMEM;
buffer = (char*)__get_free_page(GFP_KERNEL);
if (!buffer)
goto out;
-
- buflen = PAGE_SIZE;
- end = buffer+buflen;
- *--end = '\0';
- buflen--;
- path = end-1;
- *path = '/';
- while (table) {
- const char *name = table->procname;
- size_t namelen = strlen(name);
- buflen -= namelen + 1;
- if (buflen < 0)
- goto out_free;
- end -= namelen;
- memcpy(end, name, namelen);
- *--end = '/';
- path = end;
- table = table->parent;
- }
- buflen -= 4;
- if (buflen < 0)
- goto out_free;
- end -= 4;
- memcpy(end, "/sys", 4);
- path = end;
- rc = security_genfs_sid("proc", path, tclass, sid);
-out_free:
+ path = sysctl_pathname(table, buffer, PAGE_SIZE);
+ if (path)
+ rc = security_genfs_sid("proc", path, tclass, sid);
free_page((unsigned long)buffer);
out:
return rc;

View file

@ -1,268 +0,0 @@
From: Andreas Gruenbacher <agruen@suse.de>
Subject: 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. This patch fixes that; if a process was in directory
/foo/bar and /foo got lazily unmounted, the old result was ``foobar'' (note the
missing slash), while the new result with this patch is ``foo/bar''.
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. We need an
unambiguous result for AppArmor at least though, so we make sure that paths
will only start with a slash if the path leads all the way up to the root.
We also add a @fail_deleted argument, which allows to get rid of some of the
mess in sys_getcwd().
This patch leaves getcwd() and d_path() as they were before for everything
except for bind-mounted directories; for them, it reports ``/foo/bar'' instead
of ``foobar'' in the example described above.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
Acked-by: Alan Cox <alan@lxorguk.ukuu.org.uk>
---
fs/dcache.c | 169 ++++++++++++++++++++++++++++++++++--------------------------
1 file changed, 98 insertions(+), 71 deletions(-)
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1764,52 +1764,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 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,
+ * then if @fail_deleted is true, ERR_PTR(-ENOENT) is returned. Otherwise,
* 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)
+{
+ int namelen, is_slash;
+
+ if (buflen < 2)
+ return ERR_PTR(-ENAMETOOLONG);
+ buffer += --buflen;
+ *buffer = '\0';
- *--end = '\0';
- buflen--;
+ spin_lock(&dcache_lock);
if (!IS_ROOT(dentry) && d_unhashed(dentry)) {
- buflen -= 10;
- end -= 10;
- if (buflen < 0)
+ if (fail_deleted) {
+ buffer = ERR_PTR(-ENOENT);
+ goto out;
+ }
+ if (buflen < 10)
goto Elong;
- memcpy(end, " (deleted)", 10);
+ buflen -= 10;
+ buffer -= 10;
+ memcpy(buffer, " (deleted)", 10);
}
-
- if (buflen < 1)
- goto Elong;
- /* Get '/' right */
- retval = end-1;
- *retval = '/';
-
- for (;;) {
+ while (dentry != root || vfsmnt != rootmnt) {
struct dentry * parent;
- if (dentry == root && vfsmnt == rootmnt)
- break;
if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
- /* Global root? */
spin_lock(&vfsmount_lock);
if (vfsmnt->mnt_parent == vfsmnt) {
spin_unlock(&vfsmount_lock);
@@ -1823,33 +1822,72 @@ 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 + 1)
goto Elong;
- end -= namelen;
- memcpy(end, dentry->d_name.name, namelen);
- *--end = '/';
- retval = end;
+ buflen -= namelen + 1;
+ buffer -= namelen;
+ memcpy(buffer, dentry->d_name.name, namelen);
+ *--buffer = '/';
dentry = parent;
}
+ /* Get '/' right. */
+ if (*buffer != '/')
+ *--buffer = '/';
- return retval;
+out:
+ spin_unlock(&dcache_lock);
+ return buffer;
global_root:
+ /*
+ * 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)
+ 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)
+ goto out;
+ }
+ if (buflen < namelen)
goto Elong;
- retval -= namelen-1; /* hit the slash */
- memcpy(retval, dentry->d_name.name, namelen);
- return retval;
+ buffer -= namelen;
+ memcpy(buffer, dentry->d_name.name, namelen);
+ goto out;
+
Elong:
- return ERR_PTR(-ENAMETOOLONG);
+ buffer = ERR_PTR(-ENAMETOOLONG);
+ goto out;
+}
+
+static char *__connect_d_path(char *path, char *buffer)
+{
+ if (!IS_ERR(path) && *path != '/') {
+ /* Pretend that disconnected paths are hanging off the root. */
+ if (path == buffer)
+ path = ERR_PTR(-ENAMETOOLONG);
+ else
+ *--path = '/';
+ }
+ return path;
}
/* write full pathname into buffer and return start of pathname */
-char * d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
- char *buf, int buflen)
+char *d_path(struct dentry *dentry, struct vfsmount *vfsmnt, char *buf,
+ int buflen)
{
char *res;
struct vfsmount *rootmnt;
@@ -1869,9 +1907,8 @@ char * d_path(struct dentry *dentry, str
rootmnt = mntget(current->fs->rootmnt);
root = dget(current->fs->root);
read_unlock(&current->fs->lock);
- spin_lock(&dcache_lock);
- res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen);
- spin_unlock(&dcache_lock);
+ res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen, 0);
+ res = __connect_d_path(res, buf);
dput(root);
mntput(rootmnt);
return res;
@@ -1918,10 +1955,10 @@ char *dynamic_dname(struct dentry *dentr
*/
asmlinkage long sys_getcwd(char __user *buf, unsigned long size)
{
- int error;
+ int error, len;
struct vfsmount *pwdmnt, *rootmnt;
struct dentry *pwd, *root;
- char *page = (char *) __get_free_page(GFP_USER);
+ char *page = (char *) __get_free_page(GFP_USER), *cwd;
if (!page)
return -ENOMEM;
@@ -1933,29 +1970,19 @@ asmlinkage long sys_getcwd(char __user *
root = dget(current->fs->root);
read_unlock(&current->fs->lock);
- error = -ENOENT;
- /* Has the current directory has been unlinked? */
- spin_lock(&dcache_lock);
- if (pwd->d_parent == pwd || !d_unhashed(pwd)) {
- unsigned long len;
- char * cwd;
-
- cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE);
- spin_unlock(&dcache_lock);
-
- error = PTR_ERR(cwd);
- if (IS_ERR(cwd))
- goto out;
-
- error = -ERANGE;
- len = PAGE_SIZE + page - cwd;
- if (len <= size) {
- error = len;
- if (copy_to_user(buf, cwd, len))
- error = -EFAULT;
- }
- } else
- spin_unlock(&dcache_lock);
+ cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE, 1);
+ cwd = __connect_d_path(cwd, page);
+ error = PTR_ERR(cwd);
+ if (IS_ERR(cwd))
+ goto out;
+
+ error = -ERANGE;
+ len = PAGE_SIZE + page - cwd;
+ if (len <= size) {
+ error = len;
+ if (copy_to_user(buf, cwd, len))
+ error = -EFAULT;
+ }
out:
dput(pwd);

View file

@ -1,190 +0,0 @@
From: Tony Jones <tonyj@suse.de>
Subject: Add a struct vfsmount parameter to vfs_getxattr()
The vfsmount will be passed down to the LSM hook so that LSMs can compute
pathnames.
Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
fs/nfsd/nfs4xdr.c | 2 +-
fs/nfsd/vfs.c | 21 ++++++++++++---------
fs/xattr.c | 14 ++++++++------
include/linux/nfsd/nfsd.h | 3 ++-
include/linux/xattr.h | 3 ++-
5 files changed, 25 insertions(+), 18 deletions(-)
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1496,7 +1496,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
}
if (bmval0 & (FATTR4_WORD0_ACL | FATTR4_WORD0_ACLSUPPORT
| FATTR4_WORD0_SUPPORTED_ATTRS)) {
- err = nfsd4_get_nfs4_acl(rqstp, dentry, &acl);
+ err = nfsd4_get_nfs4_acl(rqstp, dentry, exp->ex_mnt, &acl);
aclsupport = (err == 0);
if (bmval0 & FATTR4_WORD0_ACL) {
if (err == -EOPNOTSUPP)
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -408,11 +408,12 @@ out_nfserr:
#if defined(CONFIG_NFSD_V2_ACL) || \
defined(CONFIG_NFSD_V3_ACL) || \
defined(CONFIG_NFSD_V4)
-static ssize_t nfsd_getxattr(struct dentry *dentry, char *key, void **buf)
+static ssize_t nfsd_getxattr(struct dentry *dentry, struct vfsmount *mnt,
+ char *key, void **buf)
{
ssize_t buflen;
- buflen = vfs_getxattr(dentry, key, NULL, 0);
+ buflen = vfs_getxattr(dentry, mnt, key, NULL, 0);
if (buflen <= 0)
return buflen;
@@ -420,7 +421,7 @@ static ssize_t nfsd_getxattr(struct dent
if (!*buf)
return -ENOMEM;
- return vfs_getxattr(dentry, key, *buf, buflen);
+ return vfs_getxattr(dentry, mnt, key, *buf, buflen);
}
#endif
@@ -501,13 +502,13 @@ out_nfserr:
}
static struct posix_acl *
-_get_posix_acl(struct dentry *dentry, char *key)
+_get_posix_acl(struct dentry *dentry, struct vfsmount *mnt, char *key)
{
void *buf = NULL;
struct posix_acl *pacl = NULL;
int buflen;
- buflen = nfsd_getxattr(dentry, key, &buf);
+ buflen = nfsd_getxattr(dentry, mnt, key, &buf);
if (!buflen)
buflen = -ENODATA;
if (buflen <= 0)
@@ -519,14 +520,15 @@ _get_posix_acl(struct dentry *dentry, ch
}
int
-nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_acl **acl)
+nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry,
+ struct vfsmount *mnt, struct nfs4_acl **acl)
{
struct inode *inode = dentry->d_inode;
int error = 0;
struct posix_acl *pacl = NULL, *dpacl = NULL;
unsigned int flags = 0;
- pacl = _get_posix_acl(dentry, POSIX_ACL_XATTR_ACCESS);
+ pacl = _get_posix_acl(dentry, mnt, POSIX_ACL_XATTR_ACCESS);
if (IS_ERR(pacl) && PTR_ERR(pacl) == -ENODATA)
pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
if (IS_ERR(pacl)) {
@@ -536,7 +538,7 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqst
}
if (S_ISDIR(inode->i_mode)) {
- dpacl = _get_posix_acl(dentry, POSIX_ACL_XATTR_DEFAULT);
+ dpacl = _get_posix_acl(dentry, mnt, POSIX_ACL_XATTR_DEFAULT);
if (IS_ERR(dpacl) && PTR_ERR(dpacl) == -ENODATA)
dpacl = NULL;
else if (IS_ERR(dpacl)) {
@@ -2001,7 +2003,8 @@ nfsd_get_posix_acl(struct svc_fh *fhp, i
return ERR_PTR(-EOPNOTSUPP);
}
- size = nfsd_getxattr(fhp->fh_dentry, name, &value);
+ size = nfsd_getxattr(fhp->fh_dentry, fhp->fh_export->ex_mnt, name,
+ &value);
if (size < 0)
return ERR_PTR(size);
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -105,7 +105,8 @@ out:
EXPORT_SYMBOL_GPL(vfs_setxattr);
ssize_t
-vfs_getxattr(struct dentry *dentry, char *name, void *value, size_t size)
+vfs_getxattr(struct dentry *dentry, struct vfsmount *mnt, char *name,
+ void *value, size_t size)
{
struct inode *inode = dentry->d_inode;
int error;
@@ -277,7 +278,8 @@ sys_fsetxattr(int fd, char __user *name,
* Extended attribute GET operations
*/
static ssize_t
-getxattr(struct dentry *d, char __user *name, void __user *value, size_t size)
+getxattr(struct dentry *dentry, struct vfsmount *mnt, char __user *name,
+ void __user *value, size_t size)
{
ssize_t error;
void *kvalue = NULL;
@@ -297,7 +299,7 @@ getxattr(struct dentry *d, char __user *
return -ENOMEM;
}
- error = vfs_getxattr(d, kname, kvalue, size);
+ error = vfs_getxattr(dentry, mnt, kname, kvalue, size);
if (error > 0) {
if (size && copy_to_user(value, kvalue, error))
error = -EFAULT;
@@ -320,7 +322,7 @@ sys_getxattr(char __user *path, char __u
error = user_path_walk(path, &nd);
if (error)
return error;
- error = getxattr(nd.dentry, name, value, size);
+ error = getxattr(nd.dentry, nd.mnt, name, value, size);
path_release(&nd);
return error;
}
@@ -335,7 +337,7 @@ sys_lgetxattr(char __user *path, char __
error = user_path_walk_link(path, &nd);
if (error)
return error;
- error = getxattr(nd.dentry, name, value, size);
+ error = getxattr(nd.dentry, nd.mnt, name, value, size);
path_release(&nd);
return error;
}
@@ -350,7 +352,7 @@ sys_fgetxattr(int fd, char __user *name,
if (!f)
return error;
audit_inode(NULL, f->f_path.dentry);
- error = getxattr(f->f_path.dentry, name, value, size);
+ error = getxattr(f->f_path.dentry, f->f_path.mnt, name, value, size);
fput(f);
return error;
}
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -79,7 +79,8 @@ __be32 nfsd_setattr(struct svc_rqst *,
#ifdef CONFIG_NFSD_V4
__be32 nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *,
struct nfs4_acl *);
-int nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **);
+int nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *,
+ struct vfsmount *mnt, struct nfs4_acl **);
#endif /* CONFIG_NFSD_V4 */
__be32 nfsd_create(struct svc_rqst *, struct svc_fh *,
char *name, int len, struct iattr *attrs,
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -46,7 +46,8 @@ struct xattr_handler {
size_t size, int flags);
};
-ssize_t vfs_getxattr(struct dentry *, char *, void *, size_t);
+ssize_t vfs_getxattr(struct dentry *, struct vfsmount *, char *, void *,
+ size_t);
ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size);
int vfs_setxattr(struct dentry *, struct vfsmount *, char *, void *, size_t,
int);

View file

@ -1,90 +0,0 @@
From: Tony Jones <tonyj@suse.de>
Subject: Add struct vfsmount parameters to vfs_link()
The vfsmount will be passed down to the LSM hook so that LSMs can compute
pathnames.
Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
fs/ecryptfs/inode.c | 9 +++++++--
fs/namei.c | 5 +++--
fs/nfsd/vfs.c | 3 ++-
include/linux/fs.h | 2 +-
4 files changed, 13 insertions(+), 6 deletions(-)
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -402,19 +402,24 @@ static int ecryptfs_link(struct dentry *
struct dentry *new_dentry)
{
struct dentry *lower_old_dentry;
+ struct vfsmount *lower_old_mnt;
struct dentry *lower_new_dentry;
+ struct vfsmount *lower_new_mnt;
struct dentry *lower_dir_dentry;
u64 file_size_save;
int rc;
file_size_save = i_size_read(old_dentry->d_inode);
lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry);
+ lower_old_mnt = ecryptfs_dentry_to_lower_mnt(old_dentry);
lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry);
+ lower_new_mnt = ecryptfs_dentry_to_lower_mnt(new_dentry);
dget(lower_old_dentry);
dget(lower_new_dentry);
lower_dir_dentry = lock_parent(lower_new_dentry);
- rc = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode,
- lower_new_dentry);
+ rc = vfs_link(lower_old_dentry, lower_old_mnt,
+ lower_dir_dentry->d_inode, lower_new_dentry,
+ lower_new_mnt);
if (rc || !lower_new_dentry->d_inode)
goto out_lock;
rc = ecryptfs_interpose(lower_new_dentry, new_dentry, dir->i_sb, 0);
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2331,7 +2331,7 @@ asmlinkage long sys_symlink(const char _
return sys_symlinkat(oldname, AT_FDCWD, newname);
}
-int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
+int vfs_link(struct dentry *old_dentry, struct vfsmount *old_mnt, struct inode *dir, struct dentry *new_dentry, struct vfsmount *new_mnt)
{
struct inode *inode = old_dentry->d_inode;
int error;
@@ -2409,7 +2409,8 @@ asmlinkage long sys_linkat(int olddfd, c
error = PTR_ERR(new_dentry);
if (IS_ERR(new_dentry))
goto out_unlock;
- error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry);
+ error = vfs_link(old_nd.dentry, old_nd.mnt, nd.dentry->d_inode,
+ new_dentry, nd.mnt);
dput(new_dentry);
out_unlock:
mutex_unlock(&nd.dentry->d_inode->i_mutex);
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1589,7 +1589,8 @@ nfsd_link(struct svc_rqst *rqstp, struct
dold = tfhp->fh_dentry;
dest = dold->d_inode;
- host_err = vfs_link(dold, dirp, dnew);
+ host_err = vfs_link(dold, tfhp->fh_export->ex_mnt, dirp,
+ dnew, ffhp->fh_export->ex_mnt);
if (!host_err) {
if (EX_ISSYNC(ffhp->fh_export)) {
err = nfserrno(nfsd_sync_dir(ddir));
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1071,7 +1071,7 @@ extern int vfs_create(struct inode *, st
extern int vfs_mkdir(struct inode *, struct dentry *, struct vfsmount *, int);
extern int vfs_mknod(struct inode *, struct dentry *, struct vfsmount *, int, dev_t);
extern int vfs_symlink(struct inode *, struct dentry *, struct vfsmount *, const char *, int);
-extern int vfs_link(struct dentry *, struct inode *, struct dentry *);
+extern int vfs_link(struct dentry *, struct vfsmount *, struct inode *, struct dentry *, struct vfsmount *);
extern int vfs_rmdir(struct inode *, struct dentry *);
extern int vfs_unlink(struct inode *, struct dentry *);
extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);

View file

@ -1,102 +0,0 @@
From: Tony Jones <tonyj@suse.de>
Subject: Add a struct vfsmount parameter to vfs_listxattr()
The vfsmount will be passed down to the LSM hook so that LSMs can compute
pathnames.
Signed-off-by: Tony Jones <tonyj@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
fs/xattr.c | 25 ++++++++++++++-----------
include/linux/xattr.h | 3 ++-
2 files changed, 16 insertions(+), 12 deletions(-)
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -142,18 +142,20 @@ vfs_getxattr(struct dentry *dentry, stru
EXPORT_SYMBOL_GPL(vfs_getxattr);
ssize_t
-vfs_listxattr(struct dentry *d, char *list, size_t size)
+vfs_listxattr(struct dentry *dentry, struct vfsmount *mnt, char *list,
+ size_t size)
{
+ struct inode *inode = dentry->d_inode;
ssize_t error;
- error = security_inode_listxattr(d);
+ error = security_inode_listxattr(dentry);
if (error)
return error;
error = -EOPNOTSUPP;
- if (d->d_inode->i_op && d->d_inode->i_op->listxattr) {
- error = d->d_inode->i_op->listxattr(d, list, size);
- } else {
- error = security_inode_listsecurity(d->d_inode, list, size);
+ if (inode->i_op && inode->i_op->listxattr)
+ error = inode->i_op->listxattr(dentry, list, size);
+ else {
+ error = security_inode_listsecurity(inode, list, size);
if (size && error > size)
error = -ERANGE;
}
@@ -361,7 +363,8 @@ sys_fgetxattr(int fd, char __user *name,
* Extended attribute LIST operations
*/
static ssize_t
-listxattr(struct dentry *d, char __user *list, size_t size)
+listxattr(struct dentry *dentry, struct vfsmount *mnt, char __user *list,
+ size_t size)
{
ssize_t error;
char *klist = NULL;
@@ -374,7 +377,7 @@ listxattr(struct dentry *d, char __user
return -ENOMEM;
}
- error = vfs_listxattr(d, klist, size);
+ error = vfs_listxattr(dentry, mnt, klist, size);
if (error > 0) {
if (size && copy_to_user(list, klist, error))
error = -EFAULT;
@@ -396,7 +399,7 @@ sys_listxattr(char __user *path, char __
error = user_path_walk(path, &nd);
if (error)
return error;
- error = listxattr(nd.dentry, list, size);
+ error = listxattr(nd.dentry, nd.mnt, list, size);
path_release(&nd);
return error;
}
@@ -410,7 +413,7 @@ sys_llistxattr(char __user *path, char _
error = user_path_walk_link(path, &nd);
if (error)
return error;
- error = listxattr(nd.dentry, list, size);
+ error = listxattr(nd.dentry, nd.mnt, list, size);
path_release(&nd);
return error;
}
@@ -425,7 +428,7 @@ sys_flistxattr(int fd, char __user *list
if (!f)
return error;
audit_inode(NULL, f->f_path.dentry);
- error = listxattr(f->f_path.dentry, list, size);
+ error = listxattr(f->f_path.dentry, f->f_path.mnt, list, size);
fput(f);
return error;
}
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -48,7 +48,8 @@ struct xattr_handler {
ssize_t vfs_getxattr(struct dentry *, struct vfsmount *, char *, void *,
size_t);
-ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size);
+ssize_t vfs_listxattr(struct dentry *d, struct vfsmount *, char *list,
+ size_t size);
int vfs_setxattr(struct dentry *, struct vfsmount *, char *, void *, size_t,
int);
int vfs_removexattr(struct dentry *, char *);

Some files were not shown because too many files have changed in this diff Show more