mirror of
https://gitlab.com/apparmor/apparmor.git
synced 2025-03-04 08:24:42 +01:00
remove for-mainline dir from kernel patches
This commit is contained in:
parent
446f3fc533
commit
ffa6034243
119 changed files with 0 additions and 26841 deletions
|
@ -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(¤t->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(¤t->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.. */
|
|
@ -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;
|
|
@ -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);
|
|
@ -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;
|
|
@ -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");
|
|
@ -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,
|
|
@ -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";
|
|
@ -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;
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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);
|
|
@ -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");
|
|
@ -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
|
@ -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)) {
|
|
@ -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)
|
||||
{
|
|
@ -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];
|
|
@ -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 :-)
|
||||
+
|
||||
+
|
|
@ -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);
|
|
@ -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;
|
||||
|
|
@ -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) {
|
|
@ -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)
|
|
@ -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(¤t->fs->lock);
|
||||
+ rootmnt = mntget(current->fs->rootmnt);
|
||||
+ read_unlock(¤t->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 */
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
|
@ -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
|
|
@ -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)
|
||||
|
|
@ -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 {
|
|
@ -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);
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
|
@ -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 */
|
|
@ -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(¤t->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);
|
|
@ -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
|
|
@ -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);
|
|
@ -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(¤t->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;
|
|
@ -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;
|
||||
}
|
|
@ -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,
|
|
@ -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;
|
||||
|
|
@ -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)
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
|
@ -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[] = {
|
|
@ -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) {
|
|
@ -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");
|
|
@ -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) */
|
||||
|
|
@ -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));
|
|
@ -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
|
|
@ -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)
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
|
@ -1,3 +0,0 @@
|
|||
obj-$(CONFIG_SECURITY_FOOBAR) += foobar.o
|
||||
|
||||
foobar-y := foobar-lsm.o
|
|
@ -1 +0,0 @@
|
|||
obj-m += foobar.o
|
|
@ -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");
|
|
@ -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)
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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
|
@ -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;
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
|
|
@ -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;
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
|
@ -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);
|
|
@ -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);
|
|
@ -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
|
|
@ -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);
|
|
@ -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
|
@ -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");
|
|
@ -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
|
|
@ -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;
|
|
@ -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
|
|
@ -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 *);
|
File diff suppressed because it is too large
Load diff
|
@ -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 *,
|
|
@ -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;
|
||||
|
|
@ -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);
|
|
@ -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:
|
|
@ -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;
|
|
@ -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(¤t->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(¤t->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);
|
|
@ -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);
|
|
@ -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 *);
|
|
@ -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
Loading…
Add table
Reference in a new issue