mirror of
https://github.com/vincentmli/bpfire.git
synced 2026-04-13 04:22:58 +02:00
Added missing SuSE-Xen-Patches.
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
From: Jeff Mahoney <jeffm@suse.com>
|
||||
Subject: [PATCH] vfs: introduce path_permission()
|
||||
|
||||
2.6.27 eliminated the nameidata parameter from permission and replaced
|
||||
several call sites with inode_permission. This keeps the information
|
||||
required by AppArmor from reaching it.
|
||||
|
||||
The following patch factors out the permission assessment part of
|
||||
inode_permission into __inode_permission and adds a path_permission
|
||||
function that takes a struct path instead of a struct inode and passes
|
||||
it to security_path_permission instead of security_inode_permission.
|
||||
|
||||
All of the call sites that had access to a struct path whether by
|
||||
itself or via a file or nameidata (and used it) in 2.6.26 are changed
|
||||
to use the path_permission call.
|
||||
|
||||
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
|
||||
---
|
||||
fs/inotify_user.c | 2 +-
|
||||
fs/namei.c | 32 ++++++++++++++++++++++++--------
|
||||
fs/open.c | 10 +++++-----
|
||||
include/linux/fs.h | 5 +++++
|
||||
4 files changed, 35 insertions(+), 14 deletions(-)
|
||||
|
||||
--- a/fs/inotify_user.c
|
||||
+++ b/fs/inotify_user.c
|
||||
@@ -372,7 +372,7 @@ static int find_inode(const char __user
|
||||
if (error)
|
||||
return error;
|
||||
/* you can only watch an inode if you have read permissions on it */
|
||||
- error = inode_permission(path->dentry->d_inode, MAY_READ);
|
||||
+ error = path_permission(path, MAY_READ);
|
||||
if (error)
|
||||
path_put(path);
|
||||
return error;
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -227,7 +227,7 @@ int generic_permission(struct inode *ino
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
-int inode_permission(struct inode *inode, int mask)
|
||||
+static int __inode_permission(struct inode *inode, int mask)
|
||||
{
|
||||
int retval;
|
||||
int submask = mask;
|
||||
@@ -273,7 +273,12 @@ int inode_permission(struct inode *inode
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
- retval = devcgroup_inode_permission(inode, mask);
|
||||
+ return devcgroup_inode_permission(inode, mask);
|
||||
+}
|
||||
+
|
||||
+int inode_permission(struct inode *inode, int mask)
|
||||
+{
|
||||
+ int retval = __inode_permission(inode, mask);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
@@ -281,6 +286,15 @@ int inode_permission(struct inode *inode
|
||||
mask & (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND));
|
||||
}
|
||||
|
||||
+int path_permission(struct path *path, int mask)
|
||||
+{
|
||||
+ int retval = __inode_permission(path->dentry->d_inode, mask);
|
||||
+ if (retval)
|
||||
+ return retval;
|
||||
+ return security_path_permission(path,
|
||||
+ mask & (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND));
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* vfs_permission - check for access rights to a given path
|
||||
* @nd: lookup result that describes the path
|
||||
@@ -293,7 +307,7 @@ int inode_permission(struct inode *inode
|
||||
*/
|
||||
int vfs_permission(struct nameidata *nd, int mask)
|
||||
{
|
||||
- return inode_permission(nd->path.dentry->d_inode, mask);
|
||||
+ return path_permission(&nd->path, mask);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -310,7 +324,7 @@ int vfs_permission(struct nameidata *nd,
|
||||
*/
|
||||
int file_permission(struct file *file, int mask)
|
||||
{
|
||||
- return inode_permission(file->f_path.dentry->d_inode, mask);
|
||||
+ return path_permission(&file->f_path, mask);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -452,8 +466,9 @@ static struct dentry * cached_lookup(str
|
||||
* short-cut DAC fails, then call permission() to do more
|
||||
* complete permission check.
|
||||
*/
|
||||
-static int exec_permission_lite(struct inode *inode)
|
||||
+static int exec_permission_lite(struct path *path)
|
||||
{
|
||||
+ struct inode *inode = path->dentry->d_inode;
|
||||
umode_t mode = inode->i_mode;
|
||||
|
||||
if (inode->i_op && inode->i_op->permission)
|
||||
@@ -478,7 +493,7 @@ static int exec_permission_lite(struct i
|
||||
|
||||
return -EACCES;
|
||||
ok:
|
||||
- return security_inode_permission(inode, MAY_EXEC);
|
||||
+ return security_path_permission(path, MAY_EXEC);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -875,7 +890,7 @@ static int __link_path_walk(const char *
|
||||
unsigned int c;
|
||||
|
||||
nd->flags |= LOOKUP_CONTINUE;
|
||||
- err = exec_permission_lite(inode);
|
||||
+ err = exec_permission_lite(&nd->path);
|
||||
if (err == -EAGAIN)
|
||||
err = vfs_permission(nd, MAY_EXEC);
|
||||
if (err)
|
||||
@@ -1250,7 +1265,7 @@ static struct dentry *lookup_hash(struct
|
||||
{
|
||||
int err;
|
||||
|
||||
- err = inode_permission(nd->path.dentry->d_inode, MAY_EXEC);
|
||||
+ err = path_permission(&nd->path, MAY_EXEC);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
return __lookup_hash(&nd->last, nd->path.dentry, nd);
|
||||
@@ -2907,6 +2922,7 @@ EXPORT_SYMBOL(page_symlink_inode_operati
|
||||
EXPORT_SYMBOL(path_lookup);
|
||||
EXPORT_SYMBOL(vfs_path_lookup);
|
||||
EXPORT_SYMBOL(inode_permission);
|
||||
+EXPORT_SYMBOL(path_permission);
|
||||
EXPORT_SYMBOL(vfs_permission);
|
||||
EXPORT_SYMBOL(file_permission);
|
||||
EXPORT_SYMBOL(unlock_rename);
|
||||
--- a/fs/open.c
|
||||
+++ b/fs/open.c
|
||||
@@ -248,7 +248,7 @@ static long do_sys_truncate(const char _
|
||||
if (error)
|
||||
goto dput_and_out;
|
||||
|
||||
- error = inode_permission(inode, MAY_WRITE);
|
||||
+ error = path_permission(&path, MAY_WRITE);
|
||||
if (error)
|
||||
goto mnt_drop_write_and_out;
|
||||
|
||||
@@ -493,7 +493,7 @@ SYSCALL_DEFINE3(faccessat, int, dfd, con
|
||||
goto out_path_release;
|
||||
}
|
||||
|
||||
- res = inode_permission(inode, mode | MAY_ACCESS);
|
||||
+ res = path_permission(&path, mode | MAY_ACCESS);
|
||||
/* SuS v2 requires we report a read only fs too */
|
||||
if (res || !(mode & S_IWOTH) || special_file(inode->i_mode))
|
||||
goto out_path_release;
|
||||
@@ -536,7 +536,7 @@ SYSCALL_DEFINE1(chdir, const char __user
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
- error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
|
||||
+ error = path_permission(&path, MAY_EXEC | MAY_ACCESS);
|
||||
if (error)
|
||||
goto dput_and_out;
|
||||
|
||||
@@ -565,7 +565,7 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd
|
||||
if (!S_ISDIR(inode->i_mode))
|
||||
goto out_putf;
|
||||
|
||||
- error = inode_permission(inode, MAY_EXEC | MAY_ACCESS);
|
||||
+ error = path_permission(&file->f_path, MAY_EXEC | MAY_ACCESS);
|
||||
if (!error)
|
||||
set_fs_pwd(current->fs, &file->f_path);
|
||||
out_putf:
|
||||
@@ -583,7 +583,7 @@ SYSCALL_DEFINE1(chroot, const char __use
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
- error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
|
||||
+ error = path_permission(&path, MAY_EXEC | MAY_ACCESS);
|
||||
if (error)
|
||||
goto dput_and_out;
|
||||
|
||||
--- a/include/linux/fs.h
|
||||
+++ b/include/linux/fs.h
|
||||
@@ -1201,6 +1201,11 @@ extern void dentry_unhash(struct dentry
|
||||
extern int file_permission(struct file *, int);
|
||||
|
||||
/*
|
||||
+ * VFS path helper functions.
|
||||
+ */
|
||||
+extern int path_permission(struct path *, int);
|
||||
+
|
||||
+/*
|
||||
* File types
|
||||
*
|
||||
* NOTE! These match bits 12..15 of stat.st_mode
|
||||
@@ -0,0 +1,47 @@
|
||||
From: John Johansen <jjohansen@suse.de>
|
||||
Subject: AppArmor: Patch AppArmor for 2.6.25 kernel
|
||||
|
||||
Add 64 bit capabilities support to AppArmor.
|
||||
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
security/apparmor/module_interface.c | 22 ++++++++++++++++++----
|
||||
1 file changed, 18 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/security/apparmor/module_interface.c
|
||||
+++ b/security/apparmor/module_interface.c
|
||||
@@ -395,15 +395,29 @@ static struct aa_profile *aa_unpack_prof
|
||||
if (!aa_is_nameX(e, AA_STRUCTEND, NULL))
|
||||
goto fail;
|
||||
|
||||
- if (!aa_is_u32(e, &(profile->capabilities), NULL))
|
||||
+ if (!aa_is_u32(e, &(profile->capabilities.cap[0]), NULL))
|
||||
goto fail;
|
||||
- if (!aa_is_u32(e, &(profile->audit_caps), NULL))
|
||||
+ if (!aa_is_u32(e, &(profile->audit_caps.cap[0]), NULL))
|
||||
goto fail;
|
||||
- if (!aa_is_u32(e, &(profile->quiet_caps), NULL))
|
||||
+ if (!aa_is_u32(e, &(profile->quiet_caps.cap[0]), NULL))
|
||||
goto fail;
|
||||
- if (!aa_is_u32(e, &(profile->set_caps), NULL))
|
||||
+ if (!aa_is_u32(e, &(profile->set_caps.cap[0]), NULL))
|
||||
goto fail;
|
||||
|
||||
+ if (aa_is_nameX(e, AA_STRUCT, "caps64")) {
|
||||
+ /* optional upper half of 64 bit caps */
|
||||
+ if (!aa_is_u32(e, &(profile->capabilities.cap[1]), NULL))
|
||||
+ goto fail;
|
||||
+ if (!aa_is_u32(e, &(profile->audit_caps.cap[1]), NULL))
|
||||
+ goto fail;
|
||||
+ if (!aa_is_u32(e, &(profile->quiet_caps.cap[1]), NULL))
|
||||
+ goto fail;
|
||||
+ if (!aa_is_u32(e, &(profile->set_caps.cap[1]), NULL))
|
||||
+ goto fail;
|
||||
+ if (!aa_is_nameX(e, AA_STRUCTEND, NULL))
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
if (!aa_unpack_rlimits(e, profile))
|
||||
goto fail;
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
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)
|
||||
@@ -119,6 +119,13 @@
|
||||
#define AUDIT_MAC_UNLBL_STCADD 1416 /* NetLabel: add a static label */
|
||||
#define AUDIT_MAC_UNLBL_STCDEL 1417 /* NetLabel: del a static label */
|
||||
|
||||
+#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 */
|
||||
@@ -545,6 +552,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
|
||||
@@ -1231,8 +1231,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;
|
||||
@@ -1506,3 +1505,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);
|
||||
@@ -0,0 +1,31 @@
|
||||
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 | 3 ++-
|
||||
2 files changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/security/Kconfig
|
||||
+++ b/security/Kconfig
|
||||
@@ -117,6 +117,7 @@ config SECURITY_DEFAULT_MMAP_MIN_ADDR
|
||||
|
||||
source security/selinux/Kconfig
|
||||
source security/smack/Kconfig
|
||||
+source security/apparmor/Kconfig
|
||||
|
||||
endmenu
|
||||
|
||||
--- a/security/Makefile
|
||||
+++ b/security/Makefile
|
||||
@@ -14,5 +14,6 @@ obj-$(CONFIG_SECURITY) += security.o c
|
||||
# Must precede capability.o in order to stack properly.
|
||||
obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
|
||||
obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o
|
||||
-obj-$(CONFIG_SECURITY_ROOTPLUG) += root_plug.o
|
||||
+obj-$(CONFIG_SECURITY_APPARMOR) += commoncap.o apparmor/
|
||||
+ obj-$(CONFIG_SECURITY_ROOTPLUG) += root_plug.o
|
||||
obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o
|
||||
910
src/patches/suse-2.6.27.25/patches.apparmor/apparmor-lsm.diff
Normal file
910
src/patches/suse-2.6.27.25/patches.apparmor/apparmor-lsm.diff
Normal file
@@ -0,0 +1,910 @@
|
||||
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 | 895 ++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 895 insertions(+)
|
||||
|
||||
--- /dev/null
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -0,0 +1,895 @@
|
||||
+/*
|
||||
+ * 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, unsigned int mode)
|
||||
+{
|
||||
+ 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 path *path, 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,
|
||||
+ const char *name, const void *value,
|
||||
+ size_t size, int flags, struct file *file)
|
||||
+{
|
||||
+ int error = cap_inode_setxattr(dentry, mnt, name, value, size, flags,
|
||||
+ file);
|
||||
+
|
||||
+ if (!error)
|
||||
+ error = aa_xattr_permission(dentry, mnt, "xattr set",
|
||||
+ MAY_WRITE, file);
|
||||
+ return error;
|
||||
+}
|
||||
+
|
||||
+static int apparmor_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const 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, const 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");
|
||||
1493
src/patches/suse-2.6.27.25/patches.apparmor/apparmor-main.diff
Normal file
1493
src/patches/suse-2.6.27.25/patches.apparmor/apparmor-main.diff
Normal file
File diff suppressed because it is too large
Load Diff
1441
src/patches/suse-2.6.27.25/patches.apparmor/apparmor-misc.diff
Normal file
1441
src/patches/suse-2.6.27.25/patches.apparmor/apparmor-misc.diff
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,408 @@
|
||||
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
|
||||
@@ -212,6 +214,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;
|
||||
@@ -258,6 +263,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;
|
||||
};
|
||||
|
||||
@@ -319,6 +325,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"
|
||||
@@ -680,6 +681,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)
|
||||
{
|
||||
@@ -780,9 +892,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,
|
||||
@@ -820,6 +929,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=");
|
||||
@@ -767,6 +806,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
|
||||
@@ -321,8 +321,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)
|
||||
@@ -355,6 +355,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)) {
|
||||
@@ -0,0 +1,55 @@
|
||||
From: Jeff Mahoney <jeffm@suse.com>
|
||||
Subject: apparmor: use new ptrace security_operations
|
||||
|
||||
This patch implements the new ptrace security_operations members.
|
||||
|
||||
->ptrace was changed to ->ptrace_may_access and ->ptrace_traceme.
|
||||
|
||||
The apparmor versions are really just wrappers for the old function.
|
||||
|
||||
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
|
||||
|
||||
---
|
||||
security/apparmor/lsm.c | 17 +++++++++++++++--
|
||||
1 file changed, 15 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/security/apparmor/lsm.c
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -158,7 +158,7 @@ static int aa_reject_syscall(struct task
|
||||
}
|
||||
|
||||
static int apparmor_ptrace(struct task_struct *parent,
|
||||
- struct task_struct *child, unsigned int mode)
|
||||
+ struct task_struct *child)
|
||||
{
|
||||
struct aa_task_context *cxt;
|
||||
int error = 0;
|
||||
@@ -207,6 +207,18 @@ static int apparmor_ptrace(struct task_s
|
||||
return error;
|
||||
}
|
||||
|
||||
+static int apparmor_ptrace_may_access(struct task_struct *child,
|
||||
+ unsigned int mode)
|
||||
+{
|
||||
+ return apparmor_ptrace(child->parent, child);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static int apparmor_ptrace_traceme(struct task_struct *parent)
|
||||
+{
|
||||
+ return apparmor_ptrace(parent, current);
|
||||
+}
|
||||
+
|
||||
static int apparmor_capable(struct task_struct *task, int cap)
|
||||
{
|
||||
int error;
|
||||
@@ -899,7 +911,8 @@ static int apparmor_task_setrlimit(unsig
|
||||
}
|
||||
|
||||
struct security_operations apparmor_ops = {
|
||||
- .ptrace = apparmor_ptrace,
|
||||
+ .ptrace_may_access = apparmor_ptrace_may_access,
|
||||
+ .ptrace_traceme = apparmor_ptrace_traceme,
|
||||
.capget = cap_capget,
|
||||
.capset_check = cap_capset_check,
|
||||
.capset_set = cap_capset_set,
|
||||
@@ -0,0 +1,461 @@
|
||||
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>
|
||||
|
||||
@@ -139,6 +140,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
|
||||
@@ -173,6 +186,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
|
||||
@@ -210,6 +225,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;
|
||||
@@ -261,6 +279,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;
|
||||
@@ -328,6 +347,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
|
||||
@@ -106,7 +106,7 @@ static ssize_t aa_features_read(struct f
|
||||
{
|
||||
const char *features = "file=3.0 capability=2.0 network=1.0 "
|
||||
"change_hat=1.5 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
|
||||
@@ -883,6 +883,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,
|
||||
@@ -926,6 +941,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;
|
||||
}
|
||||
@@ -1303,6 +1393,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);
|
||||
|
||||
@@ -1481,17 +1577,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)
|
||||
@@ -1499,8 +1596,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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1565,6 +1669,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) {
|
||||
@@ -1576,6 +1681,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;
|
||||
@@ -312,6 +328,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
|
||||
@@ -355,6 +404,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)
|
||||
@@ -614,6 +666,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
|
||||
@@ -634,6 +688,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);
|
||||
@@ -656,6 +711,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)
|
||||
{
|
||||
@@ -0,0 +1,60 @@
|
||||
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/namespace.c | 30 ++++++++++++++++++++++++++++++
|
||||
include/linux/mount.h | 2 ++
|
||||
2 files changed, 32 insertions(+)
|
||||
|
||||
--- a/fs/namespace.c
|
||||
+++ b/fs/namespace.c
|
||||
@@ -2299,3 +2299,33 @@ 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 path root, tmp, ns_root = { };
|
||||
+ struct path path = { .mnt = vfsmnt, .dentry = dentry };
|
||||
+ char *res;
|
||||
+
|
||||
+ read_lock(¤t->fs->lock);
|
||||
+ root = current->fs->root;
|
||||
+ path_get(¤t->fs->root);
|
||||
+ read_unlock(¤t->fs->lock);
|
||||
+ spin_lock(&vfsmount_lock);
|
||||
+ if (root.mnt)
|
||||
+ ns_root.mnt = mntget(root.mnt->mnt_ns->root);
|
||||
+ if (ns_root.mnt)
|
||||
+ ns_root.dentry = dget(ns_root.mnt->mnt_root);
|
||||
+ spin_unlock(&vfsmount_lock);
|
||||
+ tmp = ns_root;
|
||||
+ res = __d_path(&path, &tmp, buf, buflen,
|
||||
+ D_PATH_FAIL_DELETED | D_PATH_DISCONNECT);
|
||||
+ path_put(&root);
|
||||
+ path_put(&ns_root);
|
||||
+
|
||||
+ /* Prevent empty path for lazily unmounted filesystems. */
|
||||
+ if (!IS_ERR(res) && *res == '\0')
|
||||
+ *--res = '.';
|
||||
+ return res;
|
||||
+}
|
||||
+EXPORT_SYMBOL(d_namespace_path);
|
||||
--- a/include/linux/mount.h
|
||||
+++ b/include/linux/mount.h
|
||||
@@ -134,4 +134,6 @@ extern void mark_mounts_for_expiry(struc
|
||||
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 /* _LINUX_MOUNT_H */
|
||||
@@ -0,0 +1,25 @@
|
||||
From: Miklos Szeredi <mszeredi@suse.cz>
|
||||
Subject: fix oops in d_namespace_path
|
||||
Patch-mainline: no
|
||||
References: bnc#433504
|
||||
|
||||
d_namespace_path uses the current->fs->root to get the current
|
||||
namespace. If root is detached root.mnt->mnt_ns will be NULL, causing
|
||||
an Oops. Fix by checking this before dereferencing the mnt_ns.
|
||||
|
||||
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
|
||||
---
|
||||
fs/namespace.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/fs/namespace.c
|
||||
+++ b/fs/namespace.c
|
||||
@@ -2312,7 +2312,7 @@ char *d_namespace_path(struct dentry *de
|
||||
path_get(¤t->fs->root);
|
||||
read_unlock(¤t->fs->lock);
|
||||
spin_lock(&vfsmount_lock);
|
||||
- if (root.mnt)
|
||||
+ if (root.mnt && root.mnt->mnt_ns)
|
||||
ns_root.mnt = mntget(root.mnt->mnt_ns->root);
|
||||
if (ns_root.mnt)
|
||||
ns_root.dentry = dget(ns_root.mnt->mnt_root);
|
||||
@@ -0,0 +1,42 @@
|
||||
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 | 7 ++-----
|
||||
1 file changed, 2 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -1085,24 +1085,21 @@ static int do_path_lookup(int dfd, const
|
||||
path_get(&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->path = file->f_path;
|
||||
|
||||
retval = -ENOTDIR;
|
||||
- if (!S_ISDIR(dentry->d_inode->i_mode))
|
||||
+ if (!S_ISDIR(nd->path.dentry->d_inode->i_mode))
|
||||
goto fput_fail;
|
||||
|
||||
retval = file_permission(file, MAY_EXEC);
|
||||
if (retval)
|
||||
goto fput_fail;
|
||||
|
||||
- nd->path = file->f_path;
|
||||
path_get(&file->f_path);
|
||||
|
||||
fput_light(file, fput_needed);
|
||||
@@ -0,0 +1,84 @@
|
||||
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 | 5 ++++-
|
||||
2 files changed, 11 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/fs/nfsd/vfs.c
|
||||
+++ b/fs/nfsd/vfs.c
|
||||
@@ -425,7 +425,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;
|
||||
|
||||
@@ -433,7 +433,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
|
||||
|
||||
@@ -459,7 +459,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;
|
||||
@@ -2133,12 +2133,14 @@ nfsd_set_posix_acl(struct svc_fh *fhp, i
|
||||
if (error)
|
||||
goto getout;
|
||||
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
|
||||
@@ -623,7 +623,7 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd
|
||||
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);
|
||||
mnt_drop_write(file->f_path.mnt);
|
||||
@@ -686,6 +686,9 @@ 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);
|
||||
@@ -0,0 +1,26 @@
|
||||
From: John Johansen <jjohansen@suse.de>
|
||||
Subject: fix enforcement of deny rules in complain mode
|
||||
Patch-mainline: no
|
||||
References: bnc#426159
|
||||
|
||||
Fix enforcement of deny rules so that they are not enforced in complain
|
||||
mode. This is necessary so that application behavior is not changed by
|
||||
the presence of the deny rule.
|
||||
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
security/apparmor/main.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/security/apparmor/main.c
|
||||
+++ b/security/apparmor/main.c
|
||||
@@ -325,7 +325,7 @@ static int aa_audit_file(struct aa_profi
|
||||
} else {
|
||||
int mask = AUDIT_QUIET_MASK(sa->audit_mask);
|
||||
|
||||
- if (!(sa->denied_mask & ~mask))
|
||||
+ if (!(sa->denied_mask & ~mask) && !PROFILE_COMPLAIN(profile))
|
||||
return sa->error_code;
|
||||
|
||||
/* mask off perms whose denial is being silenced */
|
||||
@@ -0,0 +1,25 @@
|
||||
From: John Johansen <jrjohansen@verizon.net>
|
||||
Subject: [PATCH] AppArmor: Fix leak of filename for deleted files
|
||||
|
||||
This patch fixes a memory leak where the name doesn't get freed when
|
||||
a file has been deleted.
|
||||
|
||||
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
|
||||
---
|
||||
security/apparmor/main.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/security/apparmor/main.c
|
||||
+++ b/security/apparmor/main.c
|
||||
@@ -500,10 +500,10 @@ static char *aa_get_name(struct dentry *
|
||||
*buffer = buf;
|
||||
return name;
|
||||
}
|
||||
+ kfree(buf);
|
||||
if (PTR_ERR(name) != -ENAMETOOLONG)
|
||||
return name;
|
||||
|
||||
- kfree(buf);
|
||||
size <<= 1;
|
||||
if (size > apparmor_path_max)
|
||||
return ERR_PTR(-ENAMETOOLONG);
|
||||
@@ -0,0 +1,66 @@
|
||||
From: John Johansen <jjohansen@suse.de>
|
||||
Subject: fix recognition of security= boot parameter
|
||||
Patch-mainline: no
|
||||
References: bnc#442668
|
||||
|
||||
Fix AppArmor to respect the kernel boot parameter security=, so that if a
|
||||
different lsm is choosen apparmor does not try to register its lsm hooks.
|
||||
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
security/Kconfig | 9 +++++++++
|
||||
security/apparmor/lsm.c | 5 +++--
|
||||
security/security.c | 2 +-
|
||||
3 files changed, 13 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/security/Kconfig
|
||||
+++ b/security/Kconfig
|
||||
@@ -51,6 +51,15 @@ config SECURITY
|
||||
|
||||
If you are unsure how to answer this question, answer N.
|
||||
|
||||
+config SECURITY_DEFAULT
|
||||
+ string "Default security module"
|
||||
+ depends on SECURITY
|
||||
+ default ""
|
||||
+ help
|
||||
+ This determines the security module used if the security=
|
||||
+ boot parmater is not provided. If a security module is not
|
||||
+ specified the first module to register will be used.
|
||||
+
|
||||
config SECURITY_NETWORK
|
||||
bool "Socket and Networking Security Hooks"
|
||||
depends on SECURITY
|
||||
--- a/security/apparmor/lsm.c
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -911,6 +911,7 @@ static int apparmor_task_setrlimit(unsig
|
||||
}
|
||||
|
||||
struct security_operations apparmor_ops = {
|
||||
+ .name = "apparmor",
|
||||
.ptrace_may_access = apparmor_ptrace_may_access,
|
||||
.ptrace_traceme = apparmor_ptrace_traceme,
|
||||
.capget = cap_capget,
|
||||
@@ -989,8 +990,8 @@ static int __init apparmor_init(void)
|
||||
{
|
||||
int error;
|
||||
|
||||
- if (!apparmor_enabled) {
|
||||
- info_message("AppArmor disabled by boottime parameter\n");
|
||||
+ if (!apparmor_enabled || !security_module_enable(&apparmor_ops)) {
|
||||
+ info_message("AppArmor disabled by boot time parameter\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <linux/security.h>
|
||||
|
||||
/* Boot-time LSM user choice */
|
||||
-static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1];
|
||||
+static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] = CONFIG_SECURITY_DEFAULT;
|
||||
|
||||
/* things that live in capability.c */
|
||||
extern struct security_operations default_security_ops;
|
||||
@@ -0,0 +1,44 @@
|
||||
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
|
||||
@@ -2177,6 +2177,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);
|
||||
@@ -2184,12 +2188,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) {
|
||||
108
src/patches/suse-2.6.27.25/patches.apparmor/fork-tracking.diff
Normal file
108
src/patches/suse-2.6.27.25/patches.apparmor/fork-tracking.diff
Normal file
@@ -0,0 +1,108 @@
|
||||
From: John Johansen <jjohansen@suse.de>
|
||||
Subject: fix log messages to enable tools profile learning
|
||||
Patch-mainline: no
|
||||
References: bnc#447564
|
||||
|
||||
The allocation of the child pid is done after the LSM clone hook, which
|
||||
breaks the AppArmor tools fork tracking, for profiles learning. Output
|
||||
the parent pid with each log message to enable the tools to handle fork
|
||||
tracking.
|
||||
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
security/apparmor/lsm.c | 28 ----------------------------
|
||||
security/apparmor/main.c | 10 +++++-----
|
||||
security/apparmor/module_interface.c | 2 +-
|
||||
3 files changed, 6 insertions(+), 34 deletions(-)
|
||||
|
||||
--- a/security/apparmor/lsm.c
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -143,20 +143,6 @@ static int param_set_aa_enabled(const ch
|
||||
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)
|
||||
{
|
||||
@@ -292,17 +278,6 @@ static int apparmor_bprm_secureexec(stru
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static int apparmor_sb_mount(char *dev_name, struct path *path, 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)
|
||||
{
|
||||
@@ -925,9 +900,6 @@ struct security_operations apparmor_ops
|
||||
.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,
|
||||
--- a/security/apparmor/main.c
|
||||
+++ b/security/apparmor/main.c
|
||||
@@ -229,9 +229,13 @@ static int aa_audit_base(struct aa_profi
|
||||
audit_log_format(ab, " protocol=%d", sa->protocol);
|
||||
}
|
||||
|
||||
- audit_log_format(ab, " pid=%d", current->pid);
|
||||
+ audit_log_format(ab, " pid=%d", current->pid);
|
||||
|
||||
if (profile) {
|
||||
+ if (!sa->parent)
|
||||
+ audit_log_format(ab, " parent=%d",
|
||||
+ current->real_parent->pid);
|
||||
+
|
||||
audit_log_format(ab, " profile=");
|
||||
audit_log_untrustedstring(ab, profile->name);
|
||||
|
||||
@@ -1006,10 +1010,6 @@ repeat:
|
||||
|
||||
unlock_profile(profile);
|
||||
|
||||
- if (APPARMOR_COMPLAIN(child_cxt) &&
|
||||
- profile == profile->ns->null_complain_profile) {
|
||||
- aa_audit_hint(profile, &sa);
|
||||
- }
|
||||
aa_put_profile(profile);
|
||||
} else
|
||||
aa_free_task_context(child_cxt);
|
||||
--- a/security/apparmor/module_interface.c
|
||||
+++ b/security/apparmor/module_interface.c
|
||||
@@ -126,7 +126,7 @@ static int aa_is_nameX(struct aa_ext *e,
|
||||
* AA_NAME tag value is a u16.
|
||||
*/
|
||||
if (aa_is_X(e, AA_NAME)) {
|
||||
- char *tag;
|
||||
+ char *tag = NULL;
|
||||
size_t size = aa_is_u16_chunk(e, &tag);
|
||||
/* if a name is specified it must match. otherwise skip tag */
|
||||
if (name && (!size || strcmp(name, tag)))
|
||||
@@ -0,0 +1,28 @@
|
||||
From: John Johansen <jjohansen@suse.de>
|
||||
Subject: AppArmor: reintroduce ATTR_FILE
|
||||
|
||||
The fsetattr patch removed ATTR_FILE but AppArmor needs it to distinguish
|
||||
file based writes.
|
||||
|
||||
Note: Now that LSMs must be static, it would be better to add a file
|
||||
pointer argument to security_operations->inode_setattr() instead. Then
|
||||
move the fs.h chunk to patches.apparmor/fsetattr-restore-ia_file. -jeffm
|
||||
|
||||
Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||
|
||||
---
|
||||
fs/open.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
--- a/fs/open.c
|
||||
+++ b/fs/open.c
|
||||
@@ -208,6 +208,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);
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
From: Jeff Mahoney <jeffm@suse.com>
|
||||
Subject: [PATCH] vfs: restore ia_file for compatibility with external modules
|
||||
References: bnc#381259
|
||||
|
||||
patches.apparmor/fsetattr.diff eliminated ia_file and ATTR_FILE in favor
|
||||
of providing a ->fsetattr call that used a file pointer. Until this
|
||||
patch is accepted into mainline, this patch provides the backward
|
||||
compatibility for external file system modules.
|
||||
|
||||
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
|
||||
---
|
||||
fs/attr.c | 13 ++++++++++++-
|
||||
include/linux/fs.h | 11 +++++++++++
|
||||
2 files changed, 23 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/fs/attr.c
|
||||
+++ b/fs/attr.c
|
||||
@@ -168,8 +168,19 @@ int fnotify_change(struct dentry *dentry
|
||||
if (!error) {
|
||||
if (file && file->f_op && file->f_op->fsetattr)
|
||||
error = file->f_op->fsetattr(file, attr);
|
||||
- else
|
||||
+ else {
|
||||
+ /* External file system still expect to be
|
||||
+ * passed a file pointer via ia_file and
|
||||
+ * have it announced via ATTR_FILE. This
|
||||
+ * just makes it so they don't need to
|
||||
+ * change their API just for us. External
|
||||
+ * callers will have set these themselves. */
|
||||
+ if (file) {
|
||||
+ attr->ia_valid |= ATTR_FILE;
|
||||
+ attr->ia_file = file;
|
||||
+ }
|
||||
error = inode->i_op->setattr(dentry, attr);
|
||||
+ }
|
||||
}
|
||||
} else {
|
||||
error = inode_change_ok(inode, attr);
|
||||
--- a/include/linux/fs.h
|
||||
+++ b/include/linux/fs.h
|
||||
@@ -367,6 +367,17 @@ 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).
|
||||
+ *
|
||||
+ * NOTE: With patches.apparmor/fsetattr.diff applied, this is
|
||||
+ * for compatibility with external file system modules only. There
|
||||
+ * should not be any in-kernel users left.
|
||||
+ */
|
||||
+ struct file *ia_file;
|
||||
};
|
||||
|
||||
/*
|
||||
414
src/patches/suse-2.6.27.25/patches.apparmor/fsetattr.diff
Normal file
414
src/patches/suse-2.6.27.25/patches.apparmor/fsetattr.diff
Normal file
@@ -0,0 +1,414 @@
|
||||
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 | 19 +++++++++++++++----
|
||||
fs/fuse/dir.c | 20 +++++++++-----------
|
||||
fs/fuse/file.c | 7 +++++++
|
||||
fs/fuse/fuse_i.h | 4 ++++
|
||||
fs/open.c | 20 ++++++++------------
|
||||
fs/utimes.c | 9 +++++----
|
||||
include/linux/fs.h | 9 ++-------
|
||||
11 files changed, 68 insertions(+), 42 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
|
||||
@@ -358,7 +358,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;
|
||||
@@ -380,8 +381,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)) {
|
||||
@@ -391,10 +392,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
|
||||
@@ -548,6 +548,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;
|
||||
@@ -165,8 +165,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)
|
||||
@@ -188,5 +192,12 @@ int notify_change(struct dentry *dentry,
|
||||
|
||||
return error;
|
||||
}
|
||||
+EXPORT_SYMBOL_GPL(fnotify_change);
|
||||
+
|
||||
+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
|
||||
@@ -1105,21 +1105,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;
|
||||
|
||||
@@ -1138,7 +1139,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;
|
||||
@@ -1199,8 +1200,8 @@ void fuse_release_nowrite(struct inode *
|
||||
* 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);
|
||||
@@ -1244,7 +1245,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;
|
||||
@@ -1314,10 +1315,7 @@ error:
|
||||
|
||||
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
|
||||
@@ -1466,6 +1466,11 @@ static loff_t fuse_file_llseek(struct fi
|
||||
return retval;
|
||||
}
|
||||
|
||||
+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 = fuse_file_llseek,
|
||||
.read = do_sync_read,
|
||||
@@ -1479,6 +1484,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,
|
||||
};
|
||||
|
||||
@@ -1492,6 +1498,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
|
||||
@@ -551,6 +551,10 @@ void fuse_truncate(struct address_space
|
||||
*/
|
||||
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
|
||||
@@ -207,16 +207,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;
|
||||
}
|
||||
@@ -625,7 +621,7 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd
|
||||
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);
|
||||
mnt_drop_write(file->f_path.mnt);
|
||||
out_putf:
|
||||
@@ -669,7 +665,7 @@ SYSCALL_DEFINE2(chmod, const char __user
|
||||
}
|
||||
|
||||
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 = dentry->d_inode;
|
||||
int error;
|
||||
@@ -688,7 +684,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);
|
||||
|
||||
return error;
|
||||
@@ -705,7 +701,7 @@ SYSCALL_DEFINE3(chown, const char __user
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (error)
|
||||
goto out_release;
|
||||
- error = chown_common(path.dentry, path.mnt, user, group);
|
||||
+ error = chown_common(path.dentry, path.mnt, user, group, NULL);
|
||||
mnt_drop_write(path.mnt);
|
||||
out_release:
|
||||
path_put(&path);
|
||||
@@ -730,7 +726,7 @@ SYSCALL_DEFINE5(fchownat, int, dfd, cons
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (error)
|
||||
goto out_release;
|
||||
- error = chown_common(path.dentry, path.mnt, user, group);
|
||||
+ error = chown_common(path.dentry, path.mnt, user, group, NULL);
|
||||
mnt_drop_write(path.mnt);
|
||||
out_release:
|
||||
path_put(&path);
|
||||
@@ -749,7 +745,7 @@ SYSCALL_DEFINE3(lchown, const char __use
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (error)
|
||||
goto out_release;
|
||||
- error = chown_common(path.dentry, path.mnt, user, group);
|
||||
+ error = chown_common(path.dentry, path.mnt, user, group, NULL);
|
||||
mnt_drop_write(path.mnt);
|
||||
out_release:
|
||||
path_put(&path);
|
||||
@@ -772,7 +768,7 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd
|
||||
goto out_fput;
|
||||
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);
|
||||
mnt_drop_write(file->f_path.mnt);
|
||||
out_fput:
|
||||
fput(file);
|
||||
--- a/fs/utimes.c
|
||||
+++ b/fs/utimes.c
|
||||
@@ -48,7 +48,8 @@ static bool nsec_valid(long nsec)
|
||||
return nsec >= 0 && nsec <= 999999999;
|
||||
}
|
||||
|
||||
-static int utimes_common(struct path *path, struct timespec *times)
|
||||
+static int utimes_common(struct path *path, struct timespec *times,
|
||||
+ struct file *f)
|
||||
{
|
||||
int error;
|
||||
struct iattr newattrs;
|
||||
@@ -102,7 +103,7 @@ static int utimes_common(struct path *pa
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
||||
mnt_drop_write_and_out:
|
||||
@@ -149,7 +150,7 @@ long do_utimes(int dfd, char __user *fil
|
||||
if (!file)
|
||||
goto out;
|
||||
|
||||
- error = utimes_common(&file->f_path, times);
|
||||
+ error = utimes_common(&file->f_path, times, file);
|
||||
fput(file);
|
||||
} else {
|
||||
struct path path;
|
||||
@@ -162,7 +163,7 @@ long do_utimes(int dfd, char __user *fil
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
- error = utimes_common(&path, times);
|
||||
+ error = utimes_common(&path, times, NULL);
|
||||
path_put(&path);
|
||||
}
|
||||
|
||||
--- a/include/linux/fs.h
|
||||
+++ b/include/linux/fs.h
|
||||
@@ -367,13 +367,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;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1280,6 +1273,7 @@ struct file_operations {
|
||||
#define HAVE_FOP_OPEN_EXEC
|
||||
int (*open_exec) (struct inode *);
|
||||
int (*setlease)(struct file *, long, struct file_lock **);
|
||||
+ int (*fsetattr)(struct file *, struct iattr *);
|
||||
};
|
||||
|
||||
struct inode_operations {
|
||||
@@ -1799,6 +1793,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 inode_permission(struct inode *, int);
|
||||
extern int generic_permission(struct inode *, int,
|
||||
int (*check_acl)(struct inode *, int));
|
||||
41
src/patches/suse-2.6.27.25/patches.apparmor/remove_suid.diff
Normal file
41
src/patches/suse-2.6.27.25/patches.apparmor/remove_suid.diff
Normal file
@@ -0,0 +1,41 @@
|
||||
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>
|
||||
|
||||
---
|
||||
|
||||
mm/filemap.c | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/mm/filemap.c
|
||||
+++ b/mm/filemap.c
|
||||
@@ -1826,12 +1826,12 @@ int should_remove_suid(struct dentry *de
|
||||
}
|
||||
EXPORT_SYMBOL(should_remove_suid);
|
||||
|
||||
-static int __remove_suid(struct dentry *dentry, int kill)
|
||||
+static 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 file_remove_suid(struct file *file)
|
||||
@@ -1846,7 +1846,7 @@ int file_remove_suid(struct file *file)
|
||||
if (killpriv)
|
||||
error = security_inode_killpriv(dentry);
|
||||
if (!error && killsuid)
|
||||
- error = __remove_suid(dentry, killsuid);
|
||||
+ error = __remove_suid(&file->f_path, killsuid);
|
||||
|
||||
return error;
|
||||
}
|
||||
107
src/patches/suse-2.6.27.25/patches.apparmor/security-create.diff
Normal file
107
src/patches/suse-2.6.27.25/patches.apparmor/security-create.diff
Normal file
@@ -0,0 +1,107 @@
|
||||
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/capability.c | 2 +-
|
||||
security/security.c | 5 +++--
|
||||
security/selinux/hooks.c | 3 ++-
|
||||
5 files changed, 13 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -1543,7 +1543,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->path.mnt : NULL, mode);
|
||||
if (error)
|
||||
return error;
|
||||
DQUOT_INIT(dir);
|
||||
--- a/include/linux/security.h
|
||||
+++ b/include/linux/security.h
|
||||
@@ -337,6 +337,7 @@ static inline void security_free_mnt_opt
|
||||
* 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:
|
||||
@@ -1354,8 +1355,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);
|
||||
@@ -1622,7 +1623,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);
|
||||
@@ -1968,6 +1970,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/capability.c
|
||||
+++ b/security/capability.c
|
||||
@@ -155,7 +155,7 @@ static int cap_inode_init_security(struc
|
||||
}
|
||||
|
||||
static int cap_inode_create(struct inode *inode, struct dentry *dentry,
|
||||
- int mask)
|
||||
+ struct vfsmount *mnt, int mask)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -358,11 +358,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
|
||||
+++ b/security/selinux/hooks.c
|
||||
@@ -2566,7 +2566,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);
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
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/capability.c | 3 ++-
|
||||
security/security.c | 5 +++--
|
||||
security/selinux/hooks.c | 3 ++-
|
||||
security/smack/smack_lsm.c | 4 +++-
|
||||
6 files changed, 18 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/fs/xattr.c
|
||||
+++ b/fs/xattr.c
|
||||
@@ -141,7 +141,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
|
||||
@@ -446,7 +446,7 @@ static inline void security_free_mnt_opt
|
||||
* @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
|
||||
@@ -1400,7 +1400,8 @@ struct security_operations {
|
||||
struct vfsmount *mnt,
|
||||
const char *name, const void *value,
|
||||
size_t size, int flags);
|
||||
- int (*inode_getxattr) (struct dentry *dentry, const char *name);
|
||||
+ int (*inode_getxattr) (struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name);
|
||||
int (*inode_listxattr) (struct dentry *dentry);
|
||||
int (*inode_removexattr) (struct dentry *dentry, const char *name);
|
||||
int (*inode_need_killpriv) (struct dentry *dentry);
|
||||
@@ -1676,7 +1677,8 @@ int security_inode_setxattr(struct dentr
|
||||
void security_inode_post_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
const char *name, const void *value,
|
||||
size_t size, int flags);
|
||||
-int security_inode_getxattr(struct dentry *dentry, const char *name);
|
||||
+int security_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name);
|
||||
int security_inode_listxattr(struct dentry *dentry);
|
||||
int security_inode_removexattr(struct dentry *dentry, const char *name);
|
||||
int security_inode_need_killpriv(struct dentry *dentry);
|
||||
@@ -2113,7 +2115,8 @@ static inline void security_inode_post_s
|
||||
{ }
|
||||
|
||||
static inline int security_inode_getxattr(struct dentry *dentry,
|
||||
- const char *name)
|
||||
+ struct vfsmount *mnt,
|
||||
+ const char *name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/capability.c
|
||||
+++ b/security/capability.c
|
||||
@@ -241,7 +241,8 @@ static void cap_inode_post_setxattr(stru
|
||||
{
|
||||
}
|
||||
|
||||
-static int cap_inode_getxattr(struct dentry *dentry, const char *name)
|
||||
+static int cap_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -491,11 +491,12 @@ void security_inode_post_setxattr(struct
|
||||
flags);
|
||||
}
|
||||
|
||||
-int security_inode_getxattr(struct dentry *dentry, const char *name)
|
||||
+int security_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const 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
|
||||
@@ -2796,7 +2796,8 @@ static void selinux_inode_post_setxattr(
|
||||
return;
|
||||
}
|
||||
|
||||
-static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
|
||||
+static int selinux_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name)
|
||||
{
|
||||
return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
|
||||
}
|
||||
--- a/security/smack/smack_lsm.c
|
||||
+++ b/security/smack/smack_lsm.c
|
||||
@@ -673,11 +673,13 @@ static void smack_inode_post_setxattr(st
|
||||
/*
|
||||
* smack_inode_getxattr - Smack check on getxattr
|
||||
* @dentry: the object
|
||||
+ * @mnt: unused
|
||||
* @name: unused
|
||||
*
|
||||
* Returns 0 if access is permitted, an error code otherwise
|
||||
*/
|
||||
-static int smack_inode_getxattr(struct dentry *dentry, const char *name)
|
||||
+static int smack_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name)
|
||||
{
|
||||
return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ);
|
||||
}
|
||||
149
src/patches/suse-2.6.27.25/patches.apparmor/security-link.diff
Normal file
149
src/patches/suse-2.6.27.25/patches.apparmor/security-link.diff
Normal file
@@ -0,0 +1,149 @@
|
||||
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 | 18 ++++++++++++------
|
||||
security/capability.c | 5 +++--
|
||||
security/security.c | 8 +++++---
|
||||
security/selinux/hooks.c | 9 +++++++--
|
||||
security/smack/smack_lsm.c | 5 +++--
|
||||
6 files changed, 32 insertions(+), 16 deletions(-)
|
||||
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -2437,7 +2437,8 @@ int vfs_link(struct dentry *old_dentry,
|
||||
if (S_ISDIR(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
|
||||
@@ -343,8 +343,10 @@ static inline void security_free_mnt_opt
|
||||
* @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.
|
||||
@@ -1362,8 +1364,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);
|
||||
@@ -1632,8 +1635,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);
|
||||
@@ -1987,8 +1991,10 @@ static inline int security_inode_create(
|
||||
}
|
||||
|
||||
static inline int security_inode_link(struct dentry *old_dentry,
|
||||
- struct inode *dir,
|
||||
- struct dentry *new_dentry)
|
||||
+ struct vfsmount *old_mnt,
|
||||
+ struct inode *dir,
|
||||
+ struct dentry *new_dentry,
|
||||
+ struct vfsmount *new_mnt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/capability.c
|
||||
+++ b/security/capability.c
|
||||
@@ -160,8 +160,9 @@ static int cap_inode_create(struct inode
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int cap_inode_link(struct dentry *old_dentry, struct inode *inode,
|
||||
- struct dentry *new_dentry)
|
||||
+static int cap_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
|
||||
@@ -366,12 +366,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
|
||||
@@ -2572,11 +2572,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);
|
||||
--- a/security/smack/smack_lsm.c
|
||||
+++ b/security/smack/smack_lsm.c
|
||||
@@ -432,8 +432,9 @@ static int smack_inode_init_security(str
|
||||
*
|
||||
* Returns 0 if access is permitted, an error code otherwise
|
||||
*/
|
||||
-static int smack_inode_link(struct dentry *old_dentry, struct inode *dir,
|
||||
- struct dentry *new_dentry)
|
||||
+static int smack_inode_link(struct dentry *old_dentry, struct vfsmount *old_mnt,
|
||||
+ struct inode *dir,
|
||||
+ struct dentry *new_dentry, struct vfsmount *new_mnt)
|
||||
{
|
||||
int rc;
|
||||
char *isp;
|
||||
@@ -0,0 +1,105 @@
|
||||
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/capability.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
|
||||
@@ -174,7 +174,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
|
||||
@@ -450,7 +450,7 @@ static inline void security_free_mnt_opt
|
||||
* 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
|
||||
@@ -1402,7 +1402,7 @@ struct security_operations {
|
||||
size_t size, int flags);
|
||||
int (*inode_getxattr) (struct dentry *dentry, struct vfsmount *mnt,
|
||||
const char *name);
|
||||
- int (*inode_listxattr) (struct dentry *dentry);
|
||||
+ int (*inode_listxattr) (struct dentry *dentry, struct vfsmount *mnt);
|
||||
int (*inode_removexattr) (struct dentry *dentry, const char *name);
|
||||
int (*inode_need_killpriv) (struct dentry *dentry);
|
||||
int (*inode_killpriv) (struct dentry *dentry);
|
||||
@@ -1679,7 +1679,7 @@ void security_inode_post_setxattr(struct
|
||||
size_t size, int flags);
|
||||
int security_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
const 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, const char *name);
|
||||
int security_inode_need_killpriv(struct dentry *dentry);
|
||||
int security_inode_killpriv(struct dentry *dentry);
|
||||
@@ -2121,7 +2121,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/capability.c
|
||||
+++ b/security/capability.c
|
||||
@@ -247,7 +247,7 @@ static int cap_inode_getxattr(struct den
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int cap_inode_listxattr(struct dentry *dentry)
|
||||
+static int cap_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -499,11 +499,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, const char *name)
|
||||
--- a/security/selinux/hooks.c
|
||||
+++ b/security/selinux/hooks.c
|
||||
@@ -2802,7 +2802,7 @@ static int selinux_inode_getxattr(struct
|
||||
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);
|
||||
}
|
||||
106
src/patches/suse-2.6.27.25/patches.apparmor/security-mkdir.diff
Normal file
106
src/patches/suse-2.6.27.25/patches.apparmor/security-mkdir.diff
Normal file
@@ -0,0 +1,106 @@
|
||||
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/capability.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
|
||||
@@ -2089,7 +2089,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
|
||||
@@ -362,6 +362,7 @@ static inline void security_free_mnt_opt
|
||||
* 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:
|
||||
@@ -1363,7 +1364,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);
|
||||
@@ -1632,7 +1634,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,
|
||||
@@ -2001,6 +2004,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/capability.c
|
||||
+++ b/security/capability.c
|
||||
@@ -178,7 +178,7 @@ static int cap_inode_symlink(struct inod
|
||||
}
|
||||
|
||||
static int cap_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
|
||||
@@ -389,11 +389,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
|
||||
@@ -2597,7 +2597,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);
|
||||
}
|
||||
124
src/patches/suse-2.6.27.25/patches.apparmor/security-mknod.diff
Normal file
124
src/patches/suse-2.6.27.25/patches.apparmor/security-mknod.diff
Normal file
@@ -0,0 +1,124 @@
|
||||
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 | 6 +++---
|
||||
include/linux/security.h | 7 +++++--
|
||||
security/capability.c | 2 +-
|
||||
security/security.c | 5 +++--
|
||||
security/selinux/hooks.c | 5 +++--
|
||||
5 files changed, 15 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -1994,7 +1994,7 @@ int vfs_mknod(struct inode *dir, struct
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
- error = security_inode_mknod(dir, dentry, mode, dev);
|
||||
+ error = security_inode_mknod(dir, dentry, mnt, mode, dev);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
@@ -2056,11 +2056,11 @@ asmlinkage long sys_mknodat(int dfd, con
|
||||
break;
|
||||
case S_IFCHR: case S_IFBLK:
|
||||
error = vfs_mknod(nd.path.dentry->d_inode, dentry,
|
||||
- nd.path, mode, new_decode_dev(dev));
|
||||
+ nd.path.mnt, mode, new_decode_dev(dev));
|
||||
break;
|
||||
case S_IFIFO: case S_IFSOCK:
|
||||
error = vfs_mknod(nd.path.dentry->d_inode, dentry,
|
||||
- nd.path, mode, 0);
|
||||
+ nd.path.mnt, mode, 0);
|
||||
break;
|
||||
}
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
--- a/include/linux/security.h
|
||||
+++ b/include/linux/security.h
|
||||
@@ -377,6 +377,7 @@ static inline void security_free_mnt_opt
|
||||
* 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.
|
||||
@@ -1368,7 +1369,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);
|
||||
@@ -1637,7 +1638,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);
|
||||
@@ -2018,6 +2020,7 @@ static inline int security_inode_rmdir(s
|
||||
|
||||
static inline int security_inode_mknod(struct inode *dir,
|
||||
struct dentry *dentry,
|
||||
+ struct vfsmount *mnt,
|
||||
int mode, dev_t dev)
|
||||
{
|
||||
return 0;
|
||||
--- a/security/capability.c
|
||||
+++ b/security/capability.c
|
||||
@@ -189,7 +189,7 @@ static int cap_inode_rmdir(struct inode
|
||||
}
|
||||
|
||||
static int cap_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
|
||||
@@ -404,11 +404,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
|
||||
@@ -2608,11 +2608,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;
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
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/capability.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
|
||||
@@ -308,7 +308,7 @@ SYSCALL_DEFINE4(readlinkat, int, dfd, co
|
||||
|
||||
error = -EINVAL;
|
||||
if (inode->i_op && inode->i_op->readlink) {
|
||||
- error = security_inode_readlink(path.dentry);
|
||||
+ error = security_inode_readlink(path.dentry, path.mnt);
|
||||
if (!error) {
|
||||
touch_atime(path.mnt, path.dentry);
|
||||
error = inode->i_op->readlink(path.dentry,
|
||||
--- a/include/linux/security.h
|
||||
+++ b/include/linux/security.h
|
||||
@@ -392,6 +392,7 @@ static inline void security_free_mnt_opt
|
||||
* @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.
|
||||
@@ -1373,7 +1374,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);
|
||||
int (*inode_setattr) (struct dentry *dentry, struct vfsmount *,
|
||||
@@ -1643,7 +1644,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);
|
||||
int security_inode_setattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
@@ -2036,7 +2037,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/capability.c
|
||||
+++ b/security/capability.c
|
||||
@@ -200,7 +200,7 @@ static int cap_inode_rename(struct inode
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int cap_inode_readlink(struct dentry *dentry)
|
||||
+static int cap_inode_readlink(struct dentry *dentry, struct vfsmount *mnt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -422,11 +422,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
|
||||
@@ -2627,7 +2627,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);
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
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 | 14 +++++++++-----
|
||||
security/commoncap.c | 3 ++-
|
||||
security/security.c | 5 +++--
|
||||
security/selinux/hooks.c | 3 ++-
|
||||
security/smack/smack_lsm.c | 6 ++++--
|
||||
6 files changed, 21 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/fs/xattr.c
|
||||
+++ b/fs/xattr.c
|
||||
@@ -202,7 +202,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,8 @@ extern int cap_bprm_secureexec(struct li
|
||||
extern int cap_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
const char *name, const void *value, size_t size,
|
||||
int flags);
|
||||
-extern int cap_inode_removexattr(struct dentry *dentry, const char *name);
|
||||
+extern int cap_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const 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);
|
||||
@@ -1403,7 +1404,8 @@ struct security_operations {
|
||||
int (*inode_getxattr) (struct dentry *dentry, struct vfsmount *mnt,
|
||||
const char *name);
|
||||
int (*inode_listxattr) (struct dentry *dentry, struct vfsmount *mnt);
|
||||
- int (*inode_removexattr) (struct dentry *dentry, const char *name);
|
||||
+ int (*inode_removexattr) (struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const 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, bool alloc);
|
||||
@@ -1680,7 +1682,8 @@ void security_inode_post_setxattr(struct
|
||||
int security_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
const char *name);
|
||||
int security_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt);
|
||||
-int security_inode_removexattr(struct dentry *dentry, const char *name);
|
||||
+int security_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const 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, bool alloc);
|
||||
@@ -2128,9 +2131,10 @@ static inline int security_inode_listxat
|
||||
}
|
||||
|
||||
static inline int security_inode_removexattr(struct dentry *dentry,
|
||||
- const char *name)
|
||||
+ struct vfsmount *mnt,
|
||||
+ const 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
|
||||
@@ -429,7 +429,8 @@ int cap_inode_setxattr(struct dentry *de
|
||||
return 0;
|
||||
}
|
||||
|
||||
-int cap_inode_removexattr(struct dentry *dentry, const char *name)
|
||||
+int cap_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name)
|
||||
{
|
||||
if (!strcmp(name, XATTR_NAME_CAPS)) {
|
||||
if (!capable(CAP_SETFCAP))
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -506,11 +506,12 @@ int security_inode_listxattr(struct dent
|
||||
return security_ops->inode_listxattr(dentry, mnt);
|
||||
}
|
||||
|
||||
-int security_inode_removexattr(struct dentry *dentry, const char *name)
|
||||
+int security_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const 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
|
||||
@@ -2807,7 +2807,8 @@ static int selinux_inode_listxattr(struc
|
||||
return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
|
||||
}
|
||||
|
||||
-static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
|
||||
+static int selinux_inode_removexattr(struct dentry *dentry,
|
||||
+ struct vfsmount *mnt, const char *name)
|
||||
{
|
||||
if (strcmp(name, XATTR_NAME_SELINUX))
|
||||
return selinux_inode_setotherxattr(dentry, name);
|
||||
--- a/security/smack/smack_lsm.c
|
||||
+++ b/security/smack/smack_lsm.c
|
||||
@@ -687,13 +687,15 @@ static int smack_inode_getxattr(struct d
|
||||
/*
|
||||
* smack_inode_removexattr - Smack check on removexattr
|
||||
* @dentry: the object
|
||||
+ * @mnt: unused
|
||||
* @name: name of the attribute
|
||||
*
|
||||
* Removing the Smack attribute requires CAP_MAC_ADMIN
|
||||
*
|
||||
* Returns 0 if access is permitted, an error code otherwise
|
||||
*/
|
||||
-static int smack_inode_removexattr(struct dentry *dentry, const char *name)
|
||||
+static int smack_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
@@ -703,7 +705,7 @@ static int smack_inode_removexattr(struc
|
||||
if (!capable(CAP_MAC_ADMIN))
|
||||
rc = -EPERM;
|
||||
} else
|
||||
- rc = cap_inode_removexattr(dentry, name);
|
||||
+ rc = cap_inode_removexattr(dentry, mnt, name);
|
||||
|
||||
if (rc == 0)
|
||||
rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE);
|
||||
160
src/patches/suse-2.6.27.25/patches.apparmor/security-rename.diff
Normal file
160
src/patches/suse-2.6.27.25/patches.apparmor/security-rename.diff
Normal file
@@ -0,0 +1,160 @@
|
||||
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/capability.c | 3 ++-
|
||||
security/security.c | 7 ++++---
|
||||
security/selinux/hooks.c | 8 ++++++--
|
||||
security/smack/smack_lsm.c | 6 +++++-
|
||||
6 files changed, 31 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -2563,7 +2563,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;
|
||||
|
||||
@@ -2597,7 +2598,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
|
||||
@@ -390,8 +390,10 @@ static inline void security_free_mnt_opt
|
||||
* 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.
|
||||
@@ -1380,7 +1382,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);
|
||||
@@ -1653,7 +1657,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);
|
||||
@@ -2045,8 +2050,10 @@ static inline int security_inode_mknod(s
|
||||
|
||||
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/capability.c
|
||||
+++ b/security/capability.c
|
||||
@@ -198,7 +198,8 @@ static int cap_inode_mknod(struct inode
|
||||
}
|
||||
|
||||
static int cap_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
|
||||
- struct inode *new_inode, struct dentry *new_dentry)
|
||||
+ struct vfsmount *old_mnt, struct inode *new_inode,
|
||||
+ struct dentry *new_dentry, struct vfsmount *new_mnt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -417,13 +417,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
|
||||
@@ -2628,8 +2628,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);
|
||||
}
|
||||
--- a/security/smack/smack_lsm.c
|
||||
+++ b/security/smack/smack_lsm.c
|
||||
@@ -509,8 +509,10 @@ static int smack_inode_rmdir(struct inod
|
||||
* smack_inode_rename - Smack check on rename
|
||||
* @old_inode: the old directory
|
||||
* @old_dentry: unused
|
||||
+ * @old_mnt: unused
|
||||
* @new_inode: the new directory
|
||||
* @new_dentry: unused
|
||||
+ * @new_mnt: unused
|
||||
*
|
||||
* Read and write access is required on both the old and
|
||||
* new directories.
|
||||
@@ -519,8 +521,10 @@ static int smack_inode_rmdir(struct inod
|
||||
*/
|
||||
static int smack_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)
|
||||
{
|
||||
int rc;
|
||||
char *isp;
|
||||
127
src/patches/suse-2.6.27.25/patches.apparmor/security-rmdir.diff
Normal file
127
src/patches/suse-2.6.27.25/patches.apparmor/security-rmdir.diff
Normal file
@@ -0,0 +1,127 @@
|
||||
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/capability.c | 3 ++-
|
||||
security/security.c | 5 +++--
|
||||
security/selinux/hooks.c | 3 ++-
|
||||
security/smack/smack_lsm.c | 4 +++-
|
||||
6 files changed, 18 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -2184,7 +2184,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
|
||||
@@ -372,6 +372,7 @@ static inline void security_free_mnt_opt
|
||||
* 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
|
||||
@@ -1372,7 +1373,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,
|
||||
@@ -1643,7 +1645,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,
|
||||
@@ -2022,7 +2025,8 @@ static inline int security_inode_mkdir(s
|
||||
}
|
||||
|
||||
static inline int security_inode_rmdir(struct inode *dir,
|
||||
- struct dentry *dentry)
|
||||
+ struct dentry *dentry,
|
||||
+ struct vfsmount *mnt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/capability.c
|
||||
+++ b/security/capability.c
|
||||
@@ -184,7 +184,8 @@ static int cap_inode_mkdir(struct inode
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int cap_inode_rmdir(struct inode *inode, struct dentry *dentry)
|
||||
+static int cap_inode_rmdir(struct inode *inode, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -399,11 +399,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
|
||||
@@ -2609,7 +2609,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);
|
||||
}
|
||||
--- a/security/smack/smack_lsm.c
|
||||
+++ b/security/smack/smack_lsm.c
|
||||
@@ -480,11 +480,13 @@ static int smack_inode_unlink(struct ino
|
||||
* smack_inode_rmdir - Smack check on directory deletion
|
||||
* @dir: containing directory object
|
||||
* @dentry: directory to unlink
|
||||
+ * @mnt: vfsmount @dentry to unlink
|
||||
*
|
||||
* Returns 0 if current can write the containing directory
|
||||
* and the directory, error code otherwise
|
||||
*/
|
||||
-static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
+static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt)
|
||||
{
|
||||
int rc;
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
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 ++--
|
||||
fs/fat/file.c | 2 +-
|
||||
include/linux/security.h | 10 +++++++---
|
||||
security/capability.c | 3 ++-
|
||||
security/security.c | 5 +++--
|
||||
security/selinux/hooks.c | 5 +++--
|
||||
security/smack/smack_lsm.c | 3 ++-
|
||||
7 files changed, 20 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/fs/attr.c
|
||||
+++ b/fs/attr.c
|
||||
@@ -164,13 +164,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/fs/fat/file.c
|
||||
+++ b/fs/fat/file.c
|
||||
@@ -98,7 +98,7 @@ int fat_generic_ioctl(struct inode *inod
|
||||
* out the RO attribute for checking by the security
|
||||
* module, just because it maps to a file mode.
|
||||
*/
|
||||
- err = security_inode_setattr(filp->f_path.dentry, &ia);
|
||||
+ err = security_inode_setattr(filp->f_path.dentry, filp->f_path.mnt, &ia);
|
||||
if (err)
|
||||
goto up;
|
||||
|
||||
--- a/include/linux/security.h
|
||||
+++ b/include/linux/security.h
|
||||
@@ -412,6 +412,7 @@ static inline void security_free_mnt_opt
|
||||
* 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:
|
||||
@@ -1371,7 +1372,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);
|
||||
- int (*inode_setattr) (struct dentry *dentry, struct iattr *attr);
|
||||
+ int (*inode_setattr) (struct dentry *dentry, struct vfsmount *,
|
||||
+ struct iattr *attr);
|
||||
int (*inode_getattr) (struct vfsmount *mnt, struct dentry *dentry);
|
||||
void (*inode_delete) (struct inode *inode);
|
||||
int (*inode_setxattr) (struct dentry *dentry, const char *name,
|
||||
@@ -1638,7 +1640,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);
|
||||
-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, const char *name,
|
||||
@@ -2041,7 +2044,8 @@ static inline int security_inode_permiss
|
||||
}
|
||||
|
||||
static inline int security_inode_setattr(struct dentry *dentry,
|
||||
- struct iattr *attr)
|
||||
+ struct vfsmount *mnt,
|
||||
+ struct iattr *attr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/capability.c
|
||||
+++ b/security/capability.c
|
||||
@@ -216,7 +216,8 @@ static int cap_inode_permission(struct i
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int cap_inode_setattr(struct dentry *dentry, struct iattr *iattr)
|
||||
+static int cap_inode_setattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ struct iattr *iattr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -441,11 +441,12 @@ int security_inode_permission(struct ino
|
||||
return security_ops->inode_permission(inode, mask);
|
||||
}
|
||||
|
||||
-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);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(security_inode_setattr);
|
||||
|
||||
--- a/security/selinux/hooks.c
|
||||
+++ b/security/selinux/hooks.c
|
||||
@@ -2656,11 +2656,12 @@ static int selinux_inode_permission(stru
|
||||
open_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;
|
||||
|
||||
--- a/security/smack/smack_lsm.c
|
||||
+++ b/security/smack/smack_lsm.c
|
||||
@@ -559,7 +559,8 @@ static int smack_inode_permission(struct
|
||||
*
|
||||
* Returns 0 if access is permitted, an error code otherwise
|
||||
*/
|
||||
-static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)
|
||||
+static int smack_inode_setattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ struct iattr *iattr)
|
||||
{
|
||||
/*
|
||||
* Need to allow for clearing the setuid bit.
|
||||
@@ -0,0 +1,256 @@
|
||||
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 | 41 ++++++++++++++++++++++++++---------------
|
||||
security/capability.c | 3 ++-
|
||||
security/commoncap.c | 5 +++--
|
||||
security/security.c | 16 ++++++++++------
|
||||
security/selinux/hooks.c | 8 +++++---
|
||||
security/smack/smack_lsm.c | 12 ++++++++----
|
||||
7 files changed, 56 insertions(+), 33 deletions(-)
|
||||
|
||||
--- a/fs/xattr.c
|
||||
+++ b/fs/xattr.c
|
||||
@@ -78,7 +78,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;
|
||||
@@ -86,7 +86,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
|
||||
@@ -54,8 +54,9 @@ extern void cap_capset_set(struct task_s
|
||||
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, const char *name,
|
||||
- const void *value, size_t size, int flags);
|
||||
+extern int cap_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name, const void *value, size_t size,
|
||||
+ int flags);
|
||||
extern int cap_inode_removexattr(struct dentry *dentry, const char *name);
|
||||
extern int cap_inode_need_killpriv(struct dentry *dentry);
|
||||
extern int cap_inode_killpriv(struct dentry *dentry);
|
||||
@@ -438,11 +439,11 @@ static inline void security_free_mnt_opt
|
||||
* 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.
|
||||
@@ -1392,10 +1393,13 @@ 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, const char *name,
|
||||
- const void *value, size_t size, int flags);
|
||||
- void (*inode_post_setxattr) (struct dentry *dentry, const char *name,
|
||||
- const void *value, size_t size, int flags);
|
||||
+ int (*inode_setxattr) (struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name, const void *value, size_t size,
|
||||
+ int flags);
|
||||
+ void (*inode_post_setxattr) (struct dentry *dentry,
|
||||
+ struct vfsmount *mnt,
|
||||
+ const char *name, const void *value,
|
||||
+ size_t size, int flags);
|
||||
int (*inode_getxattr) (struct dentry *dentry, const char *name);
|
||||
int (*inode_listxattr) (struct dentry *dentry);
|
||||
int (*inode_removexattr) (struct dentry *dentry, const char *name);
|
||||
@@ -1666,10 +1670,12 @@ 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, const char *name,
|
||||
- const void *value, size_t size, int flags);
|
||||
-void security_inode_post_setxattr(struct dentry *dentry, const char *name,
|
||||
- const void *value, size_t size, int flags);
|
||||
+int security_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name, const void *value,
|
||||
+ size_t size, int flags);
|
||||
+void security_inode_post_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name, const void *value,
|
||||
+ size_t size, int flags);
|
||||
int security_inode_getxattr(struct dentry *dentry, const char *name);
|
||||
int security_inode_listxattr(struct dentry *dentry);
|
||||
int security_inode_removexattr(struct dentry *dentry, const char *name);
|
||||
@@ -2092,13 +2098,18 @@ static inline void security_inode_delete
|
||||
{ }
|
||||
|
||||
static inline int security_inode_setxattr(struct dentry *dentry,
|
||||
- const char *name, const void *value, size_t size, int flags)
|
||||
+ struct vfsmount *mnt,
|
||||
+ const char *name, const 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,
|
||||
- const char *name, const void *value, size_t size, int flags)
|
||||
+ struct vfsmount *mnt,
|
||||
+ const char *name,
|
||||
+ const void *value,
|
||||
+ size_t size, int flags)
|
||||
{ }
|
||||
|
||||
static inline int security_inode_getxattr(struct dentry *dentry,
|
||||
--- a/security/capability.c
|
||||
+++ b/security/capability.c
|
||||
@@ -235,7 +235,8 @@ static void cap_inode_delete(struct inod
|
||||
{
|
||||
}
|
||||
|
||||
-static void cap_inode_post_setxattr(struct dentry *dentry, const char *name,
|
||||
+static void cap_inode_post_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
}
|
||||
--- a/security/commoncap.c
|
||||
+++ b/security/commoncap.c
|
||||
@@ -414,8 +414,9 @@ int cap_bprm_secureexec (struct linux_bi
|
||||
current->egid != current->gid);
|
||||
}
|
||||
|
||||
-int cap_inode_setxattr(struct dentry *dentry, const char *name,
|
||||
- const void *value, size_t size, int flags)
|
||||
+int cap_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name, const void *value, size_t size,
|
||||
+ int flags)
|
||||
{
|
||||
if (!strcmp(name, XATTR_NAME_CAPS)) {
|
||||
if (!capable(CAP_SETFCAP))
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -471,20 +471,24 @@ void security_inode_delete(struct inode
|
||||
security_ops->inode_delete(inode);
|
||||
}
|
||||
|
||||
-int security_inode_setxattr(struct dentry *dentry, const char *name,
|
||||
- const void *value, size_t size, int flags)
|
||||
+int security_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name, const 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, const char *name,
|
||||
- const void *value, size_t size, int flags)
|
||||
+void security_inode_post_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name, const 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, const char *name)
|
||||
--- a/security/selinux/hooks.c
|
||||
+++ b/security/selinux/hooks.c
|
||||
@@ -2713,8 +2713,9 @@ static int selinux_inode_setotherxattr(s
|
||||
return dentry_has_perm(current, NULL, dentry, FILE__SETATTR);
|
||||
}
|
||||
|
||||
-static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
|
||||
- const void *value, size_t size, int flags)
|
||||
+static int selinux_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name, const void *value,
|
||||
+ size_t size, int flags)
|
||||
{
|
||||
struct task_security_struct *tsec = current->security;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
@@ -2768,7 +2769,8 @@ static int selinux_inode_setxattr(struct
|
||||
&ad);
|
||||
}
|
||||
|
||||
-static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
|
||||
+static void selinux_inode_post_setxattr(struct dentry *dentry,
|
||||
+ struct vfsmount *mnt, const char *name,
|
||||
const void *value, size_t size,
|
||||
int flags)
|
||||
{
|
||||
--- a/security/smack/smack_lsm.c
|
||||
+++ b/security/smack/smack_lsm.c
|
||||
@@ -595,6 +595,7 @@ static int smack_inode_getattr(struct vf
|
||||
/**
|
||||
* smack_inode_setxattr - Smack check for setting xattrs
|
||||
* @dentry: the object
|
||||
+ * @mnt: unused
|
||||
* @name: name of the attribute
|
||||
* @value: unused
|
||||
* @size: unused
|
||||
@@ -604,8 +605,9 @@ static int smack_inode_getattr(struct vf
|
||||
*
|
||||
* Returns 0 if access is permitted, an error code otherwise
|
||||
*/
|
||||
-static int smack_inode_setxattr(struct dentry *dentry, const char *name,
|
||||
- const void *value, size_t size, int flags)
|
||||
+static int smack_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *name, const void *value,
|
||||
+ size_t size, int flags)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
@@ -617,7 +619,7 @@ static int smack_inode_setxattr(struct d
|
||||
if (size == 0)
|
||||
rc = -EINVAL;
|
||||
} else
|
||||
- rc = cap_inode_setxattr(dentry, name, value, size, flags);
|
||||
+ rc = cap_inode_setxattr(dentry, mnt, name, value, size, flags);
|
||||
|
||||
if (rc == 0)
|
||||
rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE);
|
||||
@@ -628,6 +630,7 @@ static int smack_inode_setxattr(struct d
|
||||
/**
|
||||
* smack_inode_post_setxattr - Apply the Smack update approved above
|
||||
* @dentry: object
|
||||
+ * @mnt: unused
|
||||
* @name: attribute name
|
||||
* @value: attribute value
|
||||
* @size: attribute size
|
||||
@@ -636,7 +639,8 @@ static int smack_inode_setxattr(struct d
|
||||
* Set the pointer in the inode blob to the entry found
|
||||
* in the master label list.
|
||||
*/
|
||||
-static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
|
||||
+static void smack_inode_post_setxattr(struct dentry *dentry,
|
||||
+ struct vfsmount *mnt, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
struct inode_smack *isp;
|
||||
@@ -0,0 +1,105 @@
|
||||
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/capability.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
|
||||
@@ -2358,7 +2358,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
|
||||
@@ -355,6 +355,7 @@ static inline void security_free_mnt_opt
|
||||
* 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:
|
||||
@@ -1363,8 +1364,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);
|
||||
@@ -1634,7 +1635,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);
|
||||
@@ -1999,6 +2000,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/capability.c
|
||||
+++ b/security/capability.c
|
||||
@@ -172,7 +172,7 @@ static int cap_inode_unlink(struct inode
|
||||
}
|
||||
|
||||
static int cap_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
|
||||
@@ -382,11 +382,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
|
||||
@@ -2592,7 +2592,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);
|
||||
}
|
||||
132
src/patches/suse-2.6.27.25/patches.apparmor/security-unlink.diff
Normal file
132
src/patches/suse-2.6.27.25/patches.apparmor/security-unlink.diff
Normal file
@@ -0,0 +1,132 @@
|
||||
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/capability.c | 3 ++-
|
||||
security/security.c | 5 +++--
|
||||
security/selinux/hooks.c | 5 +++--
|
||||
security/smack/smack_lsm.c | 4 +++-
|
||||
6 files changed, 19 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -2264,7 +2264,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
|
||||
@@ -352,6 +352,7 @@ static inline void security_free_mnt_opt
|
||||
* 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.
|
||||
@@ -1368,7 +1369,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,
|
||||
@@ -1640,7 +1642,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,
|
||||
@@ -2003,7 +2006,8 @@ static inline int security_inode_link(st
|
||||
}
|
||||
|
||||
static inline int security_inode_unlink(struct inode *dir,
|
||||
- struct dentry *dentry)
|
||||
+ struct dentry *dentry,
|
||||
+ struct vfsmount *mnt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/capability.c
|
||||
+++ b/security/capability.c
|
||||
@@ -167,7 +167,8 @@ static int cap_inode_link(struct dentry
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int cap_inode_unlink(struct inode *inode, struct dentry *dentry)
|
||||
+static int cap_inode_unlink(struct inode *inode, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -376,11 +376,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
|
||||
@@ -2587,11 +2587,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);
|
||||
--- a/security/smack/smack_lsm.c
|
||||
+++ b/security/smack/smack_lsm.c
|
||||
@@ -454,11 +454,13 @@ static int smack_inode_link(struct dentr
|
||||
* smack_inode_unlink - Smack check on inode deletion
|
||||
* @dir: containing directory object
|
||||
* @dentry: file to unlink
|
||||
+ * @mnt: vfsmount of file to unlink
|
||||
*
|
||||
* Returns 0 if current can write the containing directory
|
||||
* and the object, error code otherwise
|
||||
*/
|
||||
-static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)
|
||||
+static int smack_inode_unlink(struct inode *dir, struct dentry *dentry,
|
||||
+ struct vfsmount *mnt)
|
||||
{
|
||||
struct inode *ip = dentry->d_inode;
|
||||
int rc;
|
||||
@@ -0,0 +1,592 @@
|
||||
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 | 59 +++++++++++++++++++++++----------------------
|
||||
include/linux/security.h | 38 ++++++++++++++++------------
|
||||
include/linux/xattr.h | 9 +++---
|
||||
security/capability.c | 5 ++-
|
||||
security/commoncap.c | 4 +--
|
||||
security/security.c | 17 ++++++------
|
||||
security/selinux/hooks.c | 10 ++++---
|
||||
security/smack/smack_lsm.c | 14 ++++++----
|
||||
8 files changed, 87 insertions(+), 69 deletions(-)
|
||||
|
||||
--- a/fs/xattr.c
|
||||
+++ b/fs/xattr.c
|
||||
@@ -68,7 +68,7 @@ xattr_permission(struct inode *inode, co
|
||||
|
||||
int
|
||||
vfs_setxattr(struct dentry *dentry, struct vfsmount *mnt, const char *name,
|
||||
- const void *value, size_t size, int flags)
|
||||
+ const void *value, size_t size, int flags, struct file *file)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int error;
|
||||
@@ -78,7 +78,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;
|
||||
@@ -132,7 +132,7 @@ EXPORT_SYMBOL_GPL(xattr_getsecurity);
|
||||
|
||||
ssize_t
|
||||
vfs_getxattr(struct dentry *dentry, struct vfsmount *mnt, const char *name,
|
||||
- void *value, size_t size)
|
||||
+ void *value, size_t size, struct file *file)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int error;
|
||||
@@ -141,7 +141,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;
|
||||
|
||||
@@ -169,12 +169,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;
|
||||
@@ -190,7 +190,8 @@ vfs_listxattr(struct dentry *dentry, str
|
||||
EXPORT_SYMBOL_GPL(vfs_listxattr);
|
||||
|
||||
int
|
||||
-vfs_removexattr(struct dentry *dentry, struct vfsmount *mnt, const char *name)
|
||||
+vfs_removexattr(struct dentry *dentry, struct vfsmount *mnt, const char *name,
|
||||
+ struct file *file)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int error;
|
||||
@@ -202,7 +203,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;
|
||||
|
||||
@@ -222,7 +223,7 @@ EXPORT_SYMBOL_GPL(vfs_removexattr);
|
||||
*/
|
||||
static long
|
||||
setxattr(struct dentry *dentry, struct vfsmount *mnt, const char __user *name,
|
||||
- const void __user *value, size_t size, int flags)
|
||||
+ const void __user *value, size_t size, int flags, struct file *file)
|
||||
{
|
||||
int error;
|
||||
void *kvalue = NULL;
|
||||
@@ -249,7 +250,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;
|
||||
}
|
||||
@@ -266,7 +267,7 @@ SYSCALL_DEFINE5(setxattr, const char __u
|
||||
return error;
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (!error) {
|
||||
- error = setxattr(path.dentry, path.mnt, name, value, size, flags);
|
||||
+ error = setxattr(path.dentry, path.mnt, name, value, size, flags, NULL);
|
||||
mnt_drop_write(path.mnt);
|
||||
}
|
||||
path_put(&path);
|
||||
@@ -285,7 +286,7 @@ SYSCALL_DEFINE5(lsetxattr, const char __
|
||||
return error;
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (!error) {
|
||||
- error = setxattr(path.dentry, path.mnt, name, value, size, flags);
|
||||
+ error = setxattr(path.dentry, path.mnt, name, value, size, flags, NULL);
|
||||
mnt_drop_write(path.mnt);
|
||||
}
|
||||
path_put(&path);
|
||||
@@ -306,7 +307,8 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, cons
|
||||
audit_inode(NULL, dentry);
|
||||
error = mnt_want_write_file(f->f_path.mnt, f);
|
||||
if (!error) {
|
||||
- error = setxattr(dentry, f->f_vfsmnt, name, value, size, flags);
|
||||
+ error = setxattr(dentry, f->f_vfsmnt, name, value, size, flags,
|
||||
+ f);
|
||||
mnt_drop_write(f->f_path.mnt);
|
||||
}
|
||||
fput(f);
|
||||
@@ -318,7 +320,7 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, cons
|
||||
*/
|
||||
static ssize_t
|
||||
getxattr(struct dentry *dentry, struct vfsmount *mnt, const char __user *name,
|
||||
- void __user *value, size_t size)
|
||||
+ void __user *value, size_t size, struct file *file)
|
||||
{
|
||||
ssize_t error;
|
||||
void *kvalue = NULL;
|
||||
@@ -338,7 +340,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;
|
||||
@@ -360,7 +362,7 @@ SYSCALL_DEFINE4(getxattr, const char __u
|
||||
error = user_path(pathname, &path);
|
||||
if (error)
|
||||
return error;
|
||||
- error = getxattr(path.dentry, path.mnt, name, value, size);
|
||||
+ error = getxattr(path.dentry, path.mnt, name, value, size, NULL);
|
||||
path_put(&path);
|
||||
return error;
|
||||
}
|
||||
@@ -374,7 +376,7 @@ SYSCALL_DEFINE4(lgetxattr, const char __
|
||||
error = user_lpath(pathname, &path);
|
||||
if (error)
|
||||
return error;
|
||||
- error = getxattr(path.dentry, path.mnt, name, value, size);
|
||||
+ error = getxattr(path.dentry, path.mnt, name, value, size, NULL);
|
||||
path_put(&path);
|
||||
return error;
|
||||
}
|
||||
@@ -389,7 +391,7 @@ SYSCALL_DEFINE4(fgetxattr, int, fd, cons
|
||||
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;
|
||||
}
|
||||
@@ -399,7 +401,7 @@ SYSCALL_DEFINE4(fgetxattr, int, fd, cons
|
||||
*/
|
||||
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;
|
||||
@@ -412,7 +414,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;
|
||||
@@ -434,7 +436,7 @@ SYSCALL_DEFINE3(listxattr, const char __
|
||||
error = user_path(pathname, &path);
|
||||
if (error)
|
||||
return error;
|
||||
- error = listxattr(path.dentry, path.mnt, list, size);
|
||||
+ error = listxattr(path.dentry, path.mnt, list, size, NULL);
|
||||
path_put(&path);
|
||||
return error;
|
||||
}
|
||||
@@ -448,7 +450,7 @@ SYSCALL_DEFINE3(llistxattr, const char _
|
||||
error = user_lpath(pathname, &path);
|
||||
if (error)
|
||||
return error;
|
||||
- error = listxattr(path.dentry, path.mnt, list, size);
|
||||
+ error = listxattr(path.dentry, path.mnt, list, size, NULL);
|
||||
path_put(&path);
|
||||
return error;
|
||||
}
|
||||
@@ -462,7 +464,7 @@ SYSCALL_DEFINE3(flistxattr, int, fd, cha
|
||||
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;
|
||||
}
|
||||
@@ -471,7 +473,8 @@ SYSCALL_DEFINE3(flistxattr, int, fd, cha
|
||||
* Extended attribute REMOVE operations
|
||||
*/
|
||||
static long
|
||||
-removexattr(struct dentry *dentry, struct vfsmount *mnt, const char __user *name)
|
||||
+removexattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char __user *name, struct file *file)
|
||||
{
|
||||
int error;
|
||||
char kname[XATTR_NAME_MAX + 1];
|
||||
@@ -482,7 +485,7 @@ removexattr(struct dentry *dentry, struc
|
||||
if (error < 0)
|
||||
return error;
|
||||
|
||||
- return vfs_removexattr(dentry, mnt, kname);
|
||||
+ return vfs_removexattr(dentry, mnt, kname, file);
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE2(removexattr, const char __user *, pathname,
|
||||
@@ -496,7 +499,7 @@ SYSCALL_DEFINE2(removexattr, const char
|
||||
return error;
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (!error) {
|
||||
- error = removexattr(path.dentry, path.mnt, name);
|
||||
+ error = removexattr(path.dentry, path.mnt, name, NULL);
|
||||
mnt_drop_write(path.mnt);
|
||||
}
|
||||
path_put(&path);
|
||||
@@ -514,7 +517,7 @@ SYSCALL_DEFINE2(lremovexattr, const char
|
||||
return error;
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (!error) {
|
||||
- error = removexattr(path.dentry, path.mnt, name);
|
||||
+ error = removexattr(path.dentry, path.mnt, name, NULL);
|
||||
mnt_drop_write(path.mnt);
|
||||
}
|
||||
path_put(&path);
|
||||
@@ -534,7 +537,7 @@ SYSCALL_DEFINE2(fremovexattr, int, fd, c
|
||||
audit_inode(NULL, dentry);
|
||||
error = mnt_want_write_file(f->f_path.mnt, f);
|
||||
if (!error) {
|
||||
- error = removexattr(dentry, f->f_path.mnt, name);
|
||||
+ error = removexattr(dentry, f->f_path.mnt, name, f);
|
||||
mnt_drop_write(f->f_path.mnt);
|
||||
}
|
||||
fput(f);
|
||||
--- a/include/linux/security.h
|
||||
+++ b/include/linux/security.h
|
||||
@@ -56,9 +56,9 @@ extern void cap_bprm_apply_creds(struct
|
||||
extern int cap_bprm_secureexec(struct linux_binprm *bprm);
|
||||
extern int cap_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
const char *name, const void *value, size_t size,
|
||||
- int flags);
|
||||
+ int flags, struct file *file);
|
||||
extern int cap_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
- const char *name);
|
||||
+ const 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);
|
||||
@@ -1396,16 +1396,17 @@ struct security_operations {
|
||||
void (*inode_delete) (struct inode *inode);
|
||||
int (*inode_setxattr) (struct dentry *dentry, struct vfsmount *mnt,
|
||||
const char *name, const void *value, size_t size,
|
||||
- int flags);
|
||||
+ int flags, struct file *file);
|
||||
void (*inode_post_setxattr) (struct dentry *dentry,
|
||||
struct vfsmount *mnt,
|
||||
const char *name, const void *value,
|
||||
size_t size, int flags);
|
||||
int (*inode_getxattr) (struct dentry *dentry, struct vfsmount *mnt,
|
||||
- const char *name);
|
||||
- int (*inode_listxattr) (struct dentry *dentry, struct vfsmount *mnt);
|
||||
+ const 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,
|
||||
- const char *name);
|
||||
+ const 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, bool alloc);
|
||||
@@ -1675,15 +1676,16 @@ int security_inode_getattr(struct vfsmou
|
||||
void security_inode_delete(struct inode *inode);
|
||||
int security_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
const char *name, const void *value,
|
||||
- size_t size, int flags);
|
||||
+ size_t size, int flags, struct file *file);
|
||||
void security_inode_post_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
const char *name, const void *value,
|
||||
size_t size, int flags);
|
||||
int security_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
- const char *name);
|
||||
-int security_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt);
|
||||
+ const 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,
|
||||
- const char *name);
|
||||
+ const 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, bool alloc);
|
||||
@@ -2105,9 +2107,10 @@ static inline void security_inode_delete
|
||||
static inline int security_inode_setxattr(struct dentry *dentry,
|
||||
struct vfsmount *mnt,
|
||||
const char *name, const void *value,
|
||||
- size_t size, int flags)
|
||||
+ 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,
|
||||
@@ -2119,22 +2122,25 @@ static inline void security_inode_post_s
|
||||
|
||||
static inline int security_inode_getxattr(struct dentry *dentry,
|
||||
struct vfsmount *mnt,
|
||||
- const char *name)
|
||||
+ const 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,
|
||||
- const char *name)
|
||||
+ const 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
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/mount.h>
|
||||
+#include <linux/fs.h>
|
||||
|
||||
/* Namespaces */
|
||||
#define XATTR_OS2_PREFIX "os2."
|
||||
@@ -48,10 +49,10 @@ struct xattr_handler {
|
||||
};
|
||||
|
||||
ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t);
|
||||
-ssize_t vfs_getxattr(struct dentry *, struct vfsmount *, const char *, void *, size_t);
|
||||
-ssize_t vfs_listxattr(struct dentry *d, struct vfsmount *, char *list, size_t size);
|
||||
-int vfs_setxattr(struct dentry *, struct vfsmount *, const char *, const void *, size_t, int);
|
||||
-int vfs_removexattr(struct dentry *, struct vfsmount *mnt, const char *);
|
||||
+ssize_t vfs_getxattr(struct dentry *, struct vfsmount *, const char *, void *, size_t, struct file *file);
|
||||
+ssize_t vfs_listxattr(struct dentry *d, struct vfsmount *, char *list, size_t size, struct file *file);
|
||||
+int vfs_setxattr(struct dentry *, struct vfsmount *, const char *, const void *, size_t, int, struct file *file);
|
||||
+int vfs_removexattr(struct dentry *, struct vfsmount *mnt, const char *, struct file *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/capability.c
|
||||
+++ b/security/capability.c
|
||||
@@ -242,12 +242,13 @@ static void cap_inode_post_setxattr(stru
|
||||
}
|
||||
|
||||
static int cap_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
- const char *name)
|
||||
+ const char *name, struct file *f)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int cap_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt)
|
||||
+static int cap_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ struct file *f)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
--- a/security/commoncap.c
|
||||
+++ b/security/commoncap.c
|
||||
@@ -416,7 +416,7 @@ int cap_bprm_secureexec (struct linux_bi
|
||||
|
||||
int cap_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
const char *name, const void *value, size_t size,
|
||||
- int flags)
|
||||
+ int flags, struct file *file)
|
||||
{
|
||||
if (!strcmp(name, XATTR_NAME_CAPS)) {
|
||||
if (!capable(CAP_SETFCAP))
|
||||
@@ -430,7 +430,7 @@ int cap_inode_setxattr(struct dentry *de
|
||||
}
|
||||
|
||||
int cap_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
- const char *name)
|
||||
+ const char *name, struct file *file)
|
||||
{
|
||||
if (!strcmp(name, XATTR_NAME_CAPS)) {
|
||||
if (!capable(CAP_SETFCAP))
|
||||
--- a/security/security.c
|
||||
+++ b/security/security.c
|
||||
@@ -473,12 +473,12 @@ void security_inode_delete(struct inode
|
||||
|
||||
int security_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
const char *name, const void *value, size_t size,
|
||||
- int flags)
|
||||
+ 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,
|
||||
@@ -492,26 +492,27 @@ void security_inode_post_setxattr(struct
|
||||
}
|
||||
|
||||
int security_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
- const char *name)
|
||||
+ const 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,
|
||||
- const char *name)
|
||||
+ const 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
|
||||
@@ -2715,7 +2715,7 @@ static int selinux_inode_setotherxattr(s
|
||||
|
||||
static int selinux_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
const char *name, const void *value,
|
||||
- size_t size, int flags)
|
||||
+ size_t size, int flags, struct file *file)
|
||||
{
|
||||
struct task_security_struct *tsec = current->security;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
@@ -2797,18 +2797,20 @@ static void selinux_inode_post_setxattr(
|
||||
}
|
||||
|
||||
static int selinux_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
- const char *name)
|
||||
+ const 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, const char *name)
|
||||
+ struct vfsmount *mnt, const char *name,
|
||||
+ struct file *file)
|
||||
{
|
||||
if (strcmp(name, XATTR_NAME_SELINUX))
|
||||
return selinux_inode_setotherxattr(dentry, name);
|
||||
--- a/security/smack/smack_lsm.c
|
||||
+++ b/security/smack/smack_lsm.c
|
||||
@@ -600,6 +600,7 @@ static int smack_inode_getattr(struct vf
|
||||
* @value: unused
|
||||
* @size: unused
|
||||
* @flags: unused
|
||||
+ * @file: unused
|
||||
*
|
||||
* This protects the Smack attribute explicitly.
|
||||
*
|
||||
@@ -607,7 +608,7 @@ static int smack_inode_getattr(struct vf
|
||||
*/
|
||||
static int smack_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
const char *name, const void *value,
|
||||
- size_t size, int flags)
|
||||
+ size_t size, int flags, struct file *file)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
@@ -619,7 +620,8 @@ static int smack_inode_setxattr(struct d
|
||||
if (size == 0)
|
||||
rc = -EINVAL;
|
||||
} else
|
||||
- rc = cap_inode_setxattr(dentry, mnt, name, value, size, flags);
|
||||
+ rc = cap_inode_setxattr(dentry, mnt, name, value, size, flags,
|
||||
+ file);
|
||||
|
||||
if (rc == 0)
|
||||
rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE);
|
||||
@@ -675,11 +677,12 @@ static void smack_inode_post_setxattr(st
|
||||
* @dentry: the object
|
||||
* @mnt: unused
|
||||
* @name: unused
|
||||
+ * @file: unused
|
||||
*
|
||||
* Returns 0 if access is permitted, an error code otherwise
|
||||
*/
|
||||
static int smack_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
- const char *name)
|
||||
+ const char *name, struct file *file)
|
||||
{
|
||||
return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ);
|
||||
}
|
||||
@@ -689,13 +692,14 @@ static int smack_inode_getxattr(struct d
|
||||
* @dentry: the object
|
||||
* @mnt: unused
|
||||
* @name: name of the attribute
|
||||
+ * @file: unused
|
||||
*
|
||||
* Removing the Smack attribute requires CAP_MAC_ADMIN
|
||||
*
|
||||
* Returns 0 if access is permitted, an error code otherwise
|
||||
*/
|
||||
static int smack_inode_removexattr(struct dentry *dentry, struct vfsmount *mnt,
|
||||
- const char *name)
|
||||
+ const char *name, struct file *file)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
@@ -705,7 +709,7 @@ static int smack_inode_removexattr(struc
|
||||
if (!capable(CAP_MAC_ADMIN))
|
||||
rc = -EPERM;
|
||||
} else
|
||||
- rc = cap_inode_removexattr(dentry, mnt, name);
|
||||
+ rc = cap_inode_removexattr(dentry, mnt, name, file);
|
||||
|
||||
if (rc == 0)
|
||||
rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE);
|
||||
111
src/patches/suse-2.6.27.25/patches.apparmor/sysctl-pathname.diff
Normal file
111
src/patches/suse-2.6.27.25/patches.apparmor/sysctl-pathname.diff
Normal file
@@ -0,0 +1,111 @@
|
||||
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 | 34 +++++-----------------------------
|
||||
3 files changed, 34 insertions(+), 29 deletions(-)
|
||||
|
||||
--- a/include/linux/sysctl.h
|
||||
+++ b/include/linux/sysctl.h
|
||||
@@ -996,6 +996,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
|
||||
@@ -1554,6 +1554,33 @@ void register_sysctl_root(struct ctl_tab
|
||||
spin_unlock(&sysctl_lock);
|
||||
}
|
||||
|
||||
+char *sysctl_pathname(struct 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_GPL(sysctl_pathname);
|
||||
+
|
||||
#ifdef CONFIG_SYSCTL_SYSCALL
|
||||
/* Perform the actual read/write of a sysctl table entry. */
|
||||
static int do_sysctl_strategy(struct ctl_table_root *root,
|
||||
--- a/security/selinux/hooks.c
|
||||
+++ b/security/selinux/hooks.c
|
||||
@@ -1811,40 +1811,16 @@ 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;
|
||||
@@ -0,0 +1,267 @@
|
||||
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>
|
||||
|
||||
[ Moved dcache_lock outside vfsmount_lock to fix lock order (bnc#490902) ]
|
||||
Signed-off-by: Nick Piggin <npiggin@suse.de>
|
||||
|
||||
---
|
||||
fs/dcache.c | 126 +++++++++++++++++++++++++++----------------------
|
||||
fs/seq_file.c | 4 -
|
||||
include/linux/dcache.h | 5 +
|
||||
3 files changed, 75 insertions(+), 60 deletions(-)
|
||||
|
||||
Index: linux-2.6.27/fs/dcache.c
|
||||
===================================================================
|
||||
--- linux-2.6.27.orig/fs/dcache.c
|
||||
+++ linux-2.6.27/fs/dcache.c
|
||||
@@ -1898,44 +1898,46 @@ static int prepend_name(char **buffer, i
|
||||
* @root: root vfsmnt/dentry (may be modified by this function)
|
||||
* @buffer: buffer to return value in
|
||||
* @buflen: buffer length
|
||||
+ * @flags: flags controling behavior of d_path
|
||||
*
|
||||
- * Convert a dentry into an ASCII path name. If the entry has been deleted
|
||||
- * the string " (deleted)" is appended. Note that this is ambiguous.
|
||||
- *
|
||||
- * Returns the buffer or an error code if the path was too long.
|
||||
- *
|
||||
- * "buflen" should be positive. Caller holds the dcache_lock.
|
||||
+ * Convert a dentry into an ASCII path name. If the entry has been deleted,
|
||||
+ * then if @flags has D_PATH_FAIL_DELETED set, ERR_PTR(-ENOENT) is returned.
|
||||
+ * Otherwise, the string " (deleted)" is appended. Note that this is ambiguous.
|
||||
*
|
||||
* If path is not reachable from the supplied root, then the value of
|
||||
- * root is changed (without modifying refcounts).
|
||||
+ * root is changed (without modifying refcounts). The path returned in this
|
||||
+ * case will be relative (i.e., it will not start with a slash).
|
||||
+ *
|
||||
+ * Returns the buffer or an error code if the path was too long.
|
||||
*/
|
||||
char *__d_path(const struct path *path, struct path *root,
|
||||
- char *buffer, int buflen)
|
||||
+ char *buffer, int buflen, int flags)
|
||||
{
|
||||
struct dentry *dentry = path->dentry;
|
||||
struct vfsmount *vfsmnt = path->mnt;
|
||||
- char *end = buffer + buflen;
|
||||
- char *retval;
|
||||
+ const unsigned char *name;
|
||||
+ int namelen;
|
||||
+
|
||||
+ buffer += buflen;
|
||||
+ prepend(&buffer, &buflen, "\0", 1);
|
||||
|
||||
+ spin_lock(&dcache_lock);
|
||||
spin_lock(&vfsmount_lock);
|
||||
- prepend(&end, &buflen, "\0", 1);
|
||||
- if (!IS_ROOT(dentry) && d_unhashed(dentry) &&
|
||||
- (prepend(&end, &buflen, " (deleted)", 10) != 0))
|
||||
+ if (!IS_ROOT(dentry) && d_unhashed(dentry)) {
|
||||
+ if (flags & D_PATH_FAIL_DELETED) {
|
||||
+ buffer = ERR_PTR(-ENOENT);
|
||||
+ goto out;
|
||||
+ }
|
||||
+ if (prepend(&buffer, &buflen, " (deleted)", 10) != 0)
|
||||
goto Elong;
|
||||
-
|
||||
+ }
|
||||
if (buflen < 1)
|
||||
goto Elong;
|
||||
- /* Get '/' right */
|
||||
- retval = end-1;
|
||||
- *retval = '/';
|
||||
|
||||
- for (;;) {
|
||||
+ while (dentry != root->dentry || vfsmnt != root->mnt) {
|
||||
struct dentry * parent;
|
||||
|
||||
- if (dentry == root->dentry && vfsmnt == root->mnt)
|
||||
- break;
|
||||
if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
|
||||
- /* Global root? */
|
||||
if (vfsmnt->mnt_parent == vfsmnt) {
|
||||
goto global_root;
|
||||
}
|
||||
@@ -1945,27 +1947,51 @@ char *__d_path(const struct path *path,
|
||||
}
|
||||
parent = dentry->d_parent;
|
||||
prefetch(parent);
|
||||
- if ((prepend_name(&end, &buflen, &dentry->d_name) != 0) ||
|
||||
- (prepend(&end, &buflen, "/", 1) != 0))
|
||||
+ if ((prepend_name(&buffer, &buflen, &dentry->d_name) != 0) ||
|
||||
+ (prepend(&buffer, &buflen, "/", 1) != 0))
|
||||
goto Elong;
|
||||
- retval = end;
|
||||
dentry = parent;
|
||||
}
|
||||
+ /* Get '/' right. */
|
||||
+ if (*buffer != '/' && prepend(&buffer, &buflen, "/", 1))
|
||||
+ goto Elong;
|
||||
|
||||
out:
|
||||
spin_unlock(&vfsmount_lock);
|
||||
- return retval;
|
||||
+ spin_unlock(&dcache_lock);
|
||||
+ return buffer;
|
||||
|
||||
global_root:
|
||||
- retval += 1; /* hit the slash */
|
||||
- if (prepend_name(&retval, &buflen, &dentry->d_name) != 0)
|
||||
+ /*
|
||||
+ * 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;
|
||||
+ 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 == '/') {
|
||||
+ buffer++;
|
||||
+ buflen++;
|
||||
+ }
|
||||
+ if ((flags & D_PATH_DISCONNECT) && *name == '/') {
|
||||
+ /* Make sure we won't return a pathname starting with '/' */
|
||||
+ name++;
|
||||
+ namelen--;
|
||||
+ }
|
||||
+ if (prepend(&buffer, &buflen, name, namelen))
|
||||
goto Elong;
|
||||
root->mnt = vfsmnt;
|
||||
root->dentry = dentry;
|
||||
goto out;
|
||||
|
||||
Elong:
|
||||
- retval = ERR_PTR(-ENAMETOOLONG);
|
||||
+ buffer = ERR_PTR(-ENAMETOOLONG);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -2002,10 +2028,8 @@ char *d_path(const struct path *path, ch
|
||||
root = current->fs->root;
|
||||
path_get(&root);
|
||||
read_unlock(¤t->fs->lock);
|
||||
- spin_lock(&dcache_lock);
|
||||
tmp = root;
|
||||
- res = __d_path(path, &tmp, buf, buflen);
|
||||
- spin_unlock(&dcache_lock);
|
||||
+ res = __d_path(path, &tmp, buf, buflen, 0);
|
||||
path_put(&root);
|
||||
return res;
|
||||
}
|
||||
@@ -2088,9 +2112,9 @@ Elong:
|
||||
*/
|
||||
SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
|
||||
{
|
||||
- int error;
|
||||
- struct path pwd, root;
|
||||
- char *page = (char *) __get_free_page(GFP_USER);
|
||||
+ int error, len;
|
||||
+ struct path pwd, root, tmp;
|
||||
+ char *page = (char *) __get_free_page(GFP_USER), *cwd;
|
||||
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
@@ -2102,30 +2126,20 @@ SYSCALL_DEFINE2(getcwd, char __user *, b
|
||||
path_get(&root);
|
||||
read_unlock(¤t->fs->lock);
|
||||
|
||||
- error = -ENOENT;
|
||||
- /* Has the current directory has been unlinked? */
|
||||
- spin_lock(&dcache_lock);
|
||||
- if (IS_ROOT(pwd.dentry) || !d_unhashed(pwd.dentry)) {
|
||||
- unsigned long len;
|
||||
- struct path tmp = root;
|
||||
- char * cwd;
|
||||
-
|
||||
- cwd = __d_path(&pwd, &tmp, page, PAGE_SIZE);
|
||||
- spin_unlock(&dcache_lock);
|
||||
-
|
||||
+ tmp = root;
|
||||
+ cwd = __d_path(&pwd, &tmp, page, PAGE_SIZE, D_PATH_FAIL_DELETED);
|
||||
+ if (IS_ERR(cwd)) {
|
||||
error = PTR_ERR(cwd);
|
||||
- if (IS_ERR(cwd))
|
||||
- goto out;
|
||||
+ 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);
|
||||
+ error = -ERANGE;
|
||||
+ len = PAGE_SIZE + page - cwd;
|
||||
+ if (len <= size) {
|
||||
+ error = len;
|
||||
+ if (copy_to_user(buf, cwd, len))
|
||||
+ error = -EFAULT;
|
||||
+ }
|
||||
|
||||
out:
|
||||
path_put(&pwd);
|
||||
Index: linux-2.6.27/fs/seq_file.c
|
||||
===================================================================
|
||||
--- linux-2.6.27.orig/fs/seq_file.c
|
||||
+++ linux-2.6.27/fs/seq_file.c
|
||||
@@ -441,9 +441,7 @@ int seq_path_root(struct seq_file *m, st
|
||||
char *s = m->buf + m->count;
|
||||
char *p;
|
||||
|
||||
- spin_lock(&dcache_lock);
|
||||
- p = __d_path(path, root, s, m->size - m->count);
|
||||
- spin_unlock(&dcache_lock);
|
||||
+ p = __d_path(path, root, s, m->size - m->count, 0);
|
||||
err = PTR_ERR(p);
|
||||
if (!IS_ERR(p)) {
|
||||
s = mangle_path(s, p, esc);
|
||||
Index: linux-2.6.27/include/linux/dcache.h
|
||||
===================================================================
|
||||
--- linux-2.6.27.orig/include/linux/dcache.h
|
||||
+++ linux-2.6.27/include/linux/dcache.h
|
||||
@@ -299,9 +299,12 @@ extern int d_validate(struct dentry *, s
|
||||
/*
|
||||
* helper function for dentry_operations.d_dname() members
|
||||
*/
|
||||
+#define D_PATH_FAIL_DELETED 1
|
||||
+#define D_PATH_DISCONNECT 2
|
||||
extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...);
|
||||
|
||||
-extern char *__d_path(const struct path *path, struct path *root, char *, int);
|
||||
+extern char *__d_path(const struct path *path, struct path *root, char *, int,
|
||||
+ int);
|
||||
extern char *d_path(const struct path *, char *, int);
|
||||
extern char *dentry_path(struct dentry *, char *, int);
|
||||
|
||||
190
src/patches/suse-2.6.27.25/patches.apparmor/vfs-getxattr.diff
Normal file
190
src/patches/suse-2.6.27.25/patches.apparmor/vfs-getxattr.diff
Normal file
@@ -0,0 +1,190 @@
|
||||
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 | 15 ++++++++-------
|
||||
include/linux/nfsd/nfsd.h | 3 ++-
|
||||
include/linux/xattr.h | 2 +-
|
||||
5 files changed, 24 insertions(+), 19 deletions(-)
|
||||
|
||||
--- a/fs/nfsd/nfs4xdr.c
|
||||
+++ b/fs/nfsd/nfs4xdr.c
|
||||
@@ -1446,7 +1446,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_path.mnt, &acl);
|
||||
aclsupport = (err == 0);
|
||||
if (bmval0 & FATTR4_WORD0_ACL) {
|
||||
if (err == -EOPNOTSUPP)
|
||||
--- a/fs/nfsd/vfs.c
|
||||
+++ b/fs/nfsd/vfs.c
|
||||
@@ -420,11 +420,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;
|
||||
|
||||
@@ -432,7 +433,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
|
||||
|
||||
@@ -513,13 +514,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)
|
||||
@@ -531,14 +532,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)) {
|
||||
@@ -548,7 +550,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)) {
|
||||
@@ -2080,7 +2082,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_path.mnt, name,
|
||||
+ &value);
|
||||
if (size < 0)
|
||||
return ERR_PTR(size);
|
||||
|
||||
--- a/fs/xattr.c
|
||||
+++ b/fs/xattr.c
|
||||
@@ -131,7 +131,8 @@ out_noalloc:
|
||||
EXPORT_SYMBOL_GPL(xattr_getsecurity);
|
||||
|
||||
ssize_t
|
||||
-vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size)
|
||||
+vfs_getxattr(struct dentry *dentry, struct vfsmount *mnt, const char *name,
|
||||
+ void *value, size_t size)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int error;
|
||||
@@ -314,8 +315,8 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, cons
|
||||
* Extended attribute GET operations
|
||||
*/
|
||||
static ssize_t
|
||||
-getxattr(struct dentry *d, const char __user *name, void __user *value,
|
||||
- size_t size)
|
||||
+getxattr(struct dentry *dentry, struct vfsmount *mnt, const char __user *name,
|
||||
+ void __user *value, size_t size)
|
||||
{
|
||||
ssize_t error;
|
||||
void *kvalue = NULL;
|
||||
@@ -335,7 +336,7 @@ getxattr(struct dentry *d, const char __
|
||||
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;
|
||||
@@ -357,7 +358,7 @@ SYSCALL_DEFINE4(getxattr, const char __u
|
||||
error = user_path(pathname, &path);
|
||||
if (error)
|
||||
return error;
|
||||
- error = getxattr(path.dentry, name, value, size);
|
||||
+ error = getxattr(path.dentry, path.mnt, name, value, size);
|
||||
path_put(&path);
|
||||
return error;
|
||||
}
|
||||
@@ -371,7 +372,7 @@ SYSCALL_DEFINE4(lgetxattr, const char __
|
||||
error = user_lpath(pathname, &path);
|
||||
if (error)
|
||||
return error;
|
||||
- error = getxattr(path.dentry, name, value, size);
|
||||
+ error = getxattr(path.dentry, path.mnt, name, value, size);
|
||||
path_put(&path);
|
||||
return error;
|
||||
}
|
||||
@@ -386,7 +387,7 @@ SYSCALL_DEFINE4(fgetxattr, int, fd, cons
|
||||
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
|
||||
@@ -85,7 +85,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
|
||||
@@ -48,7 +48,7 @@ struct xattr_handler {
|
||||
};
|
||||
|
||||
ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t);
|
||||
-ssize_t vfs_getxattr(struct dentry *, const char *, void *, size_t);
|
||||
+ssize_t vfs_getxattr(struct dentry *, struct vfsmount *, const char *, void *, size_t);
|
||||
ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size);
|
||||
int vfs_setxattr(struct dentry *, struct vfsmount *, const char *, const void *, size_t, int);
|
||||
int vfs_removexattr(struct dentry *, const char *);
|
||||
91
src/patches/suse-2.6.27.25/patches.apparmor/vfs-link.diff
Normal file
91
src/patches/suse-2.6.27.25/patches.apparmor/vfs-link.diff
Normal file
@@ -0,0 +1,91 @@
|
||||
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 | 6 ++++--
|
||||
fs/nfsd/vfs.c | 3 ++-
|
||||
include/linux/fs.h | 2 +-
|
||||
4 files changed, 14 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/fs/ecryptfs/inode.c
|
||||
+++ b/fs/ecryptfs/inode.c
|
||||
@@ -403,19 +403,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
|
||||
@@ -2412,7 +2412,7 @@ SYSCALL_DEFINE2(symlink, const char __us
|
||||
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;
|
||||
@@ -2490,7 +2490,9 @@ SYSCALL_DEFINE5(linkat, int, olddfd, con
|
||||
error = mnt_want_write(nd.path.mnt);
|
||||
if (error)
|
||||
goto out_dput;
|
||||
- error = vfs_link(old_path.dentry, nd.path.dentry->d_inode, new_dentry);
|
||||
+ error = vfs_link(old_path.dentry, old_path.mnt,
|
||||
+ nd.path.dentry->d_inode,
|
||||
+ new_dentry, nd.path.mnt);
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
out_dput:
|
||||
dput(new_dentry);
|
||||
--- a/fs/nfsd/vfs.c
|
||||
+++ b/fs/nfsd/vfs.c
|
||||
@@ -1650,7 +1650,8 @@ nfsd_link(struct svc_rqst *rqstp, struct
|
||||
err = nfserrno(host_err);
|
||||
goto out_dput;
|
||||
}
|
||||
- host_err = vfs_link(dold, dirp, dnew);
|
||||
+ host_err = vfs_link(dold, tfhp->fh_export->ex_path.mnt, dirp,
|
||||
+ dnew, ffhp->fh_export->ex_path.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
|
||||
@@ -1181,7 +1181,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 *);
|
||||
-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 *);
|
||||
101
src/patches/suse-2.6.27.25/patches.apparmor/vfs-listxattr.diff
Normal file
101
src/patches/suse-2.6.27.25/patches.apparmor/vfs-listxattr.diff
Normal file
@@ -0,0 +1,101 @@
|
||||
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 | 2 +-
|
||||
2 files changed, 15 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/fs/xattr.c
|
||||
+++ b/fs/xattr.c
|
||||
@@ -168,18 +168,20 @@ nolsm:
|
||||
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;
|
||||
}
|
||||
@@ -396,7 +398,8 @@ SYSCALL_DEFINE4(fgetxattr, int, fd, cons
|
||||
* 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;
|
||||
@@ -409,7 +412,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;
|
||||
@@ -431,7 +434,7 @@ SYSCALL_DEFINE3(listxattr, const char __
|
||||
error = user_path(pathname, &path);
|
||||
if (error)
|
||||
return error;
|
||||
- error = listxattr(path.dentry, list, size);
|
||||
+ error = listxattr(path.dentry, path.mnt, list, size);
|
||||
path_put(&path);
|
||||
return error;
|
||||
}
|
||||
@@ -445,7 +448,7 @@ SYSCALL_DEFINE3(llistxattr, const char _
|
||||
error = user_lpath(pathname, &path);
|
||||
if (error)
|
||||
return error;
|
||||
- error = listxattr(path.dentry, list, size);
|
||||
+ error = listxattr(path.dentry, path.mnt, list, size);
|
||||
path_put(&path);
|
||||
return error;
|
||||
}
|
||||
@@ -459,7 +462,7 @@ SYSCALL_DEFINE3(flistxattr, int, fd, cha
|
||||
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
|
||||
@@ -49,7 +49,7 @@ struct xattr_handler {
|
||||
|
||||
ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t);
|
||||
ssize_t vfs_getxattr(struct dentry *, struct vfsmount *, const 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 *, const char *, const void *, size_t, int);
|
||||
int vfs_removexattr(struct dentry *, const char *);
|
||||
|
||||
137
src/patches/suse-2.6.27.25/patches.apparmor/vfs-mkdir.diff
Normal file
137
src/patches/suse-2.6.27.25/patches.apparmor/vfs-mkdir.diff
Normal file
@@ -0,0 +1,137 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Add struct vfsmount parameter to vfs_mkdir()
|
||||
|
||||
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 | 5 ++++-
|
||||
fs/namei.c | 5 +++--
|
||||
fs/nfsd/nfs4recover.c | 3 ++-
|
||||
fs/nfsd/vfs.c | 8 +++++---
|
||||
include/linux/fs.h | 2 +-
|
||||
kernel/cgroup.c | 2 +-
|
||||
6 files changed, 16 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/fs/ecryptfs/inode.c
|
||||
+++ b/fs/ecryptfs/inode.c
|
||||
@@ -501,11 +501,14 @@ static int ecryptfs_mkdir(struct inode *
|
||||
{
|
||||
int rc;
|
||||
struct dentry *lower_dentry;
|
||||
+ struct vfsmount *lower_mnt;
|
||||
struct dentry *lower_dir_dentry;
|
||||
|
||||
lower_dentry = ecryptfs_dentry_to_lower(dentry);
|
||||
+ lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
|
||||
lower_dir_dentry = lock_parent(lower_dentry);
|
||||
- rc = vfs_mkdir(lower_dir_dentry->d_inode, lower_dentry, mode);
|
||||
+ rc = vfs_mkdir(lower_dir_dentry->d_inode, lower_dentry, lower_mnt,
|
||||
+ mode);
|
||||
if (rc || !lower_dentry->d_inode)
|
||||
goto out;
|
||||
rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -2077,7 +2077,8 @@ SYSCALL_DEFINE3(mknod, const char __user
|
||||
return sys_mknodat(AT_FDCWD, filename, mode, dev);
|
||||
}
|
||||
|
||||
-int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
|
||||
+int vfs_mkdir(struct inode *dir, struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ int mode)
|
||||
{
|
||||
int error = may_create(dir, dentry, 1);
|
||||
|
||||
@@ -2120,7 +2121,7 @@ SYSCALL_DEFINE3(mkdirat, int, dfd, const
|
||||
error = mnt_want_write(nd.path.mnt);
|
||||
if (error)
|
||||
goto out_dput;
|
||||
- error = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode);
|
||||
+ error = vfs_mkdir(nd.path.dentry->d_inode, dentry, nd.path.mnt, mode);
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
out_dput:
|
||||
dput(dentry);
|
||||
--- a/fs/nfsd/nfs4recover.c
|
||||
+++ b/fs/nfsd/nfs4recover.c
|
||||
@@ -158,7 +158,8 @@ nfsd4_create_clid_dir(struct nfs4_client
|
||||
status = mnt_want_write(rec_dir.path.mnt);
|
||||
if (status)
|
||||
goto out_put;
|
||||
- status = vfs_mkdir(rec_dir.path.dentry->d_inode, dentry, S_IRWXU);
|
||||
+ status = vfs_mkdir(rec_dir.path.dentry->d_inode, dentry,
|
||||
+ rec_dir.path.mnt, S_IRWXU);
|
||||
mnt_drop_write(rec_dir.path.mnt);
|
||||
out_put:
|
||||
dput(dentry);
|
||||
--- a/fs/nfsd/vfs.c
|
||||
+++ b/fs/nfsd/vfs.c
|
||||
@@ -1215,6 +1215,7 @@ nfsd_create(struct svc_rqst *rqstp, stru
|
||||
int type, dev_t rdev, struct svc_fh *resfhp)
|
||||
{
|
||||
struct dentry *dentry, *dchild = NULL;
|
||||
+ struct svc_export *exp;
|
||||
struct inode *dirp;
|
||||
__be32 err;
|
||||
__be32 err2;
|
||||
@@ -1232,6 +1233,7 @@ nfsd_create(struct svc_rqst *rqstp, stru
|
||||
goto out;
|
||||
|
||||
dentry = fhp->fh_dentry;
|
||||
+ exp = fhp->fh_export;
|
||||
dirp = dentry->d_inode;
|
||||
|
||||
err = nfserr_notdir;
|
||||
@@ -1248,7 +1250,7 @@ nfsd_create(struct svc_rqst *rqstp, stru
|
||||
host_err = PTR_ERR(dchild);
|
||||
if (IS_ERR(dchild))
|
||||
goto out_nfserr;
|
||||
- err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
|
||||
+ err = fh_compose(resfhp, exp, dchild, fhp);
|
||||
if (err)
|
||||
goto out;
|
||||
} else {
|
||||
@@ -1298,7 +1300,7 @@ nfsd_create(struct svc_rqst *rqstp, stru
|
||||
host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
|
||||
break;
|
||||
case S_IFDIR:
|
||||
- host_err = vfs_mkdir(dirp, dchild, iap->ia_mode);
|
||||
+ host_err = vfs_mkdir(dirp, dchild, exp->ex_path.mnt, iap->ia_mode);
|
||||
break;
|
||||
case S_IFCHR:
|
||||
case S_IFBLK:
|
||||
@@ -1312,7 +1314,7 @@ nfsd_create(struct svc_rqst *rqstp, stru
|
||||
goto out_nfserr;
|
||||
}
|
||||
|
||||
- if (EX_ISSYNC(fhp->fh_export)) {
|
||||
+ if (EX_ISSYNC(exp)) {
|
||||
err = nfserrno(nfsd_sync_dir(dentry));
|
||||
write_inode_now(dchild->d_inode, 1);
|
||||
}
|
||||
--- a/include/linux/fs.h
|
||||
+++ b/include/linux/fs.h
|
||||
@@ -1178,7 +1178,7 @@ extern void unlock_super(struct super_bl
|
||||
*/
|
||||
extern int vfs_permission(struct nameidata *, int);
|
||||
extern int vfs_create(struct inode *, struct dentry *, int, struct nameidata *);
|
||||
-extern int vfs_mkdir(struct inode *, struct dentry *, int);
|
||||
+extern int vfs_mkdir(struct inode *, struct dentry *, struct vfsmount *, int);
|
||||
extern int vfs_mknod(struct inode *, struct dentry *, int, dev_t);
|
||||
extern int vfs_symlink(struct inode *, struct dentry *, const char *);
|
||||
extern int vfs_link(struct dentry *, struct inode *, struct dentry *);
|
||||
--- a/kernel/cgroup.c
|
||||
+++ b/kernel/cgroup.c
|
||||
@@ -2911,7 +2911,7 @@ int cgroup_clone(struct task_struct *tsk
|
||||
}
|
||||
|
||||
/* Create the cgroup directory, which also creates the cgroup */
|
||||
- ret = vfs_mkdir(inode, dentry, S_IFDIR | 0755);
|
||||
+ ret = vfs_mkdir(inode, dentry, NULL, S_IFDIR | 0755);
|
||||
child = __d_cgrp(dentry);
|
||||
dput(dentry);
|
||||
if (ret) {
|
||||
99
src/patches/suse-2.6.27.25/patches.apparmor/vfs-mknod.diff
Normal file
99
src/patches/suse-2.6.27.25/patches.apparmor/vfs-mknod.diff
Normal file
@@ -0,0 +1,99 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Add a struct vfsmount parameter to vfs_mknod()
|
||||
|
||||
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 | 5 ++++-
|
||||
fs/namei.c | 10 ++++++----
|
||||
fs/nfsd/vfs.c | 3 ++-
|
||||
include/linux/fs.h | 2 +-
|
||||
net/unix/af_unix.c | 3 ++-
|
||||
5 files changed, 15 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/fs/ecryptfs/inode.c
|
||||
+++ b/fs/ecryptfs/inode.c
|
||||
@@ -552,11 +552,14 @@ ecryptfs_mknod(struct inode *dir, struct
|
||||
{
|
||||
int rc;
|
||||
struct dentry *lower_dentry;
|
||||
+ struct vfsmount *lower_mnt;
|
||||
struct dentry *lower_dir_dentry;
|
||||
|
||||
lower_dentry = ecryptfs_dentry_to_lower(dentry);
|
||||
+ lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
|
||||
lower_dir_dentry = lock_parent(lower_dentry);
|
||||
- rc = vfs_mknod(lower_dir_dentry->d_inode, lower_dentry, mode, dev);
|
||||
+ rc = vfs_mknod(lower_dir_dentry->d_inode, lower_dentry, lower_mnt, mode,
|
||||
+ dev);
|
||||
if (rc || !lower_dentry->d_inode)
|
||||
goto out;
|
||||
rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -1976,7 +1976,8 @@ fail:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lookup_create);
|
||||
|
||||
-int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
|
||||
+int vfs_mknod(struct inode *dir, struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ int mode, dev_t dev)
|
||||
{
|
||||
int error = may_create(dir, dentry, 0);
|
||||
|
||||
@@ -2054,11 +2055,12 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const
|
||||
error = vfs_create(nd.path.dentry->d_inode,dentry,mode,&nd);
|
||||
break;
|
||||
case S_IFCHR: case S_IFBLK:
|
||||
- error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,
|
||||
- new_decode_dev(dev));
|
||||
+ error = vfs_mknod(nd.path.dentry->d_inode, dentry,
|
||||
+ nd.path, mode, new_decode_dev(dev));
|
||||
break;
|
||||
case S_IFIFO: case S_IFSOCK:
|
||||
- error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,0);
|
||||
+ error = vfs_mknod(nd.path.dentry->d_inode, dentry,
|
||||
+ nd.path, mode, 0);
|
||||
break;
|
||||
}
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
--- a/fs/nfsd/vfs.c
|
||||
+++ b/fs/nfsd/vfs.c
|
||||
@@ -1306,7 +1306,8 @@ nfsd_create(struct svc_rqst *rqstp, stru
|
||||
case S_IFBLK:
|
||||
case S_IFIFO:
|
||||
case S_IFSOCK:
|
||||
- host_err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
|
||||
+ host_err = vfs_mknod(dirp, dchild, exp->ex_path.mnt,
|
||||
+ iap->ia_mode, rdev);
|
||||
break;
|
||||
}
|
||||
if (host_err < 0) {
|
||||
--- a/include/linux/fs.h
|
||||
+++ b/include/linux/fs.h
|
||||
@@ -1179,7 +1179,7 @@ extern void unlock_super(struct super_bl
|
||||
extern int vfs_permission(struct nameidata *, int);
|
||||
extern int vfs_create(struct inode *, struct dentry *, int, struct nameidata *);
|
||||
extern int vfs_mkdir(struct inode *, struct dentry *, struct vfsmount *, int);
|
||||
-extern int vfs_mknod(struct inode *, struct dentry *, int, dev_t);
|
||||
+extern int vfs_mknod(struct inode *, struct dentry *, struct vfsmount *, int, dev_t);
|
||||
extern int vfs_symlink(struct inode *, struct dentry *, const char *);
|
||||
extern int vfs_link(struct dentry *, struct inode *, struct dentry *);
|
||||
extern int vfs_rmdir(struct inode *, struct dentry *);
|
||||
--- a/net/unix/af_unix.c
|
||||
+++ b/net/unix/af_unix.c
|
||||
@@ -827,7 +827,8 @@ static int unix_bind(struct socket *sock
|
||||
err = mnt_want_write(nd.path.mnt);
|
||||
if (err)
|
||||
goto out_mknod_dput;
|
||||
- err = vfs_mknod(nd.path.dentry->d_inode, dentry, mode, 0);
|
||||
+ err = vfs_mknod(nd.path.dentry->d_inode, dentry, nd.path.mnt,
|
||||
+ mode, 0);
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
if (err)
|
||||
goto out_mknod_dput;
|
||||
@@ -0,0 +1,291 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Add a vfsmount parameter to notify_change()
|
||||
|
||||
The vfsmount parameter must be set appropriately for files visibile
|
||||
outside the kernel. Files that are only used in a filesystem (e.g.,
|
||||
reiserfs xattr files) will have a NULL vfsmount.
|
||||
|
||||
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 | 3 ++-
|
||||
fs/ecryptfs/inode.c | 4 +++-
|
||||
fs/exec.c | 3 ++-
|
||||
fs/hpfs/namei.c | 2 +-
|
||||
fs/namei.c | 2 +-
|
||||
fs/nfsd/vfs.c | 8 ++++----
|
||||
fs/open.c | 28 +++++++++++++++-------------
|
||||
fs/utimes.c | 2 +-
|
||||
include/linux/fs.h | 6 +++---
|
||||
mm/filemap.c | 2 +-
|
||||
10 files changed, 33 insertions(+), 27 deletions(-)
|
||||
|
||||
--- a/fs/attr.c
|
||||
+++ b/fs/attr.c
|
||||
@@ -100,7 +100,8 @@ int inode_setattr(struct inode * inode,
|
||||
}
|
||||
EXPORT_SYMBOL(inode_setattr);
|
||||
|
||||
-int notify_change(struct dentry * dentry, struct iattr * attr)
|
||||
+int notify_change(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ struct iattr *attr)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
mode_t mode = inode->i_mode;
|
||||
--- a/fs/ecryptfs/inode.c
|
||||
+++ b/fs/ecryptfs/inode.c
|
||||
@@ -850,6 +850,7 @@ static int ecryptfs_setattr(struct dentr
|
||||
{
|
||||
int rc = 0;
|
||||
struct dentry *lower_dentry;
|
||||
+ struct vfsmount *lower_mnt;
|
||||
struct inode *inode;
|
||||
struct inode *lower_inode;
|
||||
struct ecryptfs_crypt_stat *crypt_stat;
|
||||
@@ -860,6 +861,7 @@ static int ecryptfs_setattr(struct dentr
|
||||
inode = dentry->d_inode;
|
||||
lower_inode = ecryptfs_inode_to_lower(inode);
|
||||
lower_dentry = ecryptfs_dentry_to_lower(dentry);
|
||||
+ lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
|
||||
mutex_lock(&crypt_stat->cs_mutex);
|
||||
if (S_ISDIR(dentry->d_inode->i_mode))
|
||||
crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
|
||||
@@ -911,7 +913,7 @@ static int ecryptfs_setattr(struct dentr
|
||||
ia->ia_valid &= ~ATTR_MODE;
|
||||
|
||||
mutex_lock(&lower_dentry->d_inode->i_mutex);
|
||||
- rc = notify_change(lower_dentry, ia);
|
||||
+ rc = notify_change(lower_dentry, lower_mnt, ia);
|
||||
mutex_unlock(&lower_dentry->d_inode->i_mutex);
|
||||
out:
|
||||
fsstack_copy_attr_all(inode, lower_inode, NULL);
|
||||
--- a/fs/exec.c
|
||||
+++ b/fs/exec.c
|
||||
@@ -1841,7 +1841,8 @@ int do_coredump(long signr, int exit_cod
|
||||
goto close_fail;
|
||||
if (!file->f_op->write)
|
||||
goto close_fail;
|
||||
- if (!ispipe && do_truncate(file->f_path.dentry, 0, 0, file) != 0)
|
||||
+ if (!ispipe &&
|
||||
+ do_truncate(file->f_path.dentry, file->f_path.mnt, 0, 0, file) != 0)
|
||||
goto close_fail;
|
||||
|
||||
retval = binfmt->core_dump(signr, regs, file, core_limit);
|
||||
--- a/fs/hpfs/namei.c
|
||||
+++ b/fs/hpfs/namei.c
|
||||
@@ -426,7 +426,7 @@ again:
|
||||
/*printk("HPFS: truncating file before delete.\n");*/
|
||||
newattrs.ia_size = 0;
|
||||
newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
|
||||
- err = notify_change(dentry, &newattrs);
|
||||
+ err = notify_change(dentry, NULL, &newattrs);
|
||||
put_write_access(inode);
|
||||
if (!err)
|
||||
goto again;
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -1619,7 +1619,7 @@ int may_open(struct nameidata *nd, int a
|
||||
if (!error) {
|
||||
DQUOT_INIT(inode);
|
||||
|
||||
- error = do_truncate(dentry, 0,
|
||||
+ error = do_truncate(dentry, nd->path.mnt, 0,
|
||||
ATTR_MTIME|ATTR_CTIME|ATTR_OPEN,
|
||||
NULL);
|
||||
}
|
||||
--- a/fs/nfsd/vfs.c
|
||||
+++ b/fs/nfsd/vfs.c
|
||||
@@ -397,7 +397,7 @@ nfsd_setattr(struct svc_rqst *rqstp, str
|
||||
err = nfserr_notsync;
|
||||
if (!check_guard || guardtime == inode->i_ctime.tv_sec) {
|
||||
fh_lock(fhp);
|
||||
- host_err = notify_change(dentry, iap);
|
||||
+ host_err = notify_change(dentry, fhp->fh_export->ex_path.mnt, iap);
|
||||
/* to get NFSERR_JUKEBOX on the wire, need -ETIMEDOUT */
|
||||
if (host_err == -EAGAIN)
|
||||
host_err = -ETIMEDOUT;
|
||||
@@ -964,13 +964,13 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
-static void kill_suid(struct dentry *dentry)
|
||||
+static void kill_suid(struct dentry *dentry, struct vfsmount *mnt)
|
||||
{
|
||||
struct iattr ia;
|
||||
ia.ia_valid = ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV;
|
||||
|
||||
mutex_lock(&dentry->d_inode->i_mutex);
|
||||
- notify_change(dentry, &ia);
|
||||
+ notify_change(dentry, mnt, &ia);
|
||||
mutex_unlock(&dentry->d_inode->i_mutex);
|
||||
}
|
||||
|
||||
@@ -1033,7 +1033,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, s
|
||||
|
||||
/* clear setuid/setgid flag after write */
|
||||
if (host_err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID)))
|
||||
- kill_suid(dentry);
|
||||
+ kill_suid(dentry, exp->ex_path.mnt);
|
||||
|
||||
if (host_err >= 0 && stable) {
|
||||
static ino_t last_ino;
|
||||
--- a/fs/open.c
|
||||
+++ b/fs/open.c
|
||||
@@ -195,8 +195,8 @@ out:
|
||||
return error;
|
||||
}
|
||||
|
||||
-int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
|
||||
- struct file *filp)
|
||||
+int do_truncate(struct dentry *dentry, struct vfsmount *mnt, loff_t length,
|
||||
+ unsigned int time_attrs, struct file *filp)
|
||||
{
|
||||
int err;
|
||||
struct iattr newattrs;
|
||||
@@ -216,7 +216,7 @@ int do_truncate(struct dentry *dentry, l
|
||||
newattrs.ia_valid |= should_remove_suid(dentry);
|
||||
|
||||
mutex_lock(&dentry->d_inode->i_mutex);
|
||||
- err = notify_change(dentry, &newattrs);
|
||||
+ err = notify_change(dentry, mnt, &newattrs);
|
||||
mutex_unlock(&dentry->d_inode->i_mutex);
|
||||
return err;
|
||||
}
|
||||
@@ -272,7 +272,7 @@ static long do_sys_truncate(const char _
|
||||
error = locks_verify_truncate(inode, NULL, length);
|
||||
if (!error) {
|
||||
DQUOT_INIT(inode);
|
||||
- error = do_truncate(path.dentry, length, 0, NULL);
|
||||
+ error = do_truncate(path.dentry, path.mnt, length, 0, NULL);
|
||||
}
|
||||
|
||||
put_write_and_out:
|
||||
@@ -327,7 +327,8 @@ static long do_sys_ftruncate(unsigned in
|
||||
|
||||
error = locks_verify_truncate(inode, file, length);
|
||||
if (!error)
|
||||
- error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file);
|
||||
+ error = do_truncate(dentry, file->f_path.mnt, length,
|
||||
+ ATTR_MTIME|ATTR_CTIME, file);
|
||||
out_putf:
|
||||
fput(file);
|
||||
out:
|
||||
@@ -624,7 +625,7 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd
|
||||
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, &newattrs);
|
||||
+ err = notify_change(dentry, file->f_path.mnt, &newattrs);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
mnt_drop_write(file->f_path.mnt);
|
||||
out_putf:
|
||||
@@ -653,7 +654,7 @@ SYSCALL_DEFINE3(fchmodat, int, dfd, cons
|
||||
mode = inode->i_mode;
|
||||
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
|
||||
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
|
||||
- error = notify_change(path.dentry, &newattrs);
|
||||
+ error = notify_change(path.dentry, path.mnt, &newattrs);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
mnt_drop_write(path.mnt);
|
||||
dput_and_out:
|
||||
@@ -667,7 +668,8 @@ SYSCALL_DEFINE2(chmod, const char __user
|
||||
return sys_fchmodat(AT_FDCWD, filename, mode);
|
||||
}
|
||||
|
||||
-static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
|
||||
+static int chown_common(struct dentry * dentry, struct vfsmount *mnt,
|
||||
+ uid_t user, gid_t group)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int error;
|
||||
@@ -686,7 +688,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, &newattrs);
|
||||
+ error = notify_change(dentry, mnt, &newattrs);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
|
||||
return error;
|
||||
@@ -703,7 +705,7 @@ SYSCALL_DEFINE3(chown, const char __user
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (error)
|
||||
goto out_release;
|
||||
- error = chown_common(path.dentry, user, group);
|
||||
+ error = chown_common(path.dentry, path.mnt, user, group);
|
||||
mnt_drop_write(path.mnt);
|
||||
out_release:
|
||||
path_put(&path);
|
||||
@@ -728,7 +730,7 @@ SYSCALL_DEFINE5(fchownat, int, dfd, cons
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (error)
|
||||
goto out_release;
|
||||
- error = chown_common(path.dentry, user, group);
|
||||
+ error = chown_common(path.dentry, path.mnt, user, group);
|
||||
mnt_drop_write(path.mnt);
|
||||
out_release:
|
||||
path_put(&path);
|
||||
@@ -747,7 +749,7 @@ SYSCALL_DEFINE3(lchown, const char __use
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (error)
|
||||
goto out_release;
|
||||
- error = chown_common(path.dentry, user, group);
|
||||
+ error = chown_common(path.dentry, path.mnt, user, group);
|
||||
mnt_drop_write(path.mnt);
|
||||
out_release:
|
||||
path_put(&path);
|
||||
@@ -770,7 +772,7 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd
|
||||
goto out_fput;
|
||||
dentry = file->f_path.dentry;
|
||||
audit_inode(NULL, dentry);
|
||||
- error = chown_common(dentry, user, group);
|
||||
+ error = chown_common(dentry, file->f_path.mnt, user, group);
|
||||
mnt_drop_write(file->f_path.mnt);
|
||||
out_fput:
|
||||
fput(file);
|
||||
--- a/fs/utimes.c
|
||||
+++ b/fs/utimes.c
|
||||
@@ -102,7 +102,7 @@ static int utimes_common(struct path *pa
|
||||
}
|
||||
}
|
||||
mutex_lock(&inode->i_mutex);
|
||||
- error = notify_change(path->dentry, &newattrs);
|
||||
+ error = notify_change(path->dentry, path->mnt, &newattrs);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
|
||||
mnt_drop_write_and_out:
|
||||
--- a/include/linux/fs.h
|
||||
+++ b/include/linux/fs.h
|
||||
@@ -1636,8 +1636,8 @@ static inline int break_lease(struct ino
|
||||
|
||||
/* fs/open.c */
|
||||
|
||||
-extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs,
|
||||
- struct file *filp);
|
||||
+extern int do_truncate(struct dentry *, struct vfsmount *, loff_t start,
|
||||
+ unsigned int time_attrs, struct file *filp);
|
||||
extern long do_sys_open(int dfd, const char __user *filename, int flags,
|
||||
int mode);
|
||||
extern struct file *filp_open(const char *, int, int);
|
||||
@@ -1798,7 +1798,7 @@ extern int do_remount_sb(struct super_bl
|
||||
#ifdef CONFIG_BLOCK
|
||||
extern sector_t bmap(struct inode *, sector_t);
|
||||
#endif
|
||||
-extern int notify_change(struct dentry *, struct iattr *);
|
||||
+extern int notify_change(struct dentry *, struct vfsmount *, struct iattr *);
|
||||
extern int inode_permission(struct inode *, int);
|
||||
extern int generic_permission(struct inode *, int,
|
||||
int (*check_acl)(struct inode *, int));
|
||||
--- a/mm/filemap.c
|
||||
+++ b/mm/filemap.c
|
||||
@@ -1831,7 +1831,7 @@ static int __remove_suid(struct path *pa
|
||||
struct iattr newattrs;
|
||||
|
||||
newattrs.ia_valid = ATTR_FORCE | kill;
|
||||
- return notify_change(path->dentry, &newattrs);
|
||||
+ return notify_change(path->dentry, path->mnt, &newattrs);
|
||||
}
|
||||
|
||||
int file_remove_suid(struct file *file)
|
||||
121
src/patches/suse-2.6.27.25/patches.apparmor/vfs-removexattr.diff
Normal file
121
src/patches/suse-2.6.27.25/patches.apparmor/vfs-removexattr.diff
Normal file
@@ -0,0 +1,121 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Add a struct vfsmount parameter to vfs_removexattr()
|
||||
|
||||
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/vfs.c | 11 ++++++-----
|
||||
fs/xattr.c | 12 ++++++------
|
||||
include/linux/xattr.h | 2 +-
|
||||
3 files changed, 13 insertions(+), 12 deletions(-)
|
||||
|
||||
--- linux-2.6.27.orig/fs/nfsd/vfs.c
|
||||
+++ linux-2.6.27/fs/nfsd/vfs.c
|
||||
@@ -2095,6 +2095,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 vfsmount *mnt;
|
||||
struct inode *inode = fhp->fh_dentry->d_inode;
|
||||
char *name;
|
||||
void *value = NULL;
|
||||
@@ -2127,22 +2128,22 @@ nfsd_set_posix_acl(struct svc_fh *fhp, i
|
||||
} else
|
||||
size = 0;
|
||||
|
||||
- error = mnt_want_write(fhp->fh_export->ex_path.mnt);
|
||||
+ mnt = fhp->fh_export->ex_path.mnt;
|
||||
+ error = mnt_want_write(mnt);
|
||||
if (error)
|
||||
goto getout;
|
||||
if (size)
|
||||
- error = vfs_setxattr(fhp->fh_dentry, fhp->fh_export->ex_path.mnt,
|
||||
- name, value, size,0);
|
||||
+ error = vfs_setxattr(fhp->fh_dentry, mnt, 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_dentry, mnt, name);
|
||||
if (error == -ENODATA)
|
||||
error = 0;
|
||||
}
|
||||
}
|
||||
- mnt_drop_write(fhp->fh_export->ex_path.mnt);
|
||||
+ mnt_drop_write(mnt);
|
||||
|
||||
getout:
|
||||
kfree(value);
|
||||
--- linux-2.6.27.orig/fs/xattr.c
|
||||
+++ linux-2.6.27/fs/xattr.c
|
||||
@@ -190,7 +190,7 @@ vfs_listxattr(struct dentry *dentry, str
|
||||
EXPORT_SYMBOL_GPL(vfs_listxattr);
|
||||
|
||||
int
|
||||
-vfs_removexattr(struct dentry *dentry, const char *name)
|
||||
+vfs_removexattr(struct dentry *dentry, struct vfsmount *mnt, const char *name)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int error;
|
||||
@@ -471,7 +471,7 @@ SYSCALL_DEFINE3(flistxattr, int, fd, cha
|
||||
* Extended attribute REMOVE operations
|
||||
*/
|
||||
static long
|
||||
-removexattr(struct dentry *d, const char __user *name)
|
||||
+removexattr(struct dentry *dentry, struct vfsmount *mnt, const char __user *name)
|
||||
{
|
||||
int error;
|
||||
char kname[XATTR_NAME_MAX + 1];
|
||||
@@ -482,7 +482,7 @@ removexattr(struct dentry *d, const char
|
||||
if (error < 0)
|
||||
return error;
|
||||
|
||||
- return vfs_removexattr(d, kname);
|
||||
+ return vfs_removexattr(dentry, mnt, kname);
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE2(removexattr, const char __user *, pathname,
|
||||
@@ -496,7 +496,7 @@ SYSCALL_DEFINE2(removexattr, const char
|
||||
return error;
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (!error) {
|
||||
- error = removexattr(path.dentry, name);
|
||||
+ error = removexattr(path.dentry, path.mnt, name);
|
||||
mnt_drop_write(path.mnt);
|
||||
}
|
||||
path_put(&path);
|
||||
@@ -514,7 +514,7 @@ SYSCALL_DEFINE2(lremovexattr, const char
|
||||
return error;
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (!error) {
|
||||
- error = removexattr(path.dentry, name);
|
||||
+ error = removexattr(path.dentry, path.mnt, name);
|
||||
mnt_drop_write(path.mnt);
|
||||
}
|
||||
path_put(&path);
|
||||
@@ -534,7 +534,7 @@ SYSCALL_DEFINE2(fremovexattr, int, fd, c
|
||||
audit_inode(NULL, dentry);
|
||||
error = mnt_want_write_file(f->f_path.mnt, f);
|
||||
if (!error) {
|
||||
- error = removexattr(dentry, name);
|
||||
+ error = removexattr(dentry, f->f_path.mnt, name);
|
||||
mnt_drop_write(f->f_path.mnt);
|
||||
}
|
||||
fput(f);
|
||||
--- linux-2.6.27.orig/include/linux/xattr.h
|
||||
+++ linux-2.6.27/include/linux/xattr.h
|
||||
@@ -51,7 +51,7 @@ ssize_t xattr_getsecurity(struct inode *
|
||||
ssize_t vfs_getxattr(struct dentry *, struct vfsmount *, const char *, void *, size_t);
|
||||
ssize_t vfs_listxattr(struct dentry *d, struct vfsmount *, char *list, size_t size);
|
||||
int vfs_setxattr(struct dentry *, struct vfsmount *, const char *, const void *, size_t, int);
|
||||
-int vfs_removexattr(struct dentry *, const char *);
|
||||
+int vfs_removexattr(struct dentry *, struct vfsmount *mnt, const char *);
|
||||
|
||||
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);
|
||||
125
src/patches/suse-2.6.27.25/patches.apparmor/vfs-rename.diff
Normal file
125
src/patches/suse-2.6.27.25/patches.apparmor/vfs-rename.diff
Normal file
@@ -0,0 +1,125 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Add struct vfsmount parameters to vfs_rename()
|
||||
|
||||
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 | 7 ++++++-
|
||||
fs/namei.c | 19 ++++++++++++-------
|
||||
fs/nfsd/vfs.c | 3 ++-
|
||||
include/linux/fs.h | 2 +-
|
||||
4 files changed, 21 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/fs/ecryptfs/inode.c
|
||||
+++ b/fs/ecryptfs/inode.c
|
||||
@@ -590,19 +590,24 @@ ecryptfs_rename(struct inode *old_dir, s
|
||||
{
|
||||
int rc;
|
||||
struct dentry *lower_old_dentry;
|
||||
+ struct vfsmount *lower_old_mnt;
|
||||
struct dentry *lower_new_dentry;
|
||||
+ struct vfsmount *lower_new_mnt;
|
||||
struct dentry *lower_old_dir_dentry;
|
||||
struct dentry *lower_new_dir_dentry;
|
||||
|
||||
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_old_dir_dentry = dget_parent(lower_old_dentry);
|
||||
lower_new_dir_dentry = dget_parent(lower_new_dentry);
|
||||
lock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
|
||||
rc = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry,
|
||||
- lower_new_dir_dentry->d_inode, lower_new_dentry);
|
||||
+ lower_old_mnt, lower_new_dir_dentry->d_inode,
|
||||
+ lower_new_dentry, lower_new_mnt);
|
||||
if (rc)
|
||||
goto out_lock;
|
||||
fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode, NULL);
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -2547,7 +2547,8 @@ SYSCALL_DEFINE2(link, const char __user
|
||||
* locking].
|
||||
*/
|
||||
static int vfs_rename_dir(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 error = 0;
|
||||
struct inode *target;
|
||||
@@ -2590,7 +2591,8 @@ static int vfs_rename_dir(struct inode *
|
||||
}
|
||||
|
||||
static int vfs_rename_other(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)
|
||||
{
|
||||
struct inode *target;
|
||||
int error;
|
||||
@@ -2618,7 +2620,8 @@ static int vfs_rename_other(struct inode
|
||||
}
|
||||
|
||||
int vfs_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 error;
|
||||
int is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
|
||||
@@ -2647,9 +2650,11 @@ int vfs_rename(struct inode *old_dir, st
|
||||
old_name = fsnotify_oldname_init(old_dentry->d_name.name);
|
||||
|
||||
if (is_dir)
|
||||
- error = vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry);
|
||||
+ error = vfs_rename_dir(old_dir, old_dentry, old_mnt,
|
||||
+ new_dir, new_dentry, new_mnt);
|
||||
else
|
||||
- error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry);
|
||||
+ error = vfs_rename_other(old_dir, old_dentry, old_mnt,
|
||||
+ new_dir, new_dentry, new_mnt);
|
||||
if (!error) {
|
||||
const char *new_name = old_dentry->d_name.name;
|
||||
fsnotify_move(old_dir, new_dir, old_name, new_name, is_dir,
|
||||
@@ -2726,8 +2731,8 @@ SYSCALL_DEFINE4(renameat, int, olddfd, c
|
||||
error = mnt_want_write(oldnd.path.mnt);
|
||||
if (error)
|
||||
goto exit5;
|
||||
- error = vfs_rename(old_dir->d_inode, old_dentry,
|
||||
- new_dir->d_inode, new_dentry);
|
||||
+ error = vfs_rename(old_dir->d_inode, old_dentry, oldnd.path.mnt,
|
||||
+ new_dir->d_inode, new_dentry, newnd.path.mnt);
|
||||
mnt_drop_write(oldnd.path.mnt);
|
||||
exit5:
|
||||
dput(new_dentry);
|
||||
--- a/fs/nfsd/vfs.c
|
||||
+++ b/fs/nfsd/vfs.c
|
||||
@@ -1752,7 +1752,8 @@ nfsd_rename(struct svc_rqst *rqstp, stru
|
||||
if (host_err)
|
||||
goto out_dput_new;
|
||||
|
||||
- host_err = vfs_rename(fdir, odentry, tdir, ndentry);
|
||||
+ host_err = vfs_rename(fdir, odentry, ffhp->fh_export->ex_path.mnt,
|
||||
+ tdir, ndentry, tfhp->fh_export->ex_path.mnt);
|
||||
if (!host_err && EX_ISSYNC(tfhp->fh_export)) {
|
||||
host_err = nfsd_sync_dir(tdentry);
|
||||
if (!host_err)
|
||||
--- a/include/linux/fs.h
|
||||
+++ b/include/linux/fs.h
|
||||
@@ -1184,7 +1184,7 @@ extern int vfs_symlink(struct inode *, s
|
||||
extern int vfs_link(struct dentry *, struct vfsmount *, struct inode *, struct dentry *, struct vfsmount *);
|
||||
extern int vfs_rmdir(struct inode *, struct dentry *, struct vfsmount *);
|
||||
extern int vfs_unlink(struct inode *, struct dentry *, struct vfsmount *);
|
||||
-extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
|
||||
+extern int vfs_rename(struct inode *, struct dentry *, struct vfsmount *, struct inode *, struct dentry *, struct vfsmount *);
|
||||
|
||||
/*
|
||||
* VFS dentry helper functions.
|
||||
123
src/patches/suse-2.6.27.25/patches.apparmor/vfs-rmdir.diff
Normal file
123
src/patches/suse-2.6.27.25/patches.apparmor/vfs-rmdir.diff
Normal file
@@ -0,0 +1,123 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Add a struct vfsmount parameter to vfs_rmdir()
|
||||
|
||||
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 | 4 +++-
|
||||
fs/namei.c | 4 ++--
|
||||
fs/nfsd/nfs4recover.c | 2 +-
|
||||
fs/nfsd/vfs.c | 8 +++++---
|
||||
include/linux/fs.h | 2 +-
|
||||
5 files changed, 12 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/fs/ecryptfs/inode.c
|
||||
+++ b/fs/ecryptfs/inode.c
|
||||
@@ -534,14 +534,16 @@ out:
|
||||
static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
{
|
||||
struct dentry *lower_dentry;
|
||||
+ struct vfsmount *lower_mnt;
|
||||
struct dentry *lower_dir_dentry;
|
||||
int rc;
|
||||
|
||||
lower_dentry = ecryptfs_dentry_to_lower(dentry);
|
||||
+ lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
|
||||
dget(dentry);
|
||||
lower_dir_dentry = lock_parent(lower_dentry);
|
||||
dget(lower_dentry);
|
||||
- rc = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry);
|
||||
+ rc = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry, lower_mnt);
|
||||
dput(lower_dentry);
|
||||
if (!rc)
|
||||
d_delete(lower_dentry);
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -2167,7 +2167,7 @@ void dentry_unhash(struct dentry *dentry
|
||||
spin_unlock(&dcache_lock);
|
||||
}
|
||||
|
||||
-int vfs_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
+int vfs_rmdir(struct inode *dir, struct dentry *dentry,struct vfsmount *mnt)
|
||||
{
|
||||
int error = may_delete(dir, dentry, 1);
|
||||
|
||||
@@ -2230,7 +2230,7 @@ static long do_rmdir(int dfd, const char
|
||||
error = mnt_want_write(nd.path.mnt);
|
||||
if (error)
|
||||
goto exit3;
|
||||
- error = vfs_rmdir(nd.path.dentry->d_inode, dentry);
|
||||
+ error = vfs_rmdir(nd.path.dentry->d_inode, dentry, nd.path.mnt);
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
exit3:
|
||||
dput(dentry);
|
||||
--- a/fs/nfsd/nfs4recover.c
|
||||
+++ b/fs/nfsd/nfs4recover.c
|
||||
@@ -279,7 +279,7 @@ nfsd4_clear_clid_dir(struct dentry *dir,
|
||||
* a kernel from the future.... */
|
||||
nfsd4_list_rec_dir(dentry, nfsd4_remove_clid_file);
|
||||
mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
|
||||
- status = vfs_rmdir(dir->d_inode, dentry);
|
||||
+ status = vfs_rmdir(dir->d_inode, dentry, rec_dir.path.mnt);
|
||||
mutex_unlock(&dir->d_inode->i_mutex);
|
||||
return status;
|
||||
}
|
||||
--- a/fs/nfsd/vfs.c
|
||||
+++ b/fs/nfsd/vfs.c
|
||||
@@ -1790,6 +1790,7 @@ nfsd_unlink(struct svc_rqst *rqstp, stru
|
||||
char *fname, int flen)
|
||||
{
|
||||
struct dentry *dentry, *rdentry;
|
||||
+ struct svc_export *exp;
|
||||
struct inode *dirp;
|
||||
__be32 err;
|
||||
int host_err;
|
||||
@@ -1804,6 +1805,7 @@ nfsd_unlink(struct svc_rqst *rqstp, stru
|
||||
fh_lock_nested(fhp, I_MUTEX_PARENT);
|
||||
dentry = fhp->fh_dentry;
|
||||
dirp = dentry->d_inode;
|
||||
+ exp = fhp->fh_export;
|
||||
|
||||
rdentry = lookup_one_len(fname, dentry, flen);
|
||||
host_err = PTR_ERR(rdentry);
|
||||
@@ -1825,21 +1827,21 @@ nfsd_unlink(struct svc_rqst *rqstp, stru
|
||||
|
||||
if (type != S_IFDIR) { /* It's UNLINK */
|
||||
#ifdef MSNFS
|
||||
- if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
|
||||
+ if ((exp->ex_flags & NFSEXP_MSNFS) &&
|
||||
(atomic_read(&rdentry->d_count) > 1)) {
|
||||
host_err = -EPERM;
|
||||
} else
|
||||
#endif
|
||||
host_err = vfs_unlink(dirp, rdentry);
|
||||
} else { /* It's RMDIR */
|
||||
- host_err = vfs_rmdir(dirp, rdentry);
|
||||
+ host_err = vfs_rmdir(dirp, rdentry, exp->ex_path.mnt);
|
||||
}
|
||||
|
||||
dput(rdentry);
|
||||
|
||||
if (host_err)
|
||||
goto out_drop;
|
||||
- if (EX_ISSYNC(fhp->fh_export))
|
||||
+ if (EX_ISSYNC(exp))
|
||||
host_err = nfsd_sync_dir(dentry);
|
||||
|
||||
out_drop:
|
||||
--- a/include/linux/fs.h
|
||||
+++ b/include/linux/fs.h
|
||||
@@ -1182,7 +1182,7 @@ extern int vfs_mkdir(struct inode *, str
|
||||
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 *);
|
||||
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_rmdir(struct inode *, struct dentry *, struct vfsmount *);
|
||||
extern int vfs_unlink(struct inode *, struct dentry *);
|
||||
extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
|
||||
|
||||
159
src/patches/suse-2.6.27.25/patches.apparmor/vfs-setxattr.diff
Normal file
159
src/patches/suse-2.6.27.25/patches.apparmor/vfs-setxattr.diff
Normal file
@@ -0,0 +1,159 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Add a struct vfsmount parameter to vfs_setxattr()
|
||||
|
||||
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/vfs.c | 16 +++++++++++-----
|
||||
fs/xattr.c | 16 ++++++++--------
|
||||
include/linux/xattr.h | 3 ++-
|
||||
3 files changed, 21 insertions(+), 14 deletions(-)
|
||||
|
||||
--- linux-2.6.27.orig/fs/nfsd/vfs.c
|
||||
+++ linux-2.6.27/fs/nfsd/vfs.c
|
||||
@@ -438,7 +438,8 @@ static ssize_t nfsd_getxattr(struct dent
|
||||
|
||||
#if defined(CONFIG_NFSD_V4)
|
||||
static int
|
||||
-set_nfsv4_acl_one(struct dentry *dentry, struct posix_acl *pacl, char *key)
|
||||
+set_nfsv4_acl_one(struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ struct posix_acl *pacl, char *key)
|
||||
{
|
||||
int len;
|
||||
size_t buflen;
|
||||
@@ -457,7 +458,7 @@ set_nfsv4_acl_one(struct dentry *dentry,
|
||||
goto out;
|
||||
}
|
||||
|
||||
- error = vfs_setxattr(dentry, key, buf, len, 0);
|
||||
+ error = vfs_setxattr(dentry, mnt, key, buf, len, 0);
|
||||
out:
|
||||
kfree(buf);
|
||||
return error;
|
||||
@@ -470,6 +471,7 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqst
|
||||
__be32 error;
|
||||
int host_error;
|
||||
struct dentry *dentry;
|
||||
+ struct vfsmount *mnt;
|
||||
struct inode *inode;
|
||||
struct posix_acl *pacl = NULL, *dpacl = NULL;
|
||||
unsigned int flags = 0;
|
||||
@@ -480,6 +482,7 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqst
|
||||
return error;
|
||||
|
||||
dentry = fhp->fh_dentry;
|
||||
+ mnt = fhp->fh_export->ex_path.mnt;
|
||||
inode = dentry->d_inode;
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
flags = NFS4_ACL_DIR;
|
||||
@@ -490,12 +493,14 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqst
|
||||
} else if (host_error < 0)
|
||||
goto out_nfserr;
|
||||
|
||||
- host_error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS);
|
||||
+ host_error = set_nfsv4_acl_one(dentry, mnt, pacl,
|
||||
+ POSIX_ACL_XATTR_ACCESS);
|
||||
if (host_error < 0)
|
||||
goto out_release;
|
||||
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
- host_error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT);
|
||||
+ host_error = set_nfsv4_acl_one(dentry, mnt, dpacl,
|
||||
+ POSIX_ACL_XATTR_DEFAULT);
|
||||
|
||||
out_release:
|
||||
posix_acl_release(pacl);
|
||||
@@ -2123,7 +2128,8 @@ nfsd_set_posix_acl(struct svc_fh *fhp, i
|
||||
if (error)
|
||||
goto getout;
|
||||
if (size)
|
||||
- error = vfs_setxattr(fhp->fh_dentry, name, value, size, 0);
|
||||
+ error = vfs_setxattr(fhp->fh_dentry, fhp->fh_export->ex_path.mnt,
|
||||
+ name, value, size,0);
|
||||
else {
|
||||
if (!S_ISDIR(inode->i_mode) && type == ACL_TYPE_DEFAULT)
|
||||
error = 0;
|
||||
--- linux-2.6.27.orig/fs/xattr.c
|
||||
+++ linux-2.6.27/fs/xattr.c
|
||||
@@ -67,8 +67,8 @@ xattr_permission(struct inode *inode, co
|
||||
}
|
||||
|
||||
int
|
||||
-vfs_setxattr(struct dentry *dentry, const char *name, const void *value,
|
||||
- size_t size, int flags)
|
||||
+vfs_setxattr(struct dentry *dentry, struct vfsmount *mnt, const char *name,
|
||||
+ const void *value, size_t size, int flags)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int error;
|
||||
@@ -218,8 +218,8 @@ EXPORT_SYMBOL_GPL(vfs_removexattr);
|
||||
* Extended attribute SET operations
|
||||
*/
|
||||
static long
|
||||
-setxattr(struct dentry *d, const char __user *name, const void __user *value,
|
||||
- size_t size, int flags)
|
||||
+setxattr(struct dentry *dentry, struct vfsmount *mnt, const char __user *name,
|
||||
+ const void __user *value, size_t size, int flags)
|
||||
{
|
||||
int error;
|
||||
void *kvalue = NULL;
|
||||
@@ -246,7 +246,7 @@ setxattr(struct dentry *d, const char __
|
||||
}
|
||||
}
|
||||
|
||||
- error = vfs_setxattr(d, kname, kvalue, size, flags);
|
||||
+ error = vfs_setxattr(dentry, mnt, kname, kvalue, size, flags);
|
||||
kfree(kvalue);
|
||||
return error;
|
||||
}
|
||||
@@ -263,7 +263,7 @@ SYSCALL_DEFINE5(setxattr, const char __u
|
||||
return error;
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (!error) {
|
||||
- error = setxattr(path.dentry, name, value, size, flags);
|
||||
+ error = setxattr(path.dentry, path.mnt, name, value, size, flags);
|
||||
mnt_drop_write(path.mnt);
|
||||
}
|
||||
path_put(&path);
|
||||
@@ -282,7 +282,7 @@ SYSCALL_DEFINE5(lsetxattr, const char __
|
||||
return error;
|
||||
error = mnt_want_write(path.mnt);
|
||||
if (!error) {
|
||||
- error = setxattr(path.dentry, name, value, size, flags);
|
||||
+ error = setxattr(path.dentry, path.mnt, name, value, size, flags);
|
||||
mnt_drop_write(path.mnt);
|
||||
}
|
||||
path_put(&path);
|
||||
@@ -303,7 +303,7 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, cons
|
||||
audit_inode(NULL, dentry);
|
||||
error = mnt_want_write_file(f->f_path.mnt, f);
|
||||
if (!error) {
|
||||
- error = setxattr(dentry, name, value, size, flags);
|
||||
+ error = setxattr(dentry, f->f_vfsmnt, name, value, size, flags);
|
||||
mnt_drop_write(f->f_path.mnt);
|
||||
}
|
||||
fput(f);
|
||||
--- linux-2.6.27.orig/include/linux/xattr.h
|
||||
+++ linux-2.6.27/include/linux/xattr.h
|
||||
@@ -16,6 +16,7 @@
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <linux/types.h>
|
||||
+#include <linux/mount.h>
|
||||
|
||||
/* Namespaces */
|
||||
#define XATTR_OS2_PREFIX "os2."
|
||||
@@ -49,7 +50,7 @@ struct xattr_handler {
|
||||
ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t);
|
||||
ssize_t vfs_getxattr(struct dentry *, const char *, void *, size_t);
|
||||
ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size);
|
||||
-int vfs_setxattr(struct dentry *, const char *, const void *, size_t, int);
|
||||
+int vfs_setxattr(struct dentry *, struct vfsmount *, const char *, const void *, size_t, int);
|
||||
int vfs_removexattr(struct dentry *, const char *);
|
||||
|
||||
ssize_t generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size);
|
||||
123
src/patches/suse-2.6.27.25/patches.apparmor/vfs-symlink.diff
Normal file
123
src/patches/suse-2.6.27.25/patches.apparmor/vfs-symlink.diff
Normal file
@@ -0,0 +1,123 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Add a struct vfsmount parameter to vfs_symlink()
|
||||
|
||||
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 | 4 +++-
|
||||
fs/namei.c | 5 +++--
|
||||
fs/nfsd/vfs.c | 12 ++++++++----
|
||||
include/linux/fs.h | 2 +-
|
||||
4 files changed, 15 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/fs/ecryptfs/inode.c
|
||||
+++ b/fs/ecryptfs/inode.c
|
||||
@@ -464,6 +464,7 @@ static int ecryptfs_symlink(struct inode
|
||||
{
|
||||
int rc;
|
||||
struct dentry *lower_dentry;
|
||||
+ struct vfsmount *lower_mnt;
|
||||
struct dentry *lower_dir_dentry;
|
||||
char *encoded_symname;
|
||||
int encoded_symlen;
|
||||
@@ -471,6 +472,7 @@ static int ecryptfs_symlink(struct inode
|
||||
|
||||
lower_dentry = ecryptfs_dentry_to_lower(dentry);
|
||||
dget(lower_dentry);
|
||||
+ lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
|
||||
lower_dir_dentry = lock_parent(lower_dentry);
|
||||
encoded_symlen = ecryptfs_encode_filename(crypt_stat, symname,
|
||||
strlen(symname),
|
||||
@@ -479,7 +481,7 @@ static int ecryptfs_symlink(struct inode
|
||||
rc = encoded_symlen;
|
||||
goto out_lock;
|
||||
}
|
||||
- rc = vfs_symlink(lower_dir_dentry->d_inode, lower_dentry,
|
||||
+ rc = vfs_symlink(lower_dir_dentry->d_inode, lower_dentry, lower_mnt,
|
||||
encoded_symname);
|
||||
kfree(encoded_symname);
|
||||
if (rc || !lower_dentry->d_inode)
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -2347,7 +2347,8 @@ SYSCALL_DEFINE1(unlink, const char __use
|
||||
return do_unlinkat(AT_FDCWD, pathname);
|
||||
}
|
||||
|
||||
-int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
|
||||
+int vfs_symlink(struct inode *dir, struct dentry *dentry, struct vfsmount *mnt,
|
||||
+ const char *oldname)
|
||||
{
|
||||
int error = may_create(dir, dentry, 0);
|
||||
|
||||
@@ -2393,7 +2394,7 @@ SYSCALL_DEFINE3(symlinkat, const char __
|
||||
error = mnt_want_write(nd.path.mnt);
|
||||
if (error)
|
||||
goto out_dput;
|
||||
- error = vfs_symlink(nd.path.dentry->d_inode, dentry, from);
|
||||
+ error = vfs_symlink(nd.path.dentry->d_inode, dentry, nd.path.mnt, from);
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
out_dput:
|
||||
dput(dentry);
|
||||
--- a/fs/nfsd/vfs.c
|
||||
+++ b/fs/nfsd/vfs.c
|
||||
@@ -1545,6 +1545,7 @@ nfsd_symlink(struct svc_rqst *rqstp, str
|
||||
struct iattr *iap)
|
||||
{
|
||||
struct dentry *dentry, *dnew;
|
||||
+ struct svc_export *exp;
|
||||
__be32 err, cerr;
|
||||
int host_err;
|
||||
|
||||
@@ -1569,6 +1570,7 @@ nfsd_symlink(struct svc_rqst *rqstp, str
|
||||
if (host_err)
|
||||
goto out_nfserr;
|
||||
|
||||
+ exp = fhp->fh_export;
|
||||
if (unlikely(path[plen] != 0)) {
|
||||
char *path_alloced = kmalloc(plen+1, GFP_KERNEL);
|
||||
if (path_alloced == NULL)
|
||||
@@ -1576,14 +1578,16 @@ nfsd_symlink(struct svc_rqst *rqstp, str
|
||||
else {
|
||||
strncpy(path_alloced, path, plen);
|
||||
path_alloced[plen] = 0;
|
||||
- host_err = vfs_symlink(dentry->d_inode, dnew, path_alloced);
|
||||
+ host_err = vfs_symlink(dentry->d_inode, dnew,
|
||||
+ exp->ex_path.mnt, path_alloced);
|
||||
kfree(path_alloced);
|
||||
}
|
||||
} else
|
||||
- host_err = vfs_symlink(dentry->d_inode, dnew, path);
|
||||
+ host_err = vfs_symlink(dentry->d_inode, dnew, exp->ex_path.mnt,
|
||||
+ path);
|
||||
|
||||
if (!host_err) {
|
||||
- if (EX_ISSYNC(fhp->fh_export))
|
||||
+ if (EX_ISSYNC(exp))
|
||||
host_err = nfsd_sync_dir(dentry);
|
||||
}
|
||||
err = nfserrno(host_err);
|
||||
@@ -1591,7 +1595,7 @@ nfsd_symlink(struct svc_rqst *rqstp, str
|
||||
|
||||
mnt_drop_write(fhp->fh_export->ex_path.mnt);
|
||||
|
||||
- cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp);
|
||||
+ cerr = fh_compose(resfhp, exp, dnew, fhp);
|
||||
dput(dnew);
|
||||
if (err==0) err = cerr;
|
||||
out:
|
||||
--- a/include/linux/fs.h
|
||||
+++ b/include/linux/fs.h
|
||||
@@ -1180,7 +1180,7 @@ extern int vfs_permission(struct nameida
|
||||
extern int vfs_create(struct inode *, struct dentry *, int, struct nameidata *);
|
||||
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 *, const char *);
|
||||
+extern int vfs_symlink(struct inode *, struct dentry *, struct vfsmount *, const char *);
|
||||
extern int vfs_link(struct dentry *, struct inode *, struct dentry *);
|
||||
extern int vfs_rmdir(struct inode *, struct dentry *);
|
||||
extern int vfs_unlink(struct inode *, struct dentry *);
|
||||
99
src/patches/suse-2.6.27.25/patches.apparmor/vfs-unlink.diff
Normal file
99
src/patches/suse-2.6.27.25/patches.apparmor/vfs-unlink.diff
Normal file
@@ -0,0 +1,99 @@
|
||||
From: Tony Jones <tonyj@suse.de>
|
||||
Subject: Add a struct vfsmount parameter to vfs_unlink()
|
||||
|
||||
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 | 3 ++-
|
||||
fs/namei.c | 4 ++--
|
||||
fs/nfsd/nfs4recover.c | 2 +-
|
||||
fs/nfsd/vfs.c | 2 +-
|
||||
include/linux/fs.h | 2 +-
|
||||
ipc/mqueue.c | 2 +-
|
||||
6 files changed, 8 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/fs/ecryptfs/inode.c
|
||||
+++ b/fs/ecryptfs/inode.c
|
||||
@@ -445,11 +445,12 @@ static int ecryptfs_unlink(struct inode
|
||||
{
|
||||
int rc = 0;
|
||||
struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
|
||||
+ struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
|
||||
struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir);
|
||||
struct dentry *lower_dir_dentry;
|
||||
|
||||
lower_dir_dentry = lock_parent(lower_dentry);
|
||||
- rc = vfs_unlink(lower_dir_inode, lower_dentry);
|
||||
+ rc = vfs_unlink(lower_dir_inode, lower_dentry, lower_mnt);
|
||||
if (rc) {
|
||||
printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc);
|
||||
goto out_unlock;
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -2248,7 +2248,7 @@ SYSCALL_DEFINE1(rmdir, const char __user
|
||||
return do_rmdir(AT_FDCWD, pathname);
|
||||
}
|
||||
|
||||
-int vfs_unlink(struct inode *dir, struct dentry *dentry)
|
||||
+int vfs_unlink(struct inode *dir, struct dentry *dentry, struct vfsmount *mnt)
|
||||
{
|
||||
int error = may_delete(dir, dentry, 0);
|
||||
|
||||
@@ -2313,7 +2313,7 @@ static long do_unlinkat(int dfd, const c
|
||||
error = mnt_want_write(nd.path.mnt);
|
||||
if (error)
|
||||
goto exit2;
|
||||
- error = vfs_unlink(nd.path.dentry->d_inode, dentry);
|
||||
+ error = vfs_unlink(nd.path.dentry->d_inode, dentry, nd.path.mnt);
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
exit2:
|
||||
dput(dentry);
|
||||
--- a/fs/nfsd/nfs4recover.c
|
||||
+++ b/fs/nfsd/nfs4recover.c
|
||||
@@ -264,7 +264,7 @@ nfsd4_remove_clid_file(struct dentry *di
|
||||
return -EINVAL;
|
||||
}
|
||||
mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
|
||||
- status = vfs_unlink(dir->d_inode, dentry);
|
||||
+ status = vfs_unlink(dir->d_inode, dentry, rec_dir.path.mnt);
|
||||
mutex_unlock(&dir->d_inode->i_mutex);
|
||||
return status;
|
||||
}
|
||||
--- a/fs/nfsd/vfs.c
|
||||
+++ b/fs/nfsd/vfs.c
|
||||
@@ -1832,7 +1832,7 @@ nfsd_unlink(struct svc_rqst *rqstp, stru
|
||||
host_err = -EPERM;
|
||||
} else
|
||||
#endif
|
||||
- host_err = vfs_unlink(dirp, rdentry);
|
||||
+ host_err = vfs_unlink(dirp, rdentry, exp->ex_path.mnt);
|
||||
} else { /* It's RMDIR */
|
||||
host_err = vfs_rmdir(dirp, rdentry, exp->ex_path.mnt);
|
||||
}
|
||||
--- a/include/linux/fs.h
|
||||
+++ b/include/linux/fs.h
|
||||
@@ -1183,7 +1183,7 @@ extern int vfs_mknod(struct inode *, str
|
||||
extern int vfs_symlink(struct inode *, struct dentry *, struct vfsmount *, const char *);
|
||||
extern int vfs_link(struct dentry *, struct vfsmount *, struct inode *, struct dentry *, struct vfsmount *);
|
||||
extern int vfs_rmdir(struct inode *, struct dentry *, struct vfsmount *);
|
||||
-extern int vfs_unlink(struct inode *, struct dentry *);
|
||||
+extern int vfs_unlink(struct inode *, struct dentry *, struct vfsmount *);
|
||||
extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
|
||||
|
||||
/*
|
||||
--- a/ipc/mqueue.c
|
||||
+++ b/ipc/mqueue.c
|
||||
@@ -746,7 +746,7 @@ SYSCALL_DEFINE1(mq_unlink, const char __
|
||||
err = mnt_want_write(mqueue_mnt);
|
||||
if (err)
|
||||
goto out_err;
|
||||
- err = vfs_unlink(dentry->d_parent->d_inode, dentry);
|
||||
+ err = vfs_unlink(dentry->d_parent->d_inode, dentry, mqueue_mnt);
|
||||
mnt_drop_write(mqueue_mnt);
|
||||
out_err:
|
||||
dput(dentry);
|
||||
@@ -0,0 +1,48 @@
|
||||
From: Bernhard Walle <bwalle@suse.de>
|
||||
Subject: [PATCH] Fix memory map for ia64/discontmem for kdump
|
||||
|
||||
makedumpfile[1] cannot run on ia64 discontigmem kernel, because the member
|
||||
node_mem_map of struct pgdat_list has invalid value. This patch fixes it.
|
||||
|
||||
node_start_pfn shows the start pfn of each node, and node_mem_map should
|
||||
point 'struct page' of each node's node_start_pfn.
|
||||
On my machine, node0's node_start_pfn shows 0x400 and its node_mem_map points
|
||||
0xa0007fffbf000000. This address is the same as vmem_map, so the node_mem_map
|
||||
points 'struct page' of pfn 0, even if its node_start_pfn shows 0x400.
|
||||
|
||||
The cause is due to the round down of min_pfn in count_node_pages() and
|
||||
node0's node_mem_map points 'struct page' of inactive pfn (0x0).
|
||||
This patch fixes it.
|
||||
|
||||
|
||||
makedumpfile[1]: dump filtering command
|
||||
https://sourceforge.net/projects/makedumpfile/
|
||||
|
||||
Signed-off-by: Ken'ichi Ohmichi <oomichi@mxs.nes.nec.co.jp>
|
||||
Acked-by: Bernhard Walle <bwalle@suse.de>
|
||||
|
||||
---
|
||||
arch/ia64/include/asm/meminit.h | 1 -
|
||||
arch/ia64/mm/discontig.c | 1 -
|
||||
2 files changed, 2 deletions(-)
|
||||
|
||||
--- a/arch/ia64/include/asm/meminit.h
|
||||
+++ b/arch/ia64/include/asm/meminit.h
|
||||
@@ -47,7 +47,6 @@ extern int reserve_elfcorehdr(unsigned l
|
||||
*/
|
||||
#define GRANULEROUNDDOWN(n) ((n) & ~(IA64_GRANULE_SIZE-1))
|
||||
#define GRANULEROUNDUP(n) (((n)+IA64_GRANULE_SIZE-1) & ~(IA64_GRANULE_SIZE-1))
|
||||
-#define ORDERROUNDDOWN(n) ((n) & ~((PAGE_SIZE<<MAX_ORDER)-1))
|
||||
|
||||
#ifdef CONFIG_NUMA
|
||||
extern void call_pernode_memory (unsigned long start, unsigned long len, void *func);
|
||||
--- a/arch/ia64/mm/discontig.c
|
||||
+++ b/arch/ia64/mm/discontig.c
|
||||
@@ -635,7 +635,6 @@ static __init int count_node_pages(unsig
|
||||
(min(end, __pa(MAX_DMA_ADDRESS)) - start) >>PAGE_SHIFT;
|
||||
#endif
|
||||
start = GRANULEROUNDDOWN(start);
|
||||
- start = ORDERROUNDDOWN(start);
|
||||
end = GRANULEROUNDUP(end);
|
||||
mem_data[node].max_pfn = max(mem_data[node].max_pfn,
|
||||
end >> PAGE_SHIFT);
|
||||
@@ -0,0 +1,143 @@
|
||||
From: Arnd Bergmann <arnd.bergmann@de.ibm.com>
|
||||
Subject: powerpc/cell/axon-msi: retry on missing interrupt
|
||||
References: bnc#445964,bnc#467633
|
||||
|
||||
The MSI capture logic on the axon bridge can sometimes
|
||||
lose interrupts in case of high DMA and interrupt load,
|
||||
when it signals an MSI interrupt to the MPIC interrupt
|
||||
controller while we are already handling another MSI.
|
||||
|
||||
Each MSI vector gets written into a FIFO buffer in main
|
||||
memory using DMA, and that DMA access is normally flushed
|
||||
by the actual interrupt packet on the IOIF. An MMIO
|
||||
register in the MSIC holds the position of the last
|
||||
entry in the FIFO buffer that was written. However,
|
||||
reading that position does not flush the DMA, so that
|
||||
we can observe stale data in the buffer.
|
||||
|
||||
In a stress test, we have observed the DMA to arrive
|
||||
up to 14 microseconds after reading the register.
|
||||
We can reliably detect this conditioning by writing
|
||||
an invalid MSI vector into the FIFO buffer after
|
||||
reading from it, assuming that all MSIs we get
|
||||
are valid. After detecting an invalid MSI vector,
|
||||
we udelay(1) in the interrupt cascade for up to
|
||||
100 times before giving up.
|
||||
|
||||
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
|
||||
Acked-by: John Jolly <jjolly@novell.com>
|
||||
|
||||
commit 23e0e8afafd9ac065d81506524adf3339584044b
|
||||
Author: Arnd Bergmann <arnd@arndb.de>
|
||||
Date: Fri Dec 12 09:19:50 2008 +0000
|
||||
|
||||
powerpc/cell/axon-msi: Fix MSI after kexec
|
||||
|
||||
Commit d015fe995 'powerpc/cell/axon-msi: Retry on missing interrupt'
|
||||
has turned a rare failure to kexec on QS22 into a reproducible
|
||||
error, which we have now analysed.
|
||||
|
||||
The problem is that after a kexec, the MSIC hardware still points
|
||||
into the middle of the old ring buffer. We set up the ring buffer
|
||||
during reboot, but not the offset into it. On older kernels, this
|
||||
would cause a storm of thousands of spurious interrupts after a
|
||||
kexec, which would most of the time get dropped silently.
|
||||
|
||||
With the new code, we time out on each interrupt, waiting for
|
||||
it to become valid. If more interrupts come in that we time
|
||||
out on, this goes on indefinitely, which eventually leads to
|
||||
a hard crash.
|
||||
|
||||
The solution in this commit is to read the current offset from
|
||||
the MSIC when reinitializing it. This now works correctly, as
|
||||
expected.
|
||||
|
||||
Reported-by: Dirk Herrendoerfer <d.herrendoerfer@de.ibm.com>
|
||||
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
|
||||
Acked-by: Michael Ellerman <michael@ellerman.id.au>
|
||||
Signed-off-by: Paul Mackerras <paulus@samba.org>
|
||||
|
||||
|
||||
---
|
||||
arch/powerpc/platforms/cell/axon_msi.c | 39 ++++++++++++++++++++++++++++-----
|
||||
1 file changed, 34 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/arch/powerpc/platforms/cell/axon_msi.c
|
||||
+++ b/arch/powerpc/platforms/cell/axon_msi.c
|
||||
@@ -95,6 +95,7 @@ static void axon_msi_cascade(unsigned in
|
||||
struct axon_msic *msic = get_irq_data(irq);
|
||||
u32 write_offset, msi;
|
||||
int idx;
|
||||
+ int retry = 0;
|
||||
|
||||
write_offset = dcr_read(msic->dcr_host, MSIC_WRITE_OFFSET_REG);
|
||||
pr_debug("axon_msi: original write_offset 0x%x\n", write_offset);
|
||||
@@ -102,7 +103,7 @@ static void axon_msi_cascade(unsigned in
|
||||
/* write_offset doesn't wrap properly, so we have to mask it */
|
||||
write_offset &= MSIC_FIFO_SIZE_MASK;
|
||||
|
||||
- while (msic->read_offset != write_offset) {
|
||||
+ while (msic->read_offset != write_offset && retry < 100) {
|
||||
idx = msic->read_offset / sizeof(__le32);
|
||||
msi = le32_to_cpu(msic->fifo_virt[idx]);
|
||||
msi &= 0xFFFF;
|
||||
@@ -110,13 +111,37 @@ static void axon_msi_cascade(unsigned in
|
||||
pr_debug("axon_msi: woff %x roff %x msi %x\n",
|
||||
write_offset, msic->read_offset, msi);
|
||||
|
||||
+ if (msi < NR_IRQS && irq_map[msi].host == msic->irq_host) {
|
||||
+ generic_handle_irq(msi);
|
||||
+ msic->fifo_virt[idx] = cpu_to_le32(0xffffffff);
|
||||
+ } else {
|
||||
+ /*
|
||||
+ * Reading the MSIC_WRITE_OFFSET_REG does not
|
||||
+ * reliably flush the outstanding DMA to the
|
||||
+ * FIFO buffer. Here we were reading stale
|
||||
+ * data, so we need to retry.
|
||||
+ */
|
||||
+ udelay(1);
|
||||
+ retry++;
|
||||
+ pr_debug("axon_msi: invalid irq 0x%x!\n", msi);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (retry) {
|
||||
+ pr_debug("axon_msi: late irq 0x%x, retry %d\n",
|
||||
+ msi, retry);
|
||||
+ retry = 0;
|
||||
+ }
|
||||
+
|
||||
msic->read_offset += MSIC_FIFO_ENTRY_SIZE;
|
||||
msic->read_offset &= MSIC_FIFO_SIZE_MASK;
|
||||
+ }
|
||||
|
||||
- if (msi < NR_IRQS && irq_map[msi].host == msic->irq_host)
|
||||
- generic_handle_irq(msi);
|
||||
- else
|
||||
- pr_debug("axon_msi: invalid irq 0x%x!\n", msi);
|
||||
+ if (retry) {
|
||||
+ printk(KERN_WARNING "axon_msi: irq timed out\n");
|
||||
+
|
||||
+ msic->read_offset += MSIC_FIFO_ENTRY_SIZE;
|
||||
+ msic->read_offset &= MSIC_FIFO_SIZE_MASK;
|
||||
}
|
||||
|
||||
desc->chip->eoi(irq);
|
||||
@@ -364,6 +389,7 @@ static int axon_msi_probe(struct of_devi
|
||||
dn->full_name);
|
||||
goto out_free_fifo;
|
||||
}
|
||||
+ memset(msic->fifo_virt, 0xff, MSIC_FIFO_SIZE_BYTES);
|
||||
|
||||
msic->irq_host = irq_alloc_host(dn, IRQ_HOST_MAP_NOMAP,
|
||||
NR_IRQS, &msic_host_ops, 0);
|
||||
@@ -387,6 +413,9 @@ static int axon_msi_probe(struct of_devi
|
||||
MSIC_CTRL_IRQ_ENABLE | MSIC_CTRL_ENABLE |
|
||||
MSIC_CTRL_FIFO_SIZE);
|
||||
|
||||
+ msic->read_offset = dcr_read(msic->dcr_host, MSIC_WRITE_OFFSET_REG)
|
||||
+ & MSIC_FIFO_SIZE_MASK;
|
||||
+
|
||||
device->dev.platform_data = msic;
|
||||
|
||||
ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs;
|
||||
@@ -0,0 +1,215 @@
|
||||
From: Chandru <chandru@in.ibm.com>
|
||||
Date: Sat, 30 Aug 2008 00:28:16 +1000
|
||||
Subject: [PATCH] powerpc: Add support for dynamic reconfiguration memory in kexec/kdump kernels
|
||||
References: bnc#431492
|
||||
X-Git-Commit: cf00085d8045cddd80a8aabad97de96fa8131793 Mon Sep 17 00:00:00 2001
|
||||
|
||||
Kdump kernel needs to use only those memory regions that it is allowed
|
||||
to use (crashkernel, rtas, tce, etc.). Each of these regions have
|
||||
their own sizes and are currently added under 'linux,usable-memory'
|
||||
property under each memory@xxx node of the device tree.
|
||||
|
||||
The ibm,dynamic-memory property of ibm,dynamic-reconfiguration-memory
|
||||
node (on POWER6) now stores in it the representation for most of the
|
||||
logical memory blocks with the size of each memory block being a
|
||||
constant (lmb_size). If one or more or part of the above mentioned
|
||||
regions lie under one of the lmb from ibm,dynamic-memory property,
|
||||
there is a need to identify those regions within the given lmb.
|
||||
|
||||
This makes the kernel recognize a new 'linux,drconf-usable-memory'
|
||||
property added by kexec-tools. Each entry in this property is of the
|
||||
form of a count followed by that many (base, size) pairs for the above
|
||||
mentioned regions. The number of cells in the count value is given by
|
||||
the #size-cells property of the root node.
|
||||
|
||||
Signed-off-by: Chandru Siddalingappa <chandru@in.ibm.com>
|
||||
Signed-off-by: Paul Mackerras <paulus@samba.org>
|
||||
Acked-by: Bernhard Walle <bwalle@suse.de>
|
||||
|
||||
---
|
||||
arch/powerpc/kernel/prom.c | 40 +++++++++++++++++++---
|
||||
arch/powerpc/mm/numa.c | 79 +++++++++++++++++++++++++++++++++++----------
|
||||
2 files changed, 96 insertions(+), 23 deletions(-)
|
||||
|
||||
--- a/arch/powerpc/kernel/prom.c
|
||||
+++ b/arch/powerpc/kernel/prom.c
|
||||
@@ -888,9 +888,10 @@ static u64 __init dt_mem_next_cell(int s
|
||||
*/
|
||||
static int __init early_init_dt_scan_drconf_memory(unsigned long node)
|
||||
{
|
||||
- cell_t *dm, *ls;
|
||||
+ cell_t *dm, *ls, *usm;
|
||||
unsigned long l, n, flags;
|
||||
u64 base, size, lmb_size;
|
||||
+ unsigned int is_kexec_kdump = 0, rngs;
|
||||
|
||||
ls = (cell_t *)of_get_flat_dt_prop(node, "ibm,lmb-size", &l);
|
||||
if (ls == NULL || l < dt_root_size_cells * sizeof(cell_t))
|
||||
@@ -905,6 +906,12 @@ static int __init early_init_dt_scan_drc
|
||||
if (l < (n * (dt_root_addr_cells + 4) + 1) * sizeof(cell_t))
|
||||
return 0;
|
||||
|
||||
+ /* check if this is a kexec/kdump kernel. */
|
||||
+ usm = (cell_t *)of_get_flat_dt_prop(node, "linux,drconf-usable-memory",
|
||||
+ &l);
|
||||
+ if (usm != NULL)
|
||||
+ is_kexec_kdump = 1;
|
||||
+
|
||||
for (; n != 0; --n) {
|
||||
base = dt_mem_next_cell(dt_root_addr_cells, &dm);
|
||||
flags = dm[3];
|
||||
@@ -915,13 +922,34 @@ static int __init early_init_dt_scan_drc
|
||||
if ((flags & 0x80) || !(flags & 0x8))
|
||||
continue;
|
||||
size = lmb_size;
|
||||
- if (iommu_is_off) {
|
||||
- if (base >= 0x80000000ul)
|
||||
+ rngs = 1;
|
||||
+ if (is_kexec_kdump) {
|
||||
+ /*
|
||||
+ * For each lmb in ibm,dynamic-memory, a corresponding
|
||||
+ * entry in linux,drconf-usable-memory property contains
|
||||
+ * a counter 'p' followed by 'p' (base, size) duple.
|
||||
+ * Now read the counter from
|
||||
+ * linux,drconf-usable-memory property
|
||||
+ */
|
||||
+ rngs = dt_mem_next_cell(dt_root_size_cells, &usm);
|
||||
+ if (!rngs) /* there are no (base, size) duple */
|
||||
continue;
|
||||
- if ((base + size) > 0x80000000ul)
|
||||
- size = 0x80000000ul - base;
|
||||
}
|
||||
- lmb_add(base, size);
|
||||
+ do {
|
||||
+ if (is_kexec_kdump) {
|
||||
+ base = dt_mem_next_cell(dt_root_addr_cells,
|
||||
+ &usm);
|
||||
+ size = dt_mem_next_cell(dt_root_size_cells,
|
||||
+ &usm);
|
||||
+ }
|
||||
+ if (iommu_is_off) {
|
||||
+ if (base >= 0x80000000ul)
|
||||
+ continue;
|
||||
+ if ((base + size) > 0x80000000ul)
|
||||
+ size = 0x80000000ul - base;
|
||||
+ }
|
||||
+ lmb_add(base, size);
|
||||
+ } while (--rngs);
|
||||
}
|
||||
lmb_dump_all();
|
||||
return 0;
|
||||
--- a/arch/powerpc/mm/numa.c
|
||||
+++ b/arch/powerpc/mm/numa.c
|
||||
@@ -192,6 +192,21 @@ static const int *of_get_associativity(s
|
||||
return of_get_property(dev, "ibm,associativity", NULL);
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Returns the property linux,drconf-usable-memory if
|
||||
+ * it exists (the property exists only in kexec/kdump kernels,
|
||||
+ * added by kexec-tools)
|
||||
+ */
|
||||
+static const u32 *of_get_usable_memory(struct device_node *memory)
|
||||
+{
|
||||
+ const u32 *prop;
|
||||
+ u32 len;
|
||||
+ prop = of_get_property(memory, "linux,drconf-usable-memory", &len);
|
||||
+ if (!prop || len < sizeof(unsigned int))
|
||||
+ return 0;
|
||||
+ return prop;
|
||||
+}
|
||||
+
|
||||
/* Returns nid in the range [0..MAX_NUMNODES-1], or -1 if no useful numa
|
||||
* info is found.
|
||||
*/
|
||||
@@ -529,14 +544,29 @@ static unsigned long __init numa_enforce
|
||||
}
|
||||
|
||||
/*
|
||||
+ * Reads the counter for a given entry in
|
||||
+ * linux,drconf-usable-memory property
|
||||
+ */
|
||||
+static inline int __init read_usm_ranges(const u32 **usm)
|
||||
+{
|
||||
+ /*
|
||||
+ * For each lmb in ibm,dynamic-memory a corresponding
|
||||
+ * entry in linux,drconf-usable-memory property contains
|
||||
+ * a counter followed by that many (base, size) duple.
|
||||
+ * read the counter from linux,drconf-usable-memory
|
||||
+ */
|
||||
+ return read_n_cells(n_mem_size_cells, usm);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
* Extract NUMA information from the ibm,dynamic-reconfiguration-memory
|
||||
* node. This assumes n_mem_{addr,size}_cells have been set.
|
||||
*/
|
||||
static void __init parse_drconf_memory(struct device_node *memory)
|
||||
{
|
||||
- const u32 *dm;
|
||||
- unsigned int n, rc;
|
||||
- unsigned long lmb_size, size;
|
||||
+ const u32 *dm, *usm;
|
||||
+ unsigned int n, rc, ranges, is_kexec_kdump = 0;
|
||||
+ unsigned long lmb_size, base, size, sz;
|
||||
int nid;
|
||||
struct assoc_arrays aa;
|
||||
|
||||
@@ -552,6 +582,11 @@ static void __init parse_drconf_memory(s
|
||||
if (rc)
|
||||
return;
|
||||
|
||||
+ /* check if this is a kexec/kdump kernel */
|
||||
+ usm = of_get_usable_memory(memory);
|
||||
+ if (usm != NULL)
|
||||
+ is_kexec_kdump = 1;
|
||||
+
|
||||
for (; n != 0; --n) {
|
||||
struct of_drconf_cell drmem;
|
||||
|
||||
@@ -563,21 +598,31 @@ static void __init parse_drconf_memory(s
|
||||
|| !(drmem.flags & DRCONF_MEM_ASSIGNED))
|
||||
continue;
|
||||
|
||||
- nid = of_drconf_to_nid_single(&drmem, &aa);
|
||||
-
|
||||
- fake_numa_create_new_node(
|
||||
- ((drmem.base_addr + lmb_size) >> PAGE_SHIFT),
|
||||
+ base = drmem.base_addr;
|
||||
+ size = lmb_size;
|
||||
+ ranges = 1;
|
||||
+
|
||||
+ if (is_kexec_kdump) {
|
||||
+ ranges = read_usm_ranges(&usm);
|
||||
+ if (!ranges) /* there are no (base, size) duple */
|
||||
+ continue;
|
||||
+ }
|
||||
+ do {
|
||||
+ if (is_kexec_kdump) {
|
||||
+ base = read_n_cells(n_mem_addr_cells, &usm);
|
||||
+ size = read_n_cells(n_mem_size_cells, &usm);
|
||||
+ }
|
||||
+ nid = of_drconf_to_nid_single(&drmem, &aa);
|
||||
+ fake_numa_create_new_node(
|
||||
+ ((base + size) >> PAGE_SHIFT),
|
||||
&nid);
|
||||
-
|
||||
- node_set_online(nid);
|
||||
-
|
||||
- size = numa_enforce_memory_limit(drmem.base_addr, lmb_size);
|
||||
- if (!size)
|
||||
- continue;
|
||||
-
|
||||
- add_active_range(nid, drmem.base_addr >> PAGE_SHIFT,
|
||||
- (drmem.base_addr >> PAGE_SHIFT)
|
||||
- + (size >> PAGE_SHIFT));
|
||||
+ node_set_online(nid);
|
||||
+ sz = numa_enforce_memory_limit(base, size);
|
||||
+ if (sz)
|
||||
+ add_active_range(nid, base >> PAGE_SHIFT,
|
||||
+ (base >> PAGE_SHIFT)
|
||||
+ + (sz >> PAGE_SHIFT));
|
||||
+ } while (--ranges);
|
||||
}
|
||||
}
|
||||
|
||||
41
src/patches/suse-2.6.27.25/patches.arch/ppc-vmcoreinfo.diff
Normal file
41
src/patches/suse-2.6.27.25/patches.arch/ppc-vmcoreinfo.diff
Normal file
@@ -0,0 +1,41 @@
|
||||
Date: Thu, 9 Oct 2008 11:20:27 -0400
|
||||
From: Neil Horman <nhorman@tuxdriver.com>
|
||||
To: linux-kernel@vger.kernel.org, kexec@lists.infradead.org,
|
||||
vgoyal@redhat.com, hbabu@us.ibm.com
|
||||
Subject: [PATCH] add additional symbols to /sys/kernel/vmcoreinfo data for
|
||||
ppc(64)
|
||||
Cc: nhorman@tuxdriver.com
|
||||
|
||||
Hey-
|
||||
The makdumpdile dump filtering program, in some modes of operation needs
|
||||
the node_data and/or contig_page_data symbols to function properly. These
|
||||
symbols are missing from the powerpc kernel. This patch adds those symbols in
|
||||
properly. Tested successfully by myself and the reporter.
|
||||
|
||||
Regards
|
||||
Neil
|
||||
|
||||
Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
|
||||
Acked-by: Bernhard Walle <bwalle@suse.de>
|
||||
|
||||
arch/powerpc/kernel/machine_kexec.c | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
|
||||
--- a/arch/powerpc/kernel/machine_kexec.c
|
||||
+++ b/arch/powerpc/kernel/machine_kexec.c
|
||||
@@ -44,6 +44,14 @@ void machine_kexec_cleanup(struct kimage
|
||||
ppc_md.machine_kexec_cleanup(image);
|
||||
}
|
||||
|
||||
+void arch_crash_save_vmcoreinfo(void)
|
||||
+{
|
||||
+#ifdef CONFIG_NEED_MULTIPLE_NODES
|
||||
+ VMCOREINFO_SYMBOL(node_data);
|
||||
+ VMCOREINFO_LENGTH(node_data, MAX_NUMNODES);
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Do not allocate memory (or fail in any way) in machine_kexec().
|
||||
* We are past the point of no return, committed to rebooting now.
|
||||
@@ -0,0 +1,28 @@
|
||||
From: Gerald Schaefer <geraldsc@de.ibm.com>
|
||||
Subject: cio: update sac values
|
||||
References: bnc#445100
|
||||
|
||||
Symptom: Drivers based on fcx fail to start I/O.
|
||||
Problem: Values for the sac field have changed.
|
||||
Solution: Update code accordingly.
|
||||
|
||||
Acked-by: John Jolly <jjolly@suse.de>
|
||||
---
|
||||
arch/s390/include/asm/fcx.h | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
Index: linux-sles11/arch/s390/include/asm/fcx.h
|
||||
===================================================================
|
||||
--- linux-sles11.orig/arch/s390/include/asm/fcx.h
|
||||
+++ linux-sles11/arch/s390/include/asm/fcx.h
|
||||
@@ -248,8 +248,8 @@ struct dcw {
|
||||
#define TCCB_MAX_SIZE (sizeof(struct tccb_tcah) + \
|
||||
TCCB_MAX_DCW * sizeof(struct dcw) + \
|
||||
sizeof(struct tccb_tcat))
|
||||
-#define TCCB_SAC_DEFAULT 0xf901
|
||||
-#define TCCB_SAC_INTRG 0xf902
|
||||
+#define TCCB_SAC_DEFAULT 0x1ffe
|
||||
+#define TCCB_SAC_INTRG 0x1fff
|
||||
|
||||
/**
|
||||
* struct tccb_tcah - Transport-Command-Area Header (TCAH)
|
||||
@@ -0,0 +1,73 @@
|
||||
From: Gerald Schaefer <geraldsc@de.ibm.com>
|
||||
Subject: zfcp: Remove message for failed port
|
||||
References: bnc#464466
|
||||
|
||||
Symptom: During opening of an adapter the message "Remote port ...
|
||||
could not be opened" is emitted for initiator ports,
|
||||
confusing users.
|
||||
Problem: The port scan tries to open all ports, including
|
||||
initiator ports to determine if they are target ports.
|
||||
Sometimes, a different error status is returned for the
|
||||
initiator ports, triggering the message mentioned above.
|
||||
Solution: Remove the message, target port failures will be checked
|
||||
later in the error recovery, printing a different message
|
||||
if necessary.
|
||||
|
||||
Acked-by: John Jolly <jjolly@suse.de>
|
||||
---
|
||||
Documentation/kmsg/s390/zfcp | 15 ---------------
|
||||
drivers/s390/scsi/zfcp_dbf.c | 2 +-
|
||||
drivers/s390/scsi/zfcp_fsf.c | 6 ------
|
||||
3 files changed, 1 insertion(+), 22 deletions(-)
|
||||
|
||||
--- a/Documentation/kmsg/s390/zfcp 2008-12-19 13:18:45.000000000 +0100
|
||||
+++ b/Documentation/kmsg/s390/zfcp 2008-12-19 13:18:59.000000000 +0100
|
||||
@@ -677,21 +677,6 @@
|
||||
*/
|
||||
|
||||
/*?
|
||||
- * Text: "%s: Remote port 0x%016Lx could not be opened\n"
|
||||
- * Severity: Warning
|
||||
- * Parameter:
|
||||
- * @1: bus ID of the zfcp device
|
||||
- * @2: WWPN
|
||||
- * Description:
|
||||
- * The FCP adapter rejected a request to open the specified port. No retry
|
||||
- * is possible.
|
||||
- * User action:
|
||||
- * Verify the setup and try removing and adding the port again. If this
|
||||
- * problem persists, gather Linux debug data, collect the FCP adapter
|
||||
- * hardware logs, and report the problem to your support organization.
|
||||
- */
|
||||
-
|
||||
-/*?
|
||||
* Text: "%s: LUN 0x%Lx on port 0x%Lx is already in use by CSS%d, MIF Image ID %x\n"
|
||||
* Severity: Warning
|
||||
* Parameter:
|
||||
--- a/drivers/s390/scsi/zfcp_dbf.c 2008-12-19 13:18:45.000000000 +0100
|
||||
+++ b/drivers/s390/scsi/zfcp_dbf.c 2008-12-19 13:18:59.000000000 +0100
|
||||
@@ -521,7 +521,7 @@ static const char *zfcp_rec_dbf_ids[] =
|
||||
[29] = "link down",
|
||||
[30] = "link up status read",
|
||||
[31] = "open port failed",
|
||||
- [32] = "open port failed",
|
||||
+ [32] = "",
|
||||
[33] = "close port",
|
||||
[34] = "open unit failed",
|
||||
[35] = "exclusive open unit failed",
|
||||
--- a/drivers/s390/scsi/zfcp_fsf.c 2008-12-19 13:18:45.000000000 +0100
|
||||
+++ b/drivers/s390/scsi/zfcp_fsf.c 2008-12-19 13:18:59.000000000 +0100
|
||||
@@ -1405,13 +1405,7 @@ static void zfcp_fsf_open_port_handler(s
|
||||
switch (header->fsf_status_qual.word[0]) {
|
||||
case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE:
|
||||
case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED:
|
||||
- req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
- break;
|
||||
case FSF_SQ_NO_RETRY_POSSIBLE:
|
||||
- dev_warn(&req->adapter->ccw_device->dev,
|
||||
- "Remote port 0x%016Lx could not be opened\n",
|
||||
- (unsigned long long)port->wwpn);
|
||||
- zfcp_erp_port_failed(port, 32, req);
|
||||
req->status |= ZFCP_STATUS_FSFREQ_ERROR;
|
||||
break;
|
||||
}
|
||||
@@ -0,0 +1,378 @@
|
||||
From: Gerald Schaefer <geraldsc@de.ibm.com>
|
||||
Subject: zfcp: Add support for unchained FSF requests
|
||||
References: bnc#464466
|
||||
|
||||
Symptom: On a z900 zfcp loops in error recovery.
|
||||
Problem: The z900 requires support for unchained FSF requests for
|
||||
CT and ELS requests. The chained format triggers the ERP
|
||||
from the qdio error handler.
|
||||
Solution: Check the hardware feature flag and send unchained CT
|
||||
and ELS requests if chaining is not support. Adapt the
|
||||
size of the GPN_FT request as necessary and add debug data
|
||||
and a warning, in case the CT request hits a limit.
|
||||
|
||||
Acked-by: John Jolly <jjolly@suse.de>
|
||||
---
|
||||
Documentation/kmsg/s390/zfcp | 16 ++++++++++++
|
||||
drivers/s390/scsi/zfcp_dbf.c | 2 +
|
||||
drivers/s390/scsi/zfcp_dbf.h | 1
|
||||
drivers/s390/scsi/zfcp_def.h | 9 -------
|
||||
drivers/s390/scsi/zfcp_fc.c | 55 ++++++++++++++++++++++++-------------------
|
||||
drivers/s390/scsi/zfcp_fsf.c | 32 +++++++++++++++++++------
|
||||
drivers/s390/scsi/zfcp_fsf.h | 2 +
|
||||
7 files changed, 77 insertions(+), 40 deletions(-)
|
||||
|
||||
--- a/drivers/s390/scsi/zfcp_fc.c 2008-12-19 13:36:23.000000000 +0100
|
||||
+++ b/drivers/s390/scsi/zfcp_fc.c 2008-12-19 13:36:27.000000000 +0100
|
||||
@@ -25,9 +25,12 @@ struct gpn_ft_resp_acc {
|
||||
u64 wwpn;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
-#define ZFCP_GPN_FT_ENTRIES ((PAGE_SIZE - sizeof(struct ct_hdr)) \
|
||||
- / sizeof(struct gpn_ft_resp_acc))
|
||||
+#define ZFCP_CT_SIZE_ONE_PAGE (PAGE_SIZE - sizeof(struct ct_hdr))
|
||||
+#define ZFCP_GPN_FT_ENTRIES (ZFCP_CT_SIZE_ONE_PAGE \
|
||||
+ / sizeof(struct gpn_ft_resp_acc))
|
||||
#define ZFCP_GPN_FT_BUFFERS 4
|
||||
+#define ZFCP_GPN_FT_MAX_SIZE (ZFCP_GPN_FT_BUFFERS * PAGE_SIZE \
|
||||
+ - sizeof(struct ct_hdr))
|
||||
#define ZFCP_GPN_FT_MAX_ENTRIES ZFCP_GPN_FT_BUFFERS * (ZFCP_GPN_FT_ENTRIES + 1)
|
||||
|
||||
struct ct_iu_gpn_ft_resp {
|
||||
@@ -283,8 +286,6 @@ int static zfcp_fc_ns_gid_pn_request(str
|
||||
gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT;
|
||||
gid_pn->ct.req = &gid_pn->req;
|
||||
gid_pn->ct.resp = &gid_pn->resp;
|
||||
- gid_pn->ct.req_count = 1;
|
||||
- gid_pn->ct.resp_count = 1;
|
||||
sg_init_one(&gid_pn->req, &gid_pn->ct_iu_req,
|
||||
sizeof(struct ct_iu_gid_pn_req));
|
||||
sg_init_one(&gid_pn->resp, &gid_pn->ct_iu_resp,
|
||||
@@ -296,7 +297,7 @@ int static zfcp_fc_ns_gid_pn_request(str
|
||||
gid_pn->ct_iu_req.header.gs_subtype = ZFCP_CT_NAME_SERVER;
|
||||
gid_pn->ct_iu_req.header.options = ZFCP_CT_SYNCHRONOUS;
|
||||
gid_pn->ct_iu_req.header.cmd_rsp_code = ZFCP_CT_GID_PN;
|
||||
- gid_pn->ct_iu_req.header.max_res_size = ZFCP_CT_MAX_SIZE;
|
||||
+ gid_pn->ct_iu_req.header.max_res_size = ZFCP_CT_SIZE_ONE_PAGE / 4;
|
||||
gid_pn->ct_iu_req.wwpn = erp_action->port->wwpn;
|
||||
|
||||
init_completion(&compl_rec.done);
|
||||
@@ -406,8 +407,6 @@ static int zfcp_fc_adisc(struct zfcp_por
|
||||
sg_init_one(adisc->els.resp, &adisc->ls_adisc_acc,
|
||||
sizeof(struct zfcp_ls_adisc));
|
||||
|
||||
- adisc->els.req_count = 1;
|
||||
- adisc->els.resp_count = 1;
|
||||
adisc->els.adapter = adapter;
|
||||
adisc->els.port = port;
|
||||
adisc->els.d_id = port->d_id;
|
||||
@@ -447,17 +446,17 @@ void zfcp_test_link(struct zfcp_port *po
|
||||
zfcp_erp_port_forced_reopen(port, 0, 65, NULL);
|
||||
}
|
||||
|
||||
-static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft)
|
||||
+static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft, int buf_num)
|
||||
{
|
||||
struct scatterlist *sg = &gpn_ft->sg_req;
|
||||
|
||||
kfree(sg_virt(sg)); /* free request buffer */
|
||||
- zfcp_sg_free_table(gpn_ft->sg_resp, ZFCP_GPN_FT_BUFFERS);
|
||||
+ zfcp_sg_free_table(gpn_ft->sg_resp, buf_num);
|
||||
|
||||
kfree(gpn_ft);
|
||||
}
|
||||
|
||||
-static struct zfcp_gpn_ft *zfcp_alloc_sg_env(void)
|
||||
+static struct zfcp_gpn_ft *zfcp_alloc_sg_env(int buf_num)
|
||||
{
|
||||
struct zfcp_gpn_ft *gpn_ft;
|
||||
struct ct_iu_gpn_ft_req *req;
|
||||
@@ -474,8 +473,8 @@ static struct zfcp_gpn_ft *zfcp_alloc_sg
|
||||
}
|
||||
sg_init_one(&gpn_ft->sg_req, req, sizeof(*req));
|
||||
|
||||
- if (zfcp_sg_setup_table(gpn_ft->sg_resp, ZFCP_GPN_FT_BUFFERS)) {
|
||||
- zfcp_free_sg_env(gpn_ft);
|
||||
+ if (zfcp_sg_setup_table(gpn_ft->sg_resp, buf_num)) {
|
||||
+ zfcp_free_sg_env(gpn_ft, buf_num);
|
||||
gpn_ft = NULL;
|
||||
}
|
||||
out:
|
||||
@@ -484,7 +483,8 @@ out:
|
||||
|
||||
|
||||
static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft,
|
||||
- struct zfcp_adapter *adapter)
|
||||
+ struct zfcp_adapter *adapter,
|
||||
+ int max_bytes)
|
||||
{
|
||||
struct zfcp_send_ct *ct = &gpn_ft->ct;
|
||||
struct ct_iu_gpn_ft_req *req = sg_virt(&gpn_ft->sg_req);
|
||||
@@ -497,8 +497,7 @@ static int zfcp_scan_issue_gpn_ft(struct
|
||||
req->header.gs_subtype = ZFCP_CT_NAME_SERVER;
|
||||
req->header.options = ZFCP_CT_SYNCHRONOUS;
|
||||
req->header.cmd_rsp_code = ZFCP_CT_GPN_FT;
|
||||
- req->header.max_res_size = (sizeof(struct gpn_ft_resp_acc) *
|
||||
- (ZFCP_GPN_FT_MAX_ENTRIES - 1)) >> 2;
|
||||
+ req->header.max_res_size = max_bytes / 4;
|
||||
req->flags = 0;
|
||||
req->domain_id_scope = 0;
|
||||
req->area_id_scope = 0;
|
||||
@@ -511,8 +510,6 @@ static int zfcp_scan_issue_gpn_ft(struct
|
||||
ct->timeout = 10;
|
||||
ct->req = &gpn_ft->sg_req;
|
||||
ct->resp = gpn_ft->sg_resp;
|
||||
- ct->req_count = 1;
|
||||
- ct->resp_count = ZFCP_GPN_FT_BUFFERS;
|
||||
|
||||
init_completion(&compl_rec.done);
|
||||
compl_rec.handler = NULL;
|
||||
@@ -539,7 +536,7 @@ static void zfcp_validate_port(struct zf
|
||||
zfcp_port_dequeue(port);
|
||||
}
|
||||
|
||||
-static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft)
|
||||
+static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries)
|
||||
{
|
||||
struct zfcp_send_ct *ct = &gpn_ft->ct;
|
||||
struct scatterlist *sg = gpn_ft->sg_resp;
|
||||
@@ -559,13 +556,17 @@ static int zfcp_scan_eval_gpn_ft(struct
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
- if (hdr->max_res_size)
|
||||
+ if (hdr->max_res_size) {
|
||||
+ dev_warn(&adapter->ccw_device->dev,
|
||||
+ "The name server reported %d words residual data\n",
|
||||
+ hdr->max_res_size);
|
||||
return -E2BIG;
|
||||
+ }
|
||||
|
||||
down(&zfcp_data.config_sema);
|
||||
|
||||
/* first entry is the header */
|
||||
- for (x = 1; x < ZFCP_GPN_FT_MAX_ENTRIES && !last; x++) {
|
||||
+ for (x = 1; x < max_entries && !last; x++) {
|
||||
if (x % (ZFCP_GPN_FT_ENTRIES + 1))
|
||||
acc++;
|
||||
else
|
||||
@@ -611,6 +612,12 @@ int zfcp_scan_ports(struct zfcp_adapter
|
||||
{
|
||||
int ret, i;
|
||||
struct zfcp_gpn_ft *gpn_ft;
|
||||
+ int chain, max_entries, buf_num, max_bytes;
|
||||
+
|
||||
+ chain = adapter->adapter_features & FSF_FEATURE_ELS_CT_CHAINED_SBALS;
|
||||
+ buf_num = chain ? ZFCP_GPN_FT_BUFFERS : 1;
|
||||
+ max_entries = chain ? ZFCP_GPN_FT_MAX_ENTRIES : ZFCP_GPN_FT_ENTRIES;
|
||||
+ max_bytes = chain ? ZFCP_GPN_FT_MAX_SIZE : ZFCP_CT_SIZE_ONE_PAGE;
|
||||
|
||||
zfcp_erp_wait(adapter); /* wait until adapter is finished with ERP */
|
||||
if (fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPORT)
|
||||
@@ -620,23 +627,23 @@ int zfcp_scan_ports(struct zfcp_adapter
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- gpn_ft = zfcp_alloc_sg_env();
|
||||
+ gpn_ft = zfcp_alloc_sg_env(buf_num);
|
||||
if (!gpn_ft) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
- ret = zfcp_scan_issue_gpn_ft(gpn_ft, adapter);
|
||||
+ ret = zfcp_scan_issue_gpn_ft(gpn_ft, adapter, max_bytes);
|
||||
if (!ret) {
|
||||
- ret = zfcp_scan_eval_gpn_ft(gpn_ft);
|
||||
+ ret = zfcp_scan_eval_gpn_ft(gpn_ft, max_entries);
|
||||
if (ret == -EAGAIN)
|
||||
ssleep(1);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
- zfcp_free_sg_env(gpn_ft);
|
||||
+ zfcp_free_sg_env(gpn_ft, buf_num);
|
||||
out:
|
||||
zfcp_wka_port_put(&adapter->nsp);
|
||||
return ret;
|
||||
--- a/drivers/s390/scsi/zfcp_fsf.h 2008-12-19 13:36:23.000000000 +0100
|
||||
+++ b/drivers/s390/scsi/zfcp_fsf.h 2008-12-19 13:36:27.000000000 +0100
|
||||
@@ -164,6 +164,7 @@
|
||||
#define FSF_FEATURE_LUN_SHARING 0x00000004
|
||||
#define FSF_FEATURE_NOTIFICATION_LOST 0x00000008
|
||||
#define FSF_FEATURE_HBAAPI_MANAGEMENT 0x00000010
|
||||
+#define FSF_FEATURE_ELS_CT_CHAINED_SBALS 0x00000020
|
||||
#define FSF_FEATURE_UPDATE_ALERT 0x00000100
|
||||
#define FSF_FEATURE_MEASUREMENT_DATA 0x00000200
|
||||
|
||||
@@ -322,6 +323,7 @@ struct fsf_nport_serv_param {
|
||||
u8 vendor_version_level[16];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
+#define FSF_PLOGI_MIN_LEN 112
|
||||
struct fsf_plogi {
|
||||
u32 code;
|
||||
struct fsf_nport_serv_param serv_param;
|
||||
--- a/drivers/s390/scsi/zfcp_fsf.c 2008-12-19 13:36:23.000000000 +0100
|
||||
+++ b/drivers/s390/scsi/zfcp_fsf.c 2008-12-19 13:36:27.000000000 +0100
|
||||
@@ -1012,12 +1012,29 @@ skip_fsfstatus:
|
||||
send_ct->handler(send_ct->handler_data);
|
||||
}
|
||||
|
||||
-static int zfcp_fsf_setup_sbals(struct zfcp_fsf_req *req,
|
||||
- struct scatterlist *sg_req,
|
||||
- struct scatterlist *sg_resp, int max_sbals)
|
||||
+static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
|
||||
+ struct scatterlist *sg_req,
|
||||
+ struct scatterlist *sg_resp,
|
||||
+ int max_sbals)
|
||||
{
|
||||
+ struct qdio_buffer_element *sbale = zfcp_qdio_sbale_req(req);
|
||||
+ u32 feat = req->adapter->adapter_features;
|
||||
int bytes;
|
||||
|
||||
+ if (!(feat & FSF_FEATURE_ELS_CT_CHAINED_SBALS)) {
|
||||
+ if (sg_req->length > PAGE_SIZE || sg_resp->length > PAGE_SIZE ||
|
||||
+ !sg_is_last(sg_req) || !sg_is_last(sg_resp))
|
||||
+ return -EOPNOTSUPP;
|
||||
+
|
||||
+ sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ;
|
||||
+ sbale[2].addr = sg_virt(sg_req);
|
||||
+ sbale[2].length = sg_req->length;
|
||||
+ sbale[3].addr = sg_virt(sg_resp);
|
||||
+ sbale[3].length = sg_resp->length;
|
||||
+ sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ,
|
||||
sg_req, max_sbals);
|
||||
if (bytes <= 0)
|
||||
@@ -1059,8 +1076,8 @@ int zfcp_fsf_send_ct(struct zfcp_send_ct
|
||||
goto out;
|
||||
}
|
||||
|
||||
- ret = zfcp_fsf_setup_sbals(req, ct->req, ct->resp,
|
||||
- FSF_MAX_SBALS_PER_REQ);
|
||||
+ ret = zfcp_fsf_setup_ct_els_sbals(req, ct->req, ct->resp,
|
||||
+ FSF_MAX_SBALS_PER_REQ);
|
||||
if (ret)
|
||||
goto failed_send;
|
||||
|
||||
@@ -1170,7 +1187,7 @@ int zfcp_fsf_send_els(struct zfcp_send_e
|
||||
goto out;
|
||||
}
|
||||
|
||||
- ret = zfcp_fsf_setup_sbals(req, els->req, els->resp, 2);
|
||||
+ ret = zfcp_fsf_setup_ct_els_sbals(req, els->req, els->resp, 2);
|
||||
|
||||
if (ret)
|
||||
goto failed_send;
|
||||
@@ -1433,7 +1450,8 @@ static void zfcp_fsf_open_port_handler(s
|
||||
* Alternately, an ADISC/PDISC ELS should suffice, as well.
|
||||
*/
|
||||
plogi = (struct fsf_plogi *) req->qtcb->bottom.support.els;
|
||||
- if (req->qtcb->bottom.support.els1_length >= sizeof(*plogi)) {
|
||||
+ if (req->qtcb->bottom.support.els1_length >=
|
||||
+ FSF_PLOGI_MIN_LEN) {
|
||||
if (plogi->serv_param.wwpn != port->wwpn)
|
||||
atomic_clear_mask(ZFCP_STATUS_PORT_DID_DID,
|
||||
&port->status);
|
||||
--- a/Documentation/kmsg/s390/zfcp 2008-12-19 13:36:23.000000000 +0100
|
||||
+++ b/Documentation/kmsg/s390/zfcp 2008-12-19 13:36:27.000000000 +0100
|
||||
@@ -813,3 +813,19 @@
|
||||
* problem persists, gather Linux debug data, collect the FCP adapter
|
||||
* hardware logs, and report the problem to your support organization.
|
||||
*/
|
||||
+
|
||||
+/*?
|
||||
+ * Text: "%s: The name server reported %d words residual data\n"
|
||||
+ * Severity: Warning
|
||||
+ * Parameter:
|
||||
+ * @1: bus ID of the zfcp device
|
||||
+ * @2: number of words in residual data
|
||||
+ * Description:
|
||||
+ * The fibre channel name server sent too much information about remote ports.
|
||||
+ * The zfcp device driver did not receive sufficient information to attach all
|
||||
+ * available remote ports in the SAN.
|
||||
+ * User action:
|
||||
+ * Verify that you are running the latest firmware level on the FCP
|
||||
+ * adapter. Check your SAN setup and consider reducing the number of ports
|
||||
+ * visible to the FCP adapter by using more restrictive zoning in the SAN.
|
||||
+ */
|
||||
--- a/drivers/s390/scsi/zfcp_dbf.c 2008-12-19 13:36:23.000000000 +0100
|
||||
+++ b/drivers/s390/scsi/zfcp_dbf.c 2008-12-19 13:36:27.000000000 +0100
|
||||
@@ -935,6 +935,7 @@ void zfcp_san_dbf_event_ct_response(stru
|
||||
rct->reason_code = hdr->reason_code;
|
||||
rct->expl = hdr->reason_code_expl;
|
||||
rct->vendor_unique = hdr->vendor_unique;
|
||||
+ rct->max_res_size = hdr->max_res_size;
|
||||
rct->len = min((int)ct->resp->length - (int)sizeof(struct ct_hdr),
|
||||
ZFCP_DBF_SAN_MAX_PAYLOAD);
|
||||
debug_event(adapter->san_dbf, level, r, sizeof(*r));
|
||||
@@ -1042,6 +1043,7 @@ static int zfcp_san_dbf_view_format(debu
|
||||
zfcp_dbf_out(&p, "reason_code", "0x%02x", ct->reason_code);
|
||||
zfcp_dbf_out(&p, "reason_code_expl", "0x%02x", ct->expl);
|
||||
zfcp_dbf_out(&p, "vendor_unique", "0x%02x", ct->vendor_unique);
|
||||
+ zfcp_dbf_out(&p, "max_res_size", "0x%04x", ct->max_res_size);
|
||||
} else if (strncmp(r->tag, "oels", ZFCP_DBF_TAG_SIZE) == 0 ||
|
||||
strncmp(r->tag, "rels", ZFCP_DBF_TAG_SIZE) == 0 ||
|
||||
strncmp(r->tag, "iels", ZFCP_DBF_TAG_SIZE) == 0) {
|
||||
--- a/drivers/s390/scsi/zfcp_dbf.h 2008-12-19 13:36:23.000000000 +0100
|
||||
+++ b/drivers/s390/scsi/zfcp_dbf.h 2008-12-19 13:36:27.000000000 +0100
|
||||
@@ -171,6 +171,7 @@ struct zfcp_san_dbf_record_ct_response {
|
||||
u8 reason_code;
|
||||
u8 expl;
|
||||
u8 vendor_unique;
|
||||
+ u16 max_res_size;
|
||||
u32 len;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
--- a/drivers/s390/scsi/zfcp_def.h 2008-12-19 13:36:23.000000000 +0100
|
||||
+++ b/drivers/s390/scsi/zfcp_def.h 2008-12-19 13:36:27.000000000 +0100
|
||||
@@ -210,7 +210,6 @@ struct zfcp_ls_adisc {
|
||||
#define ZFCP_CT_UNABLE_TO_PERFORM_CMD 0x09
|
||||
#define ZFCP_CT_GID_PN 0x0121
|
||||
#define ZFCP_CT_GPN_FT 0x0172
|
||||
-#define ZFCP_CT_MAX_SIZE 0x1020
|
||||
#define ZFCP_CT_ACCEPT 0x8002
|
||||
#define ZFCP_CT_REJECT 0x8001
|
||||
|
||||
@@ -339,8 +338,6 @@ struct ct_iu_gid_pn_resp {
|
||||
* @wka_port: port where the request is sent to
|
||||
* @req: scatter-gather list for request
|
||||
* @resp: scatter-gather list for response
|
||||
- * @req_count: number of elements in request scatter-gather list
|
||||
- * @resp_count: number of elements in response scatter-gather list
|
||||
* @handler: handler function (called for response to the request)
|
||||
* @handler_data: data passed to handler function
|
||||
* @timeout: FSF timeout for this request
|
||||
@@ -351,8 +348,6 @@ struct zfcp_send_ct {
|
||||
struct zfcp_wka_port *wka_port;
|
||||
struct scatterlist *req;
|
||||
struct scatterlist *resp;
|
||||
- unsigned int req_count;
|
||||
- unsigned int resp_count;
|
||||
void (*handler)(unsigned long);
|
||||
unsigned long handler_data;
|
||||
int timeout;
|
||||
@@ -377,8 +372,6 @@ struct zfcp_gid_pn_data {
|
||||
* @d_id: destiniation id of port where request is sent to
|
||||
* @req: scatter-gather list for request
|
||||
* @resp: scatter-gather list for response
|
||||
- * @req_count: number of elements in request scatter-gather list
|
||||
- * @resp_count: number of elements in response scatter-gather list
|
||||
* @handler: handler function (called for response to the request)
|
||||
* @handler_data: data passed to handler function
|
||||
* @completion: completion for synchronization purposes
|
||||
@@ -391,8 +384,6 @@ struct zfcp_send_els {
|
||||
u32 d_id;
|
||||
struct scatterlist *req;
|
||||
struct scatterlist *resp;
|
||||
- unsigned int req_count;
|
||||
- unsigned int resp_count;
|
||||
void (*handler)(unsigned long);
|
||||
unsigned long handler_data;
|
||||
struct completion *completion;
|
||||
@@ -0,0 +1,207 @@
|
||||
From: Gerald Schaefer <geraldsc@de.ibm.com>
|
||||
Subject: kernel: fix cpu topology support
|
||||
References: bnc#464466
|
||||
|
||||
Symptom: CPU topology changes aren't recognized by the scheduler.
|
||||
Problem: The common code scheduler used to have a hook which could be
|
||||
called from architecture code to trigger a rebuild of all
|
||||
scheduling domains when cpu topology changed. This hook got
|
||||
removed errorneously. So cpu topology change notifications
|
||||
got lost.
|
||||
Solution: Readd the hook. This patch also removes some unused code
|
||||
from the s390 specific cpu topology code.
|
||||
|
||||
Acked-by: John Jolly <jjolly@suse.de>
|
||||
---
|
||||
arch/s390/kernel/topology.c | 35 ++++++++++-------------------------
|
||||
include/linux/topology.h | 2 +-
|
||||
kernel/sched.c | 16 +++++++++++++---
|
||||
3 files changed, 24 insertions(+), 29 deletions(-)
|
||||
|
||||
--- a/arch/s390/kernel/topology.c
|
||||
+++ b/arch/s390/kernel/topology.c
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/smp.h>
|
||||
+#include <linux/cpuset.h>
|
||||
#include <asm/delay.h>
|
||||
#include <asm/s390_ext.h>
|
||||
#include <asm/sysinfo.h>
|
||||
@@ -64,7 +65,6 @@ static void topology_work_fn(struct work
|
||||
static struct tl_info *tl_info;
|
||||
static struct core_info core_info;
|
||||
static int machine_has_topology;
|
||||
-static int machine_has_topology_irq;
|
||||
static struct timer_list topology_timer;
|
||||
static void set_topology_timer(void);
|
||||
static DECLARE_WORK(topology_work, topology_work_fn);
|
||||
@@ -81,7 +81,7 @@ cpumask_t cpu_coregroup_map(unsigned int
|
||||
|
||||
cpus_clear(mask);
|
||||
if (!topology_enabled || !machine_has_topology)
|
||||
- return cpu_present_map;
|
||||
+ return cpu_possible_map;
|
||||
spin_lock_irqsave(&topology_lock, flags);
|
||||
while (core) {
|
||||
if (cpu_isset(cpu, core->mask)) {
|
||||
@@ -171,7 +171,7 @@ static void topology_update_polarization
|
||||
int cpu;
|
||||
|
||||
mutex_lock(&smp_cpu_state_mutex);
|
||||
- for_each_present_cpu(cpu)
|
||||
+ for_each_possible_cpu(cpu)
|
||||
smp_cpu_polarization[cpu] = POLARIZATION_HRZ;
|
||||
mutex_unlock(&smp_cpu_state_mutex);
|
||||
}
|
||||
@@ -202,7 +202,7 @@ int topology_set_cpu_management(int fc)
|
||||
rc = ptf(PTF_HORIZONTAL);
|
||||
if (rc)
|
||||
return -EBUSY;
|
||||
- for_each_present_cpu(cpu)
|
||||
+ for_each_possible_cpu(cpu)
|
||||
smp_cpu_polarization[cpu] = POLARIZATION_UNKNWN;
|
||||
return rc;
|
||||
}
|
||||
@@ -211,11 +211,11 @@ static void update_cpu_core_map(void)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
- for_each_present_cpu(cpu)
|
||||
+ for_each_possible_cpu(cpu)
|
||||
cpu_core_map[cpu] = cpu_coregroup_map(cpu);
|
||||
}
|
||||
|
||||
-void arch_update_cpu_topology(void)
|
||||
+int arch_update_cpu_topology(void)
|
||||
{
|
||||
struct tl_info *info = tl_info;
|
||||
struct sys_device *sysdev;
|
||||
@@ -224,7 +224,7 @@ void arch_update_cpu_topology(void)
|
||||
if (!machine_has_topology) {
|
||||
update_cpu_core_map();
|
||||
topology_update_polarization_simple();
|
||||
- return;
|
||||
+ return 0;
|
||||
}
|
||||
stsi(info, 15, 1, 2);
|
||||
tl_to_cores(info);
|
||||
@@ -233,11 +233,12 @@ void arch_update_cpu_topology(void)
|
||||
sysdev = get_cpu_sysdev(cpu);
|
||||
kobject_uevent(&sysdev->kobj, KOBJ_CHANGE);
|
||||
}
|
||||
+ return 1;
|
||||
}
|
||||
|
||||
static void topology_work_fn(struct work_struct *work)
|
||||
{
|
||||
- arch_reinit_sched_domains();
|
||||
+ rebuild_sched_domains();
|
||||
}
|
||||
|
||||
void topology_schedule_update(void)
|
||||
@@ -260,11 +261,6 @@ static void set_topology_timer(void)
|
||||
add_timer(&topology_timer);
|
||||
}
|
||||
|
||||
-static void topology_interrupt(__u16 code)
|
||||
-{
|
||||
- schedule_work(&topology_work);
|
||||
-}
|
||||
-
|
||||
static int __init early_parse_topology(char *p)
|
||||
{
|
||||
if (strncmp(p, "on", 2))
|
||||
@@ -284,14 +280,7 @@ static int __init init_topology_update(v
|
||||
goto out;
|
||||
}
|
||||
init_timer_deferrable(&topology_timer);
|
||||
- if (machine_has_topology_irq) {
|
||||
- rc = register_external_interrupt(0x2005, topology_interrupt);
|
||||
- if (rc)
|
||||
- goto out;
|
||||
- ctl_set_bit(0, 8);
|
||||
- }
|
||||
- else
|
||||
- set_topology_timer();
|
||||
+ set_topology_timer();
|
||||
out:
|
||||
update_cpu_core_map();
|
||||
return rc;
|
||||
@@ -312,9 +301,6 @@ void __init s390_init_cpu_topology(void)
|
||||
return;
|
||||
machine_has_topology = 1;
|
||||
|
||||
- if (facility_bits & (1ULL << 51))
|
||||
- machine_has_topology_irq = 1;
|
||||
-
|
||||
tl_info = alloc_bootmem_pages(PAGE_SIZE);
|
||||
info = tl_info;
|
||||
stsi(info, 15, 1, 2);
|
||||
@@ -338,5 +324,4 @@ void __init s390_init_cpu_topology(void)
|
||||
return;
|
||||
error:
|
||||
machine_has_topology = 0;
|
||||
- machine_has_topology_irq = 0;
|
||||
}
|
||||
--- a/include/linux/topology.h
|
||||
+++ b/include/linux/topology.h
|
||||
@@ -49,7 +49,7 @@
|
||||
for_each_online_node(node) \
|
||||
if (nr_cpus_node(node))
|
||||
|
||||
-void arch_update_cpu_topology(void);
|
||||
+int arch_update_cpu_topology(void);
|
||||
|
||||
/* Conform to ACPI 2.0 SLIT distance definitions */
|
||||
#define LOCAL_DISTANCE 10
|
||||
--- a/kernel/sched.c
|
||||
+++ b/kernel/sched.c
|
||||
@@ -7640,8 +7640,14 @@ static struct sched_domain_attr *dattr_c
|
||||
*/
|
||||
static cpumask_t fallback_doms;
|
||||
|
||||
-void __attribute__((weak)) arch_update_cpu_topology(void)
|
||||
+/*
|
||||
+ * arch_update_cpu_topology lets virtualized architectures update the
|
||||
+ * cpu core maps. It is supposed to return 1 if the topology changed
|
||||
+ * or 0 if it stayed the same.
|
||||
+ */
|
||||
+int __attribute__((weak)) arch_update_cpu_topology(void)
|
||||
{
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -7735,17 +7741,21 @@ void partition_sched_domains(int ndoms_n
|
||||
struct sched_domain_attr *dattr_new)
|
||||
{
|
||||
int i, j, n;
|
||||
+ int top_changed;
|
||||
|
||||
mutex_lock(&sched_domains_mutex);
|
||||
|
||||
/* always unregister in case we don't destroy any domains */
|
||||
unregister_sched_domain_sysctl();
|
||||
|
||||
+ /* Let architecture update cpu core mappings. */
|
||||
+ top_changed = arch_update_cpu_topology();
|
||||
+
|
||||
n = doms_new ? ndoms_new : 0;
|
||||
|
||||
/* Destroy deleted domains */
|
||||
for (i = 0; i < ndoms_cur; i++) {
|
||||
- for (j = 0; j < n; j++) {
|
||||
+ for (j = 0; j < n && !top_changed; j++) {
|
||||
if (cpus_equal(doms_cur[i], doms_new[j])
|
||||
&& dattrs_equal(dattr_cur, i, dattr_new, j))
|
||||
goto match1;
|
||||
@@ -7765,7 +7775,7 @@ match1:
|
||||
|
||||
/* Build new domains */
|
||||
for (i = 0; i < ndoms_new; i++) {
|
||||
- for (j = 0; j < ndoms_cur; j++) {
|
||||
+ for (j = 0; j < ndoms_cur && !top_changed; j++) {
|
||||
if (cpus_equal(doms_new[i], doms_cur[j])
|
||||
&& dattrs_equal(dattr_new, i, dattr_cur, j))
|
||||
goto match2;
|
||||
@@ -0,0 +1,61 @@
|
||||
From: Gerald Schaefer <geraldsc@de.ibm.com>
|
||||
Subject: cio: fix subchannel multipath mode setup
|
||||
References: bnc#466462,LTC#51047
|
||||
|
||||
Symptom: Undefined behavior when trying to access DASD devices with more
|
||||
than one CHPID: e.g. I/O errors due to timeouts after missing
|
||||
interrupts, slow access to DASDs because single path mode is used.
|
||||
Problem: Setup of subchannel multipath mode is not performed correctly
|
||||
because changes to a local buffer are lost before they are sent
|
||||
to the channel subsystem. In this state, the control unit assumes
|
||||
multipath mode while the channel subsystem expects single path
|
||||
mode. As a result, interrupts may not be correctly recognized
|
||||
which leads to timeout situations and eventually I/O errors.
|
||||
Also single path processing may slow down DASD access.
|
||||
Solution: Apply changes to the subchannel configuration after modifying
|
||||
the local buffer.
|
||||
|
||||
Acked-by: John Jolly <jjolly@suse.de>
|
||||
|
||||
---
|
||||
drivers/s390/cio/device.c | 6 ++++++
|
||||
drivers/s390/cio/device_fsm.c | 2 ++
|
||||
2 files changed, 8 insertions(+)
|
||||
|
||||
Index: linux-sles11/drivers/s390/cio/device.c
|
||||
===================================================================
|
||||
--- linux-sles11.orig/drivers/s390/cio/device.c
|
||||
+++ linux-sles11/drivers/s390/cio/device.c
|
||||
@@ -1246,6 +1246,9 @@ static int io_subchannel_probe(struct su
|
||||
return 0;
|
||||
}
|
||||
io_subchannel_init_fields(sch);
|
||||
+ rc = cio_modify(sch);
|
||||
+ if (rc)
|
||||
+ goto out_schedule;
|
||||
/*
|
||||
* First check if a fitting device may be found amongst the
|
||||
* disconnected devices or in the orphanage.
|
||||
@@ -1676,6 +1679,9 @@ static int ccw_device_console_enable(str
|
||||
sch->private = cio_get_console_priv();
|
||||
memset(sch->private, 0, sizeof(struct io_subchannel_private));
|
||||
io_subchannel_init_fields(sch);
|
||||
+ rc = cio_modify(sch);
|
||||
+ if (rc)
|
||||
+ return rc;
|
||||
sch->driver = &io_subchannel_driver;
|
||||
/* Initialize the ccw_device structure. */
|
||||
cdev->dev.parent= &sch->dev;
|
||||
Index: linux-sles11/drivers/s390/cio/device_fsm.c
|
||||
===================================================================
|
||||
--- linux-sles11.orig/drivers/s390/cio/device_fsm.c
|
||||
+++ linux-sles11/drivers/s390/cio/device_fsm.c
|
||||
@@ -1028,6 +1028,8 @@ void ccw_device_trigger_reprobe(struct c
|
||||
sch->schib.pmcw.ena = 0;
|
||||
if ((sch->lpm & (sch->lpm - 1)) != 0)
|
||||
sch->schib.pmcw.mp = 1;
|
||||
+ if (cio_modify(sch))
|
||||
+ return;
|
||||
/* We should also udate ssd info, but this has to wait. */
|
||||
/* Check if this is another device which appeared on the same sch. */
|
||||
if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) {
|
||||
@@ -0,0 +1,109 @@
|
||||
From: Gerald Schaefer <geraldsc@de.ibm.com>
|
||||
Subject: zfcp: fix memory alignment for GPN_FT requests.
|
||||
References: bnc#466462
|
||||
|
||||
Symptom: An unexpected adapter reopen can be triggered in case
|
||||
of a wrongly aligned GPN_FT nameserver request.
|
||||
Problem: A request which is stored across a page is not allowed.
|
||||
The standard memory allocation does not guarantee to have
|
||||
all requested memory within one page.
|
||||
Solution: Make sure the requested memory is always within one page.
|
||||
|
||||
Acked-by: John Jolly <jjolly@suse.de>
|
||||
|
||||
---
|
||||
drivers/s390/scsi/zfcp_aux.c | 7 +++++++
|
||||
drivers/s390/scsi/zfcp_def.h | 9 +++++++++
|
||||
drivers/s390/scsi/zfcp_fc.c | 13 +++----------
|
||||
3 files changed, 19 insertions(+), 10 deletions(-)
|
||||
|
||||
Index: linux-sles11/drivers/s390/scsi/zfcp_aux.c
|
||||
===================================================================
|
||||
--- linux-sles11.orig/drivers/s390/scsi/zfcp_aux.c
|
||||
+++ linux-sles11/drivers/s390/scsi/zfcp_aux.c
|
||||
@@ -175,6 +175,11 @@ static int __init zfcp_module_init(void)
|
||||
if (!zfcp_data.gid_pn_cache)
|
||||
goto out_gid_cache;
|
||||
|
||||
+ zfcp_data.gpn_ft_cache = zfcp_cache_create(
|
||||
+ sizeof(struct ct_iu_gpn_ft_req), "zfcp_gpn");
|
||||
+ if (!zfcp_data.gpn_ft_cache)
|
||||
+ goto out_gpn_cache;
|
||||
+
|
||||
zfcp_data.work_queue = create_singlethread_workqueue("zfcp_wq");
|
||||
|
||||
INIT_LIST_HEAD(&zfcp_data.adapter_list_head);
|
||||
@@ -209,6 +214,8 @@ out_ccw_register:
|
||||
out_misc:
|
||||
fc_release_transport(zfcp_data.scsi_transport_template);
|
||||
out_transport:
|
||||
+ kmem_cache_destroy(zfcp_data.gpn_ft_cache);
|
||||
+out_gpn_cache:
|
||||
kmem_cache_destroy(zfcp_data.gid_pn_cache);
|
||||
out_gid_cache:
|
||||
kmem_cache_destroy(zfcp_data.sr_buffer_cache);
|
||||
Index: linux-sles11/drivers/s390/scsi/zfcp_def.h
|
||||
===================================================================
|
||||
--- linux-sles11.orig/drivers/s390/scsi/zfcp_def.h
|
||||
+++ linux-sles11/drivers/s390/scsi/zfcp_def.h
|
||||
@@ -333,6 +333,14 @@ struct ct_iu_gid_pn_resp {
|
||||
u32 d_id;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
+struct ct_iu_gpn_ft_req {
|
||||
+ struct ct_hdr header;
|
||||
+ u8 flags;
|
||||
+ u8 domain_id_scope;
|
||||
+ u8 area_id_scope;
|
||||
+ u8 fc4_type;
|
||||
+} __attribute__ ((packed));
|
||||
+
|
||||
/**
|
||||
* struct zfcp_send_ct - used to pass parameters to function zfcp_fsf_send_ct
|
||||
* @wka_port: port where the request is sent to
|
||||
@@ -595,6 +603,7 @@ struct zfcp_data {
|
||||
struct kmem_cache *fsf_req_qtcb_cache;
|
||||
struct kmem_cache *sr_buffer_cache;
|
||||
struct kmem_cache *gid_pn_cache;
|
||||
+ struct kmem_cache *gpn_ft_cache;
|
||||
struct workqueue_struct *work_queue;
|
||||
};
|
||||
|
||||
Index: linux-sles11/drivers/s390/scsi/zfcp_fc.c
|
||||
===================================================================
|
||||
--- linux-sles11.orig/drivers/s390/scsi/zfcp_fc.c
|
||||
+++ linux-sles11/drivers/s390/scsi/zfcp_fc.c
|
||||
@@ -10,14 +10,6 @@
|
||||
|
||||
#include "zfcp_ext.h"
|
||||
|
||||
-struct ct_iu_gpn_ft_req {
|
||||
- struct ct_hdr header;
|
||||
- u8 flags;
|
||||
- u8 domain_id_scope;
|
||||
- u8 area_id_scope;
|
||||
- u8 fc4_type;
|
||||
-} __attribute__ ((packed));
|
||||
-
|
||||
struct gpn_ft_resp_acc {
|
||||
u8 control;
|
||||
u8 port_id[3];
|
||||
@@ -450,7 +442,8 @@ static void zfcp_free_sg_env(struct zfcp
|
||||
{
|
||||
struct scatterlist *sg = &gpn_ft->sg_req;
|
||||
|
||||
- kfree(sg_virt(sg)); /* free request buffer */
|
||||
+ /* free request buffer */
|
||||
+ kmem_cache_free(zfcp_data.gpn_ft_cache, sg_virt(sg));
|
||||
zfcp_sg_free_table(gpn_ft->sg_resp, buf_num);
|
||||
|
||||
kfree(gpn_ft);
|
||||
@@ -465,7 +458,7 @@ static struct zfcp_gpn_ft *zfcp_alloc_sg
|
||||
if (!gpn_ft)
|
||||
return NULL;
|
||||
|
||||
- req = kzalloc(sizeof(struct ct_iu_gpn_ft_req), GFP_KERNEL);
|
||||
+ req = kmem_cache_alloc(zfcp_data.gpn_ft_cache, GFP_KERNEL);
|
||||
if (!req) {
|
||||
kfree(gpn_ft);
|
||||
gpn_ft = NULL;
|
||||
@@ -0,0 +1,83 @@
|
||||
From: Gerald Schaefer <geraldsc@de.ibm.com>
|
||||
Subject: iucv: failing cpu hot remove for inactive iucv
|
||||
References: bnc#466462,LTC#51104
|
||||
|
||||
Symptom: cpu hot remove rejected with NOTIFY_BAD
|
||||
Problem: If the iucv module is compiled in / loaded but no user
|
||||
is registered, cpu hot remove doesn't work. The iucv
|
||||
cpu hotplug notifier on CPU_DOWN_PREPARE checks, if
|
||||
the iucv_buffer_cpumask would be empty after the
|
||||
corresponding bit would be cleared. However the bit
|
||||
was never set since iucv wasn't enabled. That causes
|
||||
all cpu hot unplug operations to fail in this scenario.
|
||||
Solution: Use iucv_path_table as an indicator whether iucv is
|
||||
enabled or not.
|
||||
|
||||
Acked-by: John Jolly <jjolly@suse.de>
|
||||
---
|
||||
|
||||
net/iucv/iucv.c | 18 +++++++++++-------
|
||||
1 file changed, 11 insertions(+), 7 deletions(-)
|
||||
|
||||
Index: linux-sles11/net/iucv/iucv.c
|
||||
===================================================================
|
||||
--- linux-sles11.orig/net/iucv/iucv.c
|
||||
+++ linux-sles11/net/iucv/iucv.c
|
||||
@@ -516,6 +516,7 @@ static int iucv_enable(void)
|
||||
size_t alloc_size;
|
||||
int cpu, rc;
|
||||
|
||||
+ get_online_cpus();
|
||||
rc = -ENOMEM;
|
||||
alloc_size = iucv_max_pathid * sizeof(struct iucv_path);
|
||||
iucv_path_table = kzalloc(alloc_size, GFP_KERNEL);
|
||||
@@ -523,19 +524,17 @@ static int iucv_enable(void)
|
||||
goto out;
|
||||
/* Declare per cpu buffers. */
|
||||
rc = -EIO;
|
||||
- get_online_cpus();
|
||||
for_each_online_cpu(cpu)
|
||||
smp_call_function_single(cpu, iucv_declare_cpu, NULL, 1);
|
||||
if (cpus_empty(iucv_buffer_cpumask))
|
||||
/* No cpu could declare an iucv buffer. */
|
||||
- goto out_path;
|
||||
+ goto out;
|
||||
put_online_cpus();
|
||||
return 0;
|
||||
-
|
||||
-out_path:
|
||||
- put_online_cpus();
|
||||
- kfree(iucv_path_table);
|
||||
out:
|
||||
+ kfree(iucv_path_table);
|
||||
+ iucv_path_table = NULL;
|
||||
+ put_online_cpus();
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -550,8 +549,9 @@ static void iucv_disable(void)
|
||||
{
|
||||
get_online_cpus();
|
||||
on_each_cpu(iucv_retrieve_cpu, NULL, 1);
|
||||
- put_online_cpus();
|
||||
kfree(iucv_path_table);
|
||||
+ iucv_path_table = NULL;
|
||||
+ put_online_cpus();
|
||||
}
|
||||
|
||||
static int __cpuinit iucv_cpu_notify(struct notifier_block *self,
|
||||
@@ -588,10 +588,14 @@ static int __cpuinit iucv_cpu_notify(str
|
||||
case CPU_ONLINE_FROZEN:
|
||||
case CPU_DOWN_FAILED:
|
||||
case CPU_DOWN_FAILED_FROZEN:
|
||||
+ if (!iucv_path_table)
|
||||
+ break;
|
||||
smp_call_function_single(cpu, iucv_declare_cpu, NULL, 1);
|
||||
break;
|
||||
case CPU_DOWN_PREPARE:
|
||||
case CPU_DOWN_PREPARE_FROZEN:
|
||||
+ if (!iucv_path_table)
|
||||
+ break;
|
||||
cpumask = iucv_buffer_cpumask;
|
||||
cpu_clear(cpu, cpumask);
|
||||
if (cpus_empty(cpumask))
|
||||
@@ -0,0 +1,31 @@
|
||||
From: Gerald Schaefer <geraldsc@de.ibm.com>
|
||||
Subject: kernel: 31 bit compat sigaltstack syscall fails with -EFAULT.
|
||||
References: bnc#466462,LTC#50888
|
||||
|
||||
Symptom: When 31 bit user space programs call sigaltstack on a 64 bit Linux
|
||||
OS, the system call returns -1 with errno=EFAULT.
|
||||
Problem: The 31 bit pointer passed to the system call is extended
|
||||
to 64 bit, but the high order bits are not set to zero.
|
||||
The kernel detects the invalid user space pointer and
|
||||
returns -EFAULT.
|
||||
Solution: Call sys32_sigaltstack_wrapper() instead of sys32_sigaltstack().
|
||||
The wrapper function sets the high order bits to zero.
|
||||
|
||||
Acked-by: John Jolly <jjolly@suse.de>
|
||||
---
|
||||
arch/s390/kernel/syscalls.S | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
Index: linux-sles11/arch/s390/kernel/syscalls.S
|
||||
===================================================================
|
||||
--- linux-sles11.orig/arch/s390/kernel/syscalls.S
|
||||
+++ linux-sles11/arch/s390/kernel/syscalls.S
|
||||
@@ -194,7 +194,7 @@ SYSCALL(sys_chown16,sys_ni_syscall,sys32
|
||||
SYSCALL(sys_getcwd,sys_getcwd,sys32_getcwd_wrapper)
|
||||
SYSCALL(sys_capget,sys_capget,sys32_capget_wrapper)
|
||||
SYSCALL(sys_capset,sys_capset,sys32_capset_wrapper) /* 185 */
|
||||
-SYSCALL(sys_sigaltstack,sys_sigaltstack,sys32_sigaltstack)
|
||||
+SYSCALL(sys_sigaltstack,sys_sigaltstack,sys32_sigaltstack_wrapper)
|
||||
SYSCALL(sys_sendfile,sys_sendfile64,sys32_sendfile_wrapper)
|
||||
NI_SYSCALL /* streams1 */
|
||||
NI_SYSCALL /* streams2 */
|
||||
@@ -0,0 +1,30 @@
|
||||
From: Gerald Schaefer <geraldsc@de.ibm.com>
|
||||
Subject: topology: introduce arch specific SD_MC_INIT initializer
|
||||
References: bnc#477666,LTC#51049
|
||||
|
||||
Symptom: Up to 30% more cpu usage for some workloads.
|
||||
Problem: For some workloads the extra multicore scheduling domain causes
|
||||
additional cpu usage because of too optimistic assumptions when
|
||||
it is ok to migrate processes from one cpu to another. The default
|
||||
values for SD_MC_INIT don't work well on s390.
|
||||
Solution: Define an architecure specific SD_MC_INIT scheduling domain
|
||||
initializer which fixes the regression.
|
||||
|
||||
Acked-by: John Jolly <jjolly@suse.de>
|
||||
---
|
||||
arch/s390/include/asm/topology.h | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
Index: linux-sles11/arch/s390/include/asm/topology.h
|
||||
===================================================================
|
||||
--- linux-sles11.orig/arch/s390/include/asm/topology.h
|
||||
+++ linux-sles11/arch/s390/include/asm/topology.h
|
||||
@@ -28,6 +28,8 @@ static inline void s390_init_cpu_topolog
|
||||
};
|
||||
#endif
|
||||
|
||||
+#define SD_MC_INIT SD_CPU_INIT
|
||||
+
|
||||
#include <asm-generic/topology.h>
|
||||
|
||||
#endif /* _ASM_S390_TOPOLOGY_H */
|
||||
@@ -0,0 +1,23 @@
|
||||
From: Yi Zou <yi.zou@intel.com>
|
||||
Subject: [FcOE] change fcoe_sw sg_tablesize to SG_ALL
|
||||
References: bnc #459142
|
||||
|
||||
Signed-off-by: Yi Zou <yi.zou@intel.com>
|
||||
Acked-by: Bernhard Walle <bwalle@suse.de>
|
||||
---
|
||||
|
||||
drivers/scsi/fcoe/fcoe_sw.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
|
||||
--- a/drivers/scsi/fcoe/fcoe_sw.c
|
||||
+++ b/drivers/scsi/fcoe/fcoe_sw.c
|
||||
@@ -100,7 +100,7 @@ static struct scsi_host_template fcoe_sw
|
||||
.cmd_per_lun = 32,
|
||||
.can_queue = FCOE_MAX_OUTSTANDING_COMMANDS,
|
||||
.use_clustering = ENABLE_CLUSTERING,
|
||||
- .sg_tablesize = 4,
|
||||
+ .sg_tablesize = SG_ALL,
|
||||
.max_sectors = 0xffff,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
From: Yi Zou <yi.zou@intel.com>
|
||||
Subject: [FcOE] check return for fc_set_mfs
|
||||
References: bnc #459142
|
||||
|
||||
Signed-off-by: Yi Zou <yi.zou@intel.com>
|
||||
Acked-by: Bernhard Walle <bwalle@suse.de>
|
||||
---
|
||||
|
||||
drivers/scsi/fcoe/fcoe_sw.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
|
||||
--- a/drivers/scsi/fcoe/fcoe_sw.c
|
||||
+++ b/drivers/scsi/fcoe/fcoe_sw.c
|
||||
@@ -178,7 +178,8 @@ static int fcoe_sw_netdev_config(struct
|
||||
*/
|
||||
mfs = fc->real_dev->mtu - (sizeof(struct fcoe_hdr) +
|
||||
sizeof(struct fcoe_crc_eof));
|
||||
- fc_set_mfs(lp, mfs);
|
||||
+ if (fc_set_mfs(lp, mfs))
|
||||
+ return -EINVAL;
|
||||
|
||||
lp->link_status = ~FC_PAUSE & ~FC_LINK_UP;
|
||||
if (!fcoe_link_ok(lp))
|
||||
@@ -0,0 +1,149 @@
|
||||
From: Chris Leech <christopher.leech@intel.com>
|
||||
Subject: [FcOE] fix frame length validation in the early receive path
|
||||
References: bnc #459142
|
||||
|
||||
Validation of the frame length was missing before accessing the FC and FCoE
|
||||
headers. Some of the later checks were bogus, because of the way the fr_len
|
||||
variable and skb->len were being manipulated they could never fail.
|
||||
|
||||
Signed-off-by: Chris Leech <christopher.leech@intel.com>
|
||||
Acked-by: Bernhard Walle <bwalle@suse.de>
|
||||
---
|
||||
|
||||
drivers/scsi/fcoe/libfcoe.c | 48 +++++++++++++++++++++-----------------------
|
||||
include/scsi/fc/fc_fcoe.h | 12 +++++++++++
|
||||
include/scsi/fc_frame.h | 2 -
|
||||
3 files changed, 36 insertions(+), 26 deletions(-)
|
||||
|
||||
|
||||
--- a/drivers/scsi/fcoe/libfcoe.c
|
||||
+++ b/drivers/scsi/fcoe/libfcoe.c
|
||||
@@ -184,7 +184,6 @@ int fcoe_rcv(struct sk_buff *skb, struct
|
||||
struct fcoe_rcv_info *fr;
|
||||
struct fcoe_softc *fc;
|
||||
struct fcoe_dev_stats *stats;
|
||||
- u8 *data;
|
||||
struct fc_frame_header *fh;
|
||||
unsigned short oxid;
|
||||
int cpu_idx;
|
||||
@@ -211,9 +210,18 @@ int fcoe_rcv(struct sk_buff *skb, struct
|
||||
FC_DBG("wrong FC type frame");
|
||||
goto err;
|
||||
}
|
||||
- data = skb->data;
|
||||
- data += sizeof(struct fcoe_hdr);
|
||||
- fh = (struct fc_frame_header *)data;
|
||||
+
|
||||
+ /*
|
||||
+ * Check for minimum frame length, and make sure required FCoE
|
||||
+ * and FC headers are pulled into the linear data area.
|
||||
+ */
|
||||
+ if (unlikely((skb->len < FCOE_MIN_FRAME) ||
|
||||
+ !pskb_may_pull(skb, FCOE_HEADER_LEN)))
|
||||
+ goto err;
|
||||
+
|
||||
+ skb_set_transport_header(skb, sizeof(struct fcoe_hdr));
|
||||
+ fh = (struct fc_frame_header *) skb_transport_header(skb);
|
||||
+
|
||||
oxid = ntohs(fh->fh_ox_id);
|
||||
|
||||
fr = fcoe_dev_from_skb(skb);
|
||||
@@ -514,8 +522,6 @@ int fcoe_percpu_receive_thread(void *arg
|
||||
{
|
||||
struct fcoe_percpu_s *p = arg;
|
||||
u32 fr_len;
|
||||
- unsigned int hlen;
|
||||
- unsigned int tlen;
|
||||
struct fc_lport *lp;
|
||||
struct fcoe_rcv_info *fr;
|
||||
struct fcoe_dev_stats *stats;
|
||||
@@ -572,10 +578,12 @@ int fcoe_percpu_receive_thread(void *arg
|
||||
skb_linearize(skb); /* not ideal */
|
||||
|
||||
/*
|
||||
- * Check the header and pull it off.
|
||||
+ * Frame length checks and setting up the header pointers
|
||||
+ * was done in fcoe_rcv already.
|
||||
*/
|
||||
- hlen = sizeof(struct fcoe_hdr);
|
||||
- hp = (struct fcoe_hdr *)skb->data;
|
||||
+ hp = (struct fcoe_hdr *) skb_network_header(skb);
|
||||
+ fh = (struct fc_frame_header *) skb_transport_header(skb);
|
||||
+
|
||||
if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) {
|
||||
if (stats) {
|
||||
if (stats->ErrorFrames < 5)
|
||||
@@ -586,22 +594,10 @@ int fcoe_percpu_receive_thread(void *arg
|
||||
kfree_skb(skb);
|
||||
continue;
|
||||
}
|
||||
+
|
||||
skb_pull(skb, sizeof(struct fcoe_hdr));
|
||||
- tlen = sizeof(struct fcoe_crc_eof);
|
||||
- fr_len = skb->len - tlen;
|
||||
- skb_trim(skb, fr_len);
|
||||
+ fr_len = skb->len - sizeof(struct fcoe_crc_eof);
|
||||
|
||||
- if (unlikely(fr_len > skb->len)) {
|
||||
- if (stats) {
|
||||
- if (stats->ErrorFrames < 5)
|
||||
- FC_DBG("length error fr_len 0x%x "
|
||||
- "skb->len 0x%x", fr_len,
|
||||
- skb->len);
|
||||
- stats->ErrorFrames++;
|
||||
- }
|
||||
- kfree_skb(skb);
|
||||
- continue;
|
||||
- }
|
||||
if (stats) {
|
||||
stats->RxFrames++;
|
||||
stats->RxWords += fr_len / FCOE_WORD_TO_BYTE;
|
||||
@@ -610,9 +606,11 @@ int fcoe_percpu_receive_thread(void *arg
|
||||
fp = (struct fc_frame *)skb;
|
||||
cp = (struct fcoe_crc_eof *)(skb->data + fr_len);
|
||||
fc_frame_init(fp);
|
||||
- fr_eof(fp) = cp->fcoe_eof;
|
||||
- fr_sof(fp) = hp->fcoe_sof;
|
||||
fr_dev(fp) = lp;
|
||||
+ fr_sof(fp) = hp->fcoe_sof;
|
||||
+ fr_eof(fp) = cp->fcoe_eof;
|
||||
+ /* trim off the CRC and EOF trailer*/
|
||||
+ skb_trim(skb, fr_len);
|
||||
|
||||
/*
|
||||
* We only check CRC if no offload is available and if it is
|
||||
--- a/include/scsi/fc/fc_fcoe.h
|
||||
+++ b/include/scsi/fc/fc_fcoe.h
|
||||
@@ -85,6 +85,18 @@ struct fcoe_crc_eof {
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
+ * Minimum FCoE + FC header length
|
||||
+ * 14 bytes FCoE header + 24 byte FC header = 38 bytes
|
||||
+ */
|
||||
+#define FCOE_HEADER_LEN 38
|
||||
+
|
||||
+/*
|
||||
+ * Minimum FCoE frame size
|
||||
+ * 14 bytes FCoE header + 24 byte FC header + 8 byte FCoE trailer = 46 bytes
|
||||
+ */
|
||||
+#define FCOE_MIN_FRAME 46
|
||||
+
|
||||
+/*
|
||||
* fc_fcoe_set_mac - Store OUI + DID into MAC address field.
|
||||
* @mac: mac address to be set
|
||||
* @did: fc dest id to use
|
||||
--- a/include/scsi/fc_frame.h
|
||||
+++ b/include/scsi/fc_frame.h
|
||||
@@ -66,10 +66,10 @@ struct fcoe_rcv_info {
|
||||
struct fc_lport *fr_dev; /* transport layer private pointer */
|
||||
struct fc_seq *fr_seq; /* for use with exchange manager */
|
||||
struct scsi_cmnd *fr_cmd; /* for use of scsi command */
|
||||
+ u16 fr_max_payload; /* max FC payload */
|
||||
enum fc_sof fr_sof; /* start of frame delimiter */
|
||||
enum fc_eof fr_eof; /* end of frame delimiter */
|
||||
u8 fr_flags; /* flags - see below */
|
||||
- u16 fr_max_payload; /* max FC payload */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -0,0 +1,51 @@
|
||||
From: James Bottomley <James.Bottomley@HansenPartnership.com>
|
||||
Subject: fcoe: fix incorrect use of struct module
|
||||
Patch-mainline: 9296e519538b77b5070d49f2f9d66032733c76d4
|
||||
References: bnc #468051
|
||||
|
||||
This structure may not be defined if CONFIG_MODULE=n, so never deref it. Change
|
||||
uses of module->name to module_name(module) and corrects some dyslexic printks
|
||||
and docbook comments.
|
||||
|
||||
Reported-by: Randy Dunlap <randy.dunlap@oracle.com>
|
||||
Cc: Robert Love <robert.w.love@intel.com>
|
||||
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
|
||||
Acked-by: Bernhard Walle <bwalle@suse.de>
|
||||
|
||||
---
|
||||
drivers/scsi/fcoe/libfcoe.c | 10 +++++-----
|
||||
1 file changed, 5 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/drivers/scsi/fcoe/libfcoe.c
|
||||
+++ b/drivers/scsi/fcoe/libfcoe.c
|
||||
@@ -167,7 +167,7 @@ static int fcoe_cpu_callback(struct noti
|
||||
#endif /* CONFIG_HOTPLUG_CPU */
|
||||
|
||||
/**
|
||||
- * foce_rcv - this is the fcoe receive function called by NET_RX_SOFTIRQ
|
||||
+ * fcoe_rcv - this is the fcoe receive function called by NET_RX_SOFTIRQ
|
||||
* @skb: the receive skb
|
||||
* @dev: associated net device
|
||||
* @ptype: context
|
||||
@@ -992,8 +992,8 @@ static int fcoe_ethdrv_get(const struct
|
||||
|
||||
owner = fcoe_netdev_to_module_owner(netdev);
|
||||
if (owner) {
|
||||
- printk(KERN_DEBUG "foce:hold driver module %s for %s\n",
|
||||
- owner->name, netdev->name);
|
||||
+ printk(KERN_DEBUG "fcoe:hold driver module %s for %s\n",
|
||||
+ module_name(owner), netdev->name);
|
||||
return try_module_get(owner);
|
||||
}
|
||||
return -ENODEV;
|
||||
@@ -1012,8 +1012,8 @@ static int fcoe_ethdrv_put(const struct
|
||||
|
||||
owner = fcoe_netdev_to_module_owner(netdev);
|
||||
if (owner) {
|
||||
- printk(KERN_DEBUG "foce:release driver module %s for %s\n",
|
||||
- owner->name, netdev->name);
|
||||
+ printk(KERN_DEBUG "fcoe:release driver module %s for %s\n",
|
||||
+ module_name(owner), netdev->name);
|
||||
module_put(owner);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
From: Vasu Dev <vasu.dev@intel.com>
|
||||
Subject: [FcOE] improved load balancing in rx path
|
||||
References: bnc #459142
|
||||
|
||||
Currently incoming frame exchange id ANDing with total number of bits
|
||||
in online CPU bits mask, resulted only at most two CPUs selection in
|
||||
rx path, so instead used online CPU bits mask to direct incoming frame
|
||||
to a all cpus for better load balancing.
|
||||
|
||||
Added code to default to first CPU in case selected CPU is offline or
|
||||
its rx thread not present.
|
||||
|
||||
Signed-off-by: Vasu Dev <vasu.dev@intel.com>
|
||||
Acked-by: Bernhard Walle <bwalle@suse.de>
|
||||
---
|
||||
|
||||
drivers/scsi/fcoe/libfcoe.c | 13 +++++++------
|
||||
1 file changed, 7 insertions(+), 6 deletions(-)
|
||||
|
||||
|
||||
--- a/drivers/scsi/fcoe/libfcoe.c
|
||||
+++ b/drivers/scsi/fcoe/libfcoe.c
|
||||
@@ -230,13 +230,14 @@ int fcoe_rcv(struct sk_buff *skb, struct
|
||||
cpu_idx = 0;
|
||||
#ifdef CONFIG_SMP
|
||||
/*
|
||||
- * The exchange ID are ANDed with num of online CPUs,
|
||||
- * so that will have the least lock contention in
|
||||
- * handling the exchange. if there is no thread
|
||||
- * for a given idx then use first online cpu.
|
||||
+ * The incoming frame exchange id(oxid) is ANDed with num of online
|
||||
+ * cpu bits to get cpu_idx and then this cpu_idx is used for selecting
|
||||
+ * a per cpu kernel thread from fcoe_percpu. In case the cpu is
|
||||
+ * offline or no kernel thread for derived cpu_idx then cpu_idx is
|
||||
+ * initialize to first online cpu index.
|
||||
*/
|
||||
- cpu_idx = oxid & (num_online_cpus() >> 1);
|
||||
- if (fcoe_percpu[cpu_idx] == NULL)
|
||||
+ cpu_idx = oxid & (num_online_cpus() - 1);
|
||||
+ if (!fcoe_percpu[cpu_idx] || !cpu_online(cpu_idx))
|
||||
cpu_idx = first_cpu(cpu_online_map);
|
||||
#endif
|
||||
fps = fcoe_percpu[cpu_idx];
|
||||
@@ -0,0 +1,26 @@
|
||||
From: Robert Love <robert.w.love@intel.com>
|
||||
Subject: [FcOE] Logoff of the fabric when destroying interface
|
||||
References: bnc #459142
|
||||
|
||||
This line was accidentally removed by a previous patch.
|
||||
|
||||
Signed-off-by: Robert Love <robert.w.love@intel.com>
|
||||
Acked-by: Bernhard Walle <bwalle@suse.de>
|
||||
---
|
||||
|
||||
drivers/scsi/fcoe/fcoe_sw.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
|
||||
--- a/drivers/scsi/fcoe/fcoe_sw.c
|
||||
+++ b/drivers/scsi/fcoe/fcoe_sw.c
|
||||
@@ -302,6 +302,9 @@ static int fcoe_sw_destroy(struct net_de
|
||||
|
||||
fc = fcoe_softc(lp);
|
||||
|
||||
+ /* Logout of the fabric */
|
||||
+ fc_fabric_logoff(lp);
|
||||
+
|
||||
/* Remove the instance from fcoe's list */
|
||||
fcoe_hostlist_remove(lp);
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
From: Yi Zou <yi.zou@intel.com>
|
||||
Subject: [FcOE] remove WARN_ON in fc_set_mfs
|
||||
References: bnc #459142
|
||||
|
||||
remove WARN_ON in fc_set_mfs(), also adde comments.
|
||||
|
||||
Signed-off-by: Yi Zou <yi.zou@intel.com>
|
||||
Acked-by: Bernhard Walle <bwalle@suse.de>
|
||||
---
|
||||
|
||||
drivers/scsi/libfc/fc_lport.c | 13 +++++++++++--
|
||||
1 file changed, 11 insertions(+), 2 deletions(-)
|
||||
|
||||
|
||||
--- a/drivers/scsi/libfc/fc_lport.c
|
||||
+++ b/drivers/scsi/libfc/fc_lport.c
|
||||
@@ -656,10 +656,20 @@ int fc_lport_destroy(struct fc_lport *lp
|
||||
}
|
||||
EXPORT_SYMBOL(fc_lport_destroy);
|
||||
|
||||
+/**
|
||||
+ * fc_set_mfs - sets up the mfs for the corresponding fc_lport
|
||||
+ * @lport: fc_lport pointer to unregister
|
||||
+ * @mfs: the new mfs for fc_lport
|
||||
+ *
|
||||
+ * Set mfs for the given fc_lport to the new mfs.
|
||||
+ *
|
||||
+ * Return: 0 for success
|
||||
+ *
|
||||
+ **/
|
||||
int fc_set_mfs(struct fc_lport *lport, u32 mfs)
|
||||
{
|
||||
unsigned int old_mfs;
|
||||
- int rc = -1;
|
||||
+ int rc = -EINVAL;
|
||||
|
||||
mutex_lock(&lport->lp_mutex);
|
||||
|
||||
@@ -667,7 +677,6 @@ int fc_set_mfs(struct fc_lport *lport, u
|
||||
|
||||
if (mfs >= FC_MIN_MAX_FRAME) {
|
||||
mfs &= ~3;
|
||||
- WARN_ON((size_t) mfs < FC_MIN_MAX_FRAME);
|
||||
if (mfs > FC_MAX_FRAME)
|
||||
mfs = FC_MAX_FRAME;
|
||||
mfs -= sizeof(struct fc_frame_header);
|
||||
@@ -0,0 +1,34 @@
|
||||
From: Yi Zou <yi.zou@intel.com>
|
||||
Subject: [FcOE] user_mfs is never used
|
||||
References: bnc #459142
|
||||
|
||||
Signed-off-by: Yi Zou <yi.zou@intel.com>
|
||||
Acked-by: Bernhard Walle <bwalle@suse.de>
|
||||
---
|
||||
|
||||
drivers/scsi/fcoe/libfcoe.c | 2 --
|
||||
include/scsi/libfcoe.h | 1 -
|
||||
2 files changed, 3 deletions(-)
|
||||
|
||||
|
||||
--- a/drivers/scsi/fcoe/libfcoe.c
|
||||
+++ b/drivers/scsi/fcoe/libfcoe.c
|
||||
@@ -900,8 +900,6 @@ static int fcoe_device_notification(stru
|
||||
mfs = fc->real_dev->mtu -
|
||||
(sizeof(struct fcoe_hdr) +
|
||||
sizeof(struct fcoe_crc_eof));
|
||||
- if (fc->user_mfs && fc->user_mfs < mfs)
|
||||
- mfs = fc->user_mfs;
|
||||
if (mfs >= FC_MIN_MAX_FRAME)
|
||||
fc_set_mfs(lp, mfs);
|
||||
new_status &= ~FC_LINK_UP;
|
||||
--- a/include/scsi/libfcoe.h
|
||||
+++ b/include/scsi/libfcoe.h
|
||||
@@ -46,7 +46,6 @@ struct fcoe_softc {
|
||||
struct net_device *phys_dev; /* device with ethtool_ops */
|
||||
struct packet_type fcoe_packet_type;
|
||||
struct sk_buff_head fcoe_pending_queue;
|
||||
- u16 user_mfs; /* configured max frame size */
|
||||
|
||||
u8 dest_addr[ETH_ALEN];
|
||||
u8 ctl_src_addr[ETH_ALEN];
|
||||
@@ -0,0 +1,29 @@
|
||||
From: Robert Love <robert.w.love@intel.com>
|
||||
Subject: [FcOE] Add fc_disc.c locking comment block
|
||||
References: bnc #459142
|
||||
|
||||
Signed-off-by: Robert Love <robert.w.love@intel.com>
|
||||
Acked-by: Bernhard Walle <bwalle@suse.de>
|
||||
---
|
||||
|
||||
drivers/scsi/libfc/fc_disc.c | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
|
||||
--- a/drivers/scsi/libfc/fc_disc.c
|
||||
+++ b/drivers/scsi/libfc/fc_disc.c
|
||||
@@ -24,6 +24,14 @@
|
||||
* also handles RSCN events and re-discovery if necessary.
|
||||
*/
|
||||
|
||||
+/*
|
||||
+ * DISC LOCKING
|
||||
+ *
|
||||
+ * The disc mutex is can be locked when acquiring rport locks, but may not
|
||||
+ * be held when acquiring the lport lock. Refer to fc_lport.c for more
|
||||
+ * details.
|
||||
+ */
|
||||
+
|
||||
#include <linux/timer.h>
|
||||
#include <linux/err.h>
|
||||
#include <asm/unaligned.h>
|
||||
@@ -0,0 +1,218 @@
|
||||
From 251b8184b1bd4e17656d72ba9cffcba733092064 Mon Sep 17 00:00:00 2001
|
||||
From: Robert Love <robert.w.love@intel.com>
|
||||
Date: Mon, 2 Feb 2009 10:13:06 -0800
|
||||
Subject: [PATCH] libfc: check for err when recv and state is incorrect
|
||||
References: bnc#473602
|
||||
|
||||
If we've just created an interface and the an rport is
|
||||
logging in we may have a request on the wire (say PRLI).
|
||||
If we destroy the interface, we'll go through each rport
|
||||
on the disc->rports list and set each rport's state to NONE.
|
||||
Then the lport will reset the EM. The EM reset will send a
|
||||
CLOSED event to the prli_resp() handler which will notice
|
||||
that the state != PRLI. In this case it frees the frame
|
||||
pointer, decrements the refcount and unlocks the rport.
|
||||
|
||||
The problem is that there isn't a frame in this case. It's
|
||||
just a pointer with an embedded error code. The free causes
|
||||
an Oops.
|
||||
|
||||
This patch moves the error checking to be before the state
|
||||
checking.
|
||||
|
||||
Signed-off-by: Robert Love <robert.w.love@intel.com>
|
||||
Signed-off-by: Hannes Reinecke <hare@suse.de>
|
||||
|
||||
---
|
||||
drivers/scsi/libfc/fc_lport.c | 50 +++++++++++++++++++++---------------------
|
||||
drivers/scsi/libfc/fc_rport.c | 30 ++++++++++++-------------
|
||||
2 files changed, 40 insertions(+), 40 deletions(-)
|
||||
|
||||
--- a/drivers/scsi/libfc/fc_lport.c
|
||||
+++ b/drivers/scsi/libfc/fc_lport.c
|
||||
@@ -1031,17 +1031,17 @@ static void fc_lport_rft_id_resp(struct
|
||||
|
||||
FC_DEBUG_LPORT("Received a RFT_ID response\n");
|
||||
|
||||
+ if (IS_ERR(fp)) {
|
||||
+ fc_lport_error(lport, fp);
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
if (lport->state != LPORT_ST_RFT_ID) {
|
||||
FC_DBG("Received a RFT_ID response, but in state %s\n",
|
||||
fc_lport_state(lport));
|
||||
goto out;
|
||||
}
|
||||
|
||||
- if (IS_ERR(fp)) {
|
||||
- fc_lport_error(lport, fp);
|
||||
- goto err;
|
||||
- }
|
||||
-
|
||||
fh = fc_frame_header_get(fp);
|
||||
ct = fc_frame_payload_get(fp, sizeof(*ct));
|
||||
|
||||
@@ -1083,17 +1083,17 @@ static void fc_lport_rpn_id_resp(struct
|
||||
|
||||
FC_DEBUG_LPORT("Received a RPN_ID response\n");
|
||||
|
||||
+ if (IS_ERR(fp)) {
|
||||
+ fc_lport_error(lport, fp);
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
if (lport->state != LPORT_ST_RPN_ID) {
|
||||
FC_DBG("Received a RPN_ID response, but in state %s\n",
|
||||
fc_lport_state(lport));
|
||||
goto out;
|
||||
}
|
||||
|
||||
- if (IS_ERR(fp)) {
|
||||
- fc_lport_error(lport, fp);
|
||||
- goto err;
|
||||
- }
|
||||
-
|
||||
fh = fc_frame_header_get(fp);
|
||||
ct = fc_frame_payload_get(fp, sizeof(*ct));
|
||||
if (fh && ct && fh->fh_type == FC_TYPE_CT &&
|
||||
@@ -1133,17 +1133,17 @@ static void fc_lport_scr_resp(struct fc_
|
||||
|
||||
FC_DEBUG_LPORT("Received a SCR response\n");
|
||||
|
||||
+ if (IS_ERR(fp)) {
|
||||
+ fc_lport_error(lport, fp);
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
if (lport->state != LPORT_ST_SCR) {
|
||||
FC_DBG("Received a SCR response, but in state %s\n",
|
||||
fc_lport_state(lport));
|
||||
goto out;
|
||||
}
|
||||
|
||||
- if (IS_ERR(fp)) {
|
||||
- fc_lport_error(lport, fp);
|
||||
- goto err;
|
||||
- }
|
||||
-
|
||||
op = fc_frame_payload_op(fp);
|
||||
if (op == ELS_LS_ACC)
|
||||
fc_lport_enter_ready(lport);
|
||||
@@ -1359,17 +1359,17 @@ static void fc_lport_logo_resp(struct fc
|
||||
|
||||
FC_DEBUG_LPORT("Received a LOGO response\n");
|
||||
|
||||
+ if (IS_ERR(fp)) {
|
||||
+ fc_lport_error(lport, fp);
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
if (lport->state != LPORT_ST_LOGO) {
|
||||
FC_DBG("Received a LOGO response, but in state %s\n",
|
||||
fc_lport_state(lport));
|
||||
goto out;
|
||||
}
|
||||
|
||||
- if (IS_ERR(fp)) {
|
||||
- fc_lport_error(lport, fp);
|
||||
- goto err;
|
||||
- }
|
||||
-
|
||||
op = fc_frame_payload_op(fp);
|
||||
if (op == ELS_LS_ACC)
|
||||
fc_lport_enter_reset(lport);
|
||||
@@ -1443,17 +1443,17 @@ static void fc_lport_flogi_resp(struct f
|
||||
|
||||
FC_DEBUG_LPORT("Received a FLOGI response\n");
|
||||
|
||||
+ if (IS_ERR(fp)) {
|
||||
+ fc_lport_error(lport, fp);
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
if (lport->state != LPORT_ST_FLOGI) {
|
||||
FC_DBG("Received a FLOGI response, but in state %s\n",
|
||||
fc_lport_state(lport));
|
||||
goto out;
|
||||
}
|
||||
|
||||
- if (IS_ERR(fp)) {
|
||||
- fc_lport_error(lport, fp);
|
||||
- goto err;
|
||||
- }
|
||||
-
|
||||
fh = fc_frame_header_get(fp);
|
||||
did = ntoh24(fh->fh_d_id);
|
||||
if (fc_frame_payload_op(fp) == ELS_LS_ACC && did != 0) {
|
||||
--- a/drivers/scsi/libfc/fc_rport.c
|
||||
+++ b/drivers/scsi/libfc/fc_rport.c
|
||||
@@ -505,17 +505,17 @@ static void fc_rport_plogi_resp(struct f
|
||||
FC_DEBUG_RPORT("Received a PLOGI response from port (%6x)\n",
|
||||
rport->port_id);
|
||||
|
||||
+ if (IS_ERR(fp)) {
|
||||
+ fc_rport_error_retry(rport, fp);
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
if (rdata->rp_state != RPORT_ST_PLOGI) {
|
||||
FC_DBG("Received a PLOGI response, but in state %s\n",
|
||||
fc_rport_state(rport));
|
||||
goto out;
|
||||
}
|
||||
|
||||
- if (IS_ERR(fp)) {
|
||||
- fc_rport_error_retry(rport, fp);
|
||||
- goto err;
|
||||
- }
|
||||
-
|
||||
op = fc_frame_payload_op(fp);
|
||||
if (op == ELS_LS_ACC &&
|
||||
(plp = fc_frame_payload_get(fp, sizeof(*plp))) != NULL) {
|
||||
@@ -614,17 +614,17 @@ static void fc_rport_prli_resp(struct fc
|
||||
FC_DEBUG_RPORT("Received a PRLI response from port (%6x)\n",
|
||||
rport->port_id);
|
||||
|
||||
+ if (IS_ERR(fp)) {
|
||||
+ fc_rport_error_retry(rport, fp);
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
if (rdata->rp_state != RPORT_ST_PRLI) {
|
||||
FC_DBG("Received a PRLI response, but in state %s\n",
|
||||
fc_rport_state(rport));
|
||||
goto out;
|
||||
}
|
||||
|
||||
- if (IS_ERR(fp)) {
|
||||
- fc_rport_error_retry(rport, fp);
|
||||
- goto err;
|
||||
- }
|
||||
-
|
||||
op = fc_frame_payload_op(fp);
|
||||
if (op == ELS_LS_ACC) {
|
||||
pp = fc_frame_payload_get(fp, sizeof(*pp));
|
||||
@@ -764,17 +764,17 @@ static void fc_rport_rtv_resp(struct fc_
|
||||
FC_DEBUG_RPORT("Received a RTV response from port (%6x)\n",
|
||||
rport->port_id);
|
||||
|
||||
+ if (IS_ERR(fp)) {
|
||||
+ fc_rport_error(rport, fp);
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
if (rdata->rp_state != RPORT_ST_RTV) {
|
||||
FC_DBG("Received a RTV response, but in state %s\n",
|
||||
fc_rport_state(rport));
|
||||
goto out;
|
||||
}
|
||||
|
||||
- if (IS_ERR(fp)) {
|
||||
- fc_rport_error(rport, fp);
|
||||
- goto err;
|
||||
- }
|
||||
-
|
||||
op = fc_frame_payload_op(fp);
|
||||
if (op == ELS_LS_ACC) {
|
||||
struct fc_els_rtv_acc *rtv;
|
||||
@@ -0,0 +1,214 @@
|
||||
From: Robert Love <robert.w.love@intel.com>
|
||||
Subject: libfc: Ensure correct device_put/get usage (round 2)
|
||||
References:
|
||||
|
||||
Reference counting was barely used and where used
|
||||
it was incorrect. This patch creates a few simple
|
||||
policies.
|
||||
|
||||
When the rport->dev [e.g. struct device] is initialized
|
||||
it starts with a refcnt of 1. Whenever we're using the
|
||||
rport we will increment the count. When we logoff we
|
||||
should decrement the count to 0 and the 'release'
|
||||
function will be called. The FC transport provides the
|
||||
release function for real rports and libfc provides it
|
||||
for rogue rports. When we switch from a rogue to real
|
||||
rport we'll decrement the refcnt on the rogue rport
|
||||
and increment it for the real rport, after we've created
|
||||
it.
|
||||
|
||||
Any externally initiated action on an rport (login,
|
||||
logoff) will not require the caller to increment and
|
||||
decrement the refcnt.
|
||||
|
||||
For rport_login(), the rport will have just been created
|
||||
and therefore no other thread would be able to access
|
||||
this object.
|
||||
|
||||
For rport_logoff(), the rport will have been removed
|
||||
from the list of rports and therefore no other thread
|
||||
would be able to lookup() this rport.
|
||||
|
||||
This patch removes the get_device() from the rport_lookup
|
||||
function. These are the places where it is called and why
|
||||
we don't need a reference.
|
||||
|
||||
fc_disc_recv_rscn_req() - called for single port RSCNs
|
||||
the disc mutex is held and
|
||||
ensures that no other thread
|
||||
will find this rport.
|
||||
|
||||
fc_disc_new_target() - Same. The rport cannot be looked up
|
||||
so no other thread can free the rport.
|
||||
This code looks buggy though, we
|
||||
shouldn't be calling rport_login() on
|
||||
a 'real' rport, which we could do.
|
||||
|
||||
fc_disc_single() - Same. disc mutex protects the list.
|
||||
|
||||
fc_lport_recv_req() - Similar, but this time the lport lock
|
||||
ensures that no incoming requests are
|
||||
processed until the current request
|
||||
for an rport has returned.
|
||||
|
||||
When the rport layer needs to send a request it will
|
||||
increment the count so that the EM can be confident that
|
||||
the rport is present when making the callback. If
|
||||
fc_remote_port_delete() is called before the response
|
||||
callback, which is often the case for LOGO commands, the
|
||||
refcnt will still have a value of 1 becuase we grabbed the
|
||||
lock before the ctels_send() is called. The exchange would
|
||||
have been removed and so the callback will be called with
|
||||
an error code. After processing the error code we'll
|
||||
decrement the refcnt for the last time and the rport will
|
||||
be free'd.
|
||||
|
||||
Since point-to-point mode is not working this patch
|
||||
does not consider point-to-point.
|
||||
|
||||
Signed-off-by: Robert Love <robert.w.love@intel.com>
|
||||
Acked-by: Bernhard Walle <bwalle@suse.de>
|
||||
---
|
||||
|
||||
drivers/scsi/libfc/fc_disc.c | 5 +----
|
||||
drivers/scsi/libfc/fc_lport.c | 5 ++---
|
||||
drivers/scsi/libfc/fc_rport.c | 21 ++++++++++++++-------
|
||||
3 files changed, 17 insertions(+), 14 deletions(-)
|
||||
|
||||
|
||||
--- a/drivers/scsi/libfc/fc_disc.c
|
||||
+++ b/drivers/scsi/libfc/fc_disc.c
|
||||
@@ -81,7 +81,6 @@ struct fc_rport *fc_disc_lookup_rport(co
|
||||
if (rport->port_id == port_id) {
|
||||
disc_found = 1;
|
||||
found = rport;
|
||||
- get_device(&found->dev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -767,10 +766,8 @@ static void fc_disc_single(struct fc_dis
|
||||
goto out;
|
||||
|
||||
rport = lport->tt.rport_lookup(lport, dp->ids.port_id);
|
||||
- if (rport) {
|
||||
+ if (rport)
|
||||
fc_disc_del_target(disc, rport);
|
||||
- put_device(&rport->dev); /* hold from lookup */
|
||||
- }
|
||||
|
||||
new_rport = fc_rport_rogue_create(dp);
|
||||
if (new_rport) {
|
||||
--- a/drivers/scsi/libfc/fc_lport.c
|
||||
+++ b/drivers/scsi/libfc/fc_lport.c
|
||||
@@ -908,10 +908,9 @@ static void fc_lport_recv_req(struct fc_
|
||||
d_id = ntoh24(fh->fh_d_id);
|
||||
|
||||
rport = lport->tt.rport_lookup(lport, s_id);
|
||||
- if (rport) {
|
||||
+ if (rport)
|
||||
lport->tt.rport_recv_req(sp, fp, rport);
|
||||
- put_device(&rport->dev); /* hold from lookup */
|
||||
- } else {
|
||||
+ else {
|
||||
rjt_data.fp = NULL;
|
||||
rjt_data.reason = ELS_RJT_UNAB;
|
||||
rjt_data.explan = ELS_EXPL_NONE;
|
||||
--- a/drivers/scsi/libfc/fc_rport.c
|
||||
+++ b/drivers/scsi/libfc/fc_rport.c
|
||||
@@ -111,16 +111,11 @@ struct fc_rport *fc_rport_rogue_create(s
|
||||
rport->roles = dp->ids.roles;
|
||||
rport->maxframe_size = FC_MIN_MAX_PAYLOAD;
|
||||
/*
|
||||
- * init the device, so other code can manipulate the rport as if
|
||||
- * it came from the fc class. We also do an extra get because
|
||||
- * libfc will free this rport instead of relying on the normal
|
||||
- * refcounting.
|
||||
- *
|
||||
* Note: all this libfc rogue rport code will be removed for
|
||||
* upstream so it fine that this is really ugly and hacky right now.
|
||||
*/
|
||||
device_initialize(&rport->dev);
|
||||
- get_device(&rport->dev);
|
||||
+ rport->dev.release = fc_rport_rogue_destroy; // XXX: bwalle
|
||||
|
||||
mutex_init(&rdata->rp_mutex);
|
||||
rdata->local_port = dp->lp;
|
||||
@@ -402,9 +397,9 @@ static void fc_rport_timeout(struct work
|
||||
case RPORT_ST_NONE:
|
||||
break;
|
||||
}
|
||||
- put_device(&rport->dev);
|
||||
|
||||
mutex_unlock(&rdata->rp_mutex);
|
||||
+ put_device(&rport->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -531,6 +526,7 @@ out:
|
||||
fc_frame_free(fp);
|
||||
err:
|
||||
mutex_unlock(&rdata->rp_mutex);
|
||||
+ put_device(&rport->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -562,6 +558,8 @@ static void fc_rport_enter_plogi(struct
|
||||
if (!lport->tt.elsct_send(lport, rport, fp, ELS_PLOGI,
|
||||
fc_rport_plogi_resp, rport, lport->e_d_tov))
|
||||
fc_rport_error(rport, fp);
|
||||
+ else
|
||||
+ get_device(&rport->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -631,6 +629,7 @@ out:
|
||||
fc_frame_free(fp);
|
||||
err:
|
||||
mutex_unlock(&rdata->rp_mutex);
|
||||
+ put_device(&rport->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -679,6 +678,7 @@ out:
|
||||
fc_frame_free(fp);
|
||||
err:
|
||||
mutex_unlock(&rdata->rp_mutex);
|
||||
+ put_device(&rport->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -712,6 +712,8 @@ static void fc_rport_enter_prli(struct f
|
||||
if (!lport->tt.elsct_send(lport, rport, fp, ELS_PRLI,
|
||||
fc_rport_prli_resp, rport, lport->e_d_tov))
|
||||
fc_rport_error(rport, fp);
|
||||
+ else
|
||||
+ get_device(&rport->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -777,6 +779,7 @@ out:
|
||||
fc_frame_free(fp);
|
||||
err:
|
||||
mutex_unlock(&rdata->rp_mutex);
|
||||
+ put_device(&rport->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -806,6 +809,8 @@ static void fc_rport_enter_rtv(struct fc
|
||||
if (!lport->tt.elsct_send(lport, rport, fp, ELS_RTV,
|
||||
fc_rport_rtv_resp, rport, lport->e_d_tov))
|
||||
fc_rport_error(rport, fp);
|
||||
+ else
|
||||
+ get_device(&rport->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -835,6 +840,8 @@ static void fc_rport_enter_logo(struct f
|
||||
if (!lport->tt.elsct_send(lport, rport, fp, ELS_LOGO,
|
||||
fc_rport_logo_resp, rport, lport->e_d_tov))
|
||||
fc_rport_error(rport, fp);
|
||||
+ else
|
||||
+ get_device(&rport->dev);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
From: Vasu Dev <vasu.dev@intel.com>
|
||||
Subject: libfc: handle RRQ exch timeout
|
||||
References: bnc #465596
|
||||
|
||||
Cleanup exchange held due to RRQ when RRQ exch times out, in this case the
|
||||
ABTS is already done causing RRQ req therefore proceeding with cleanup in
|
||||
fc_exch_rrq_resp should be okay to restore exch resource.
|
||||
|
||||
Signed-off-by: Vasu Dev <vasu.dev@intel.com>
|
||||
Acked-by: Bernhard Walle <bwalle@suse.de>
|
||||
---
|
||||
|
||||
drivers/scsi/libfc/fc_exch.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
|
||||
--- a/drivers/scsi/libfc/fc_exch.c
|
||||
+++ b/drivers/scsi/libfc/fc_exch.c
|
||||
@@ -1605,7 +1605,7 @@ static void fc_exch_rrq_resp(struct fc_s
|
||||
if (IS_ERR(fp)) {
|
||||
int err = PTR_ERR(fp);
|
||||
|
||||
- if (err == -FC_EX_CLOSED)
|
||||
+ if (err == -FC_EX_CLOSED || err == -FC_EX_TIMEOUT)
|
||||
goto cleanup;
|
||||
FC_DBG("Cannot process RRQ, because of frame error %d\n", err);
|
||||
return;
|
||||
@@ -0,0 +1,114 @@
|
||||
From: Robert Love <robert.w.love@intel.com>
|
||||
Subject: [FcOE] Improve fc_lport.c locking comment block
|
||||
References: bnc #459142
|
||||
|
||||
Signed-off-by: Robert Love <robert.w.love@intel.com>
|
||||
Acked-by: Bernhard Walle <bwalle@suse.de>
|
||||
---
|
||||
|
||||
drivers/scsi/libfc/fc_lport.c | 76 ++++++++++++++++++++++++------------------
|
||||
1 file changed, 45 insertions(+), 31 deletions(-)
|
||||
|
||||
|
||||
--- a/drivers/scsi/libfc/fc_lport.c
|
||||
+++ b/drivers/scsi/libfc/fc_lport.c
|
||||
@@ -18,34 +18,51 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
- * General locking notes:
|
||||
+ * PORT LOCKING NOTES
|
||||
*
|
||||
- * The lport and rport blocks both have mutexes that are used to protect
|
||||
- * the port objects states. The main motivation for this protection is that
|
||||
- * we don't want to be preparing a request/response in one context while
|
||||
- * another thread "resets" the port in question. For example, if the lport
|
||||
- * block is sending a SCR request to the directory server we don't want
|
||||
- * the lport to be reset before we fill out the frame header's port_id. The
|
||||
- * problem is that a reset would cause the lport's port_id to reset to 0.
|
||||
- * If we don't protect the lport we'd spew incorrect frames.
|
||||
- *
|
||||
- * At the time of this writing there are two primary mutexes, one for the
|
||||
- * lport and one for the rport. Since the lport uses the rport and makes
|
||||
- * calls into that block the rport should never make calls that would cause
|
||||
- * the lport's mutex to be locked. In other words, the lport's mutex is
|
||||
- * considered the outer lock and the rport's lock is considered the inner
|
||||
- * lock. The bottom line is that you can hold a lport's mutex and then
|
||||
- * hold the rport's mutex, but not the other way around.
|
||||
- *
|
||||
- * The only complication to this rule is the callbacks from the rport to
|
||||
- * the lport's rport_callback function. When rports become READY they make
|
||||
- * a callback to the lport so that it can track them. In the case of the
|
||||
- * directory server that callback might cause the lport to change its
|
||||
- * state, implying that the lport mutex would need to be held. This problem
|
||||
- * was solved by serializing the rport notifications to the lport and the
|
||||
- * callback is made without holding the rport's lock.
|
||||
+ * These comments only apply to the 'port code' which consists of the lport,
|
||||
+ * disc and rport blocks.
|
||||
*
|
||||
- * lport locking notes:
|
||||
+ * MOTIVATION
|
||||
+ *
|
||||
+ * The lport, disc and rport blocks all have mutexes that are used to protect
|
||||
+ * those objects. The main motivation for these locks is to prevent from
|
||||
+ * having an lport reset just before we send a frame. In that scenario the
|
||||
+ * lport's FID would get set to zero and then we'd send a frame with an
|
||||
+ * invalid SID. We also need to ensure that states don't change unexpectedly
|
||||
+ * while processing another state.
|
||||
+ *
|
||||
+ * HEIRARCHY
|
||||
+ *
|
||||
+ * The following heirarchy defines the locking rules. A greater lock
|
||||
+ * may be held before acquiring a lesser lock, but a lesser lock should never
|
||||
+ * be held while attempting to acquire a greater lock. Here is the heirarchy-
|
||||
+ *
|
||||
+ * lport > disc, lport > rport, disc > rport
|
||||
+ *
|
||||
+ * CALLBACKS
|
||||
+ *
|
||||
+ * The callbacks cause complications with this scheme. There is a callback
|
||||
+ * from the rport (to either lport or disc) and a callback from disc
|
||||
+ * (to the lport).
|
||||
+ *
|
||||
+ * As rports exit the rport state machine a callback is made to the owner of
|
||||
+ * the rport to notify success or failure. Since the callback is likely to
|
||||
+ * cause the lport or disc to grab its lock we cannot hold the rport lock
|
||||
+ * while making the callback. To ensure that the rport is not free'd while
|
||||
+ * processing the callback the rport callbacks are serialized through a
|
||||
+ * single-threaded workqueue. An rport would never be free'd while in a
|
||||
+ * callback handler becuase no other rport work in this queue can be executed
|
||||
+ * at the same time.
|
||||
+ *
|
||||
+ * When discovery succeeds or fails a callback is made to the lport as
|
||||
+ * notification. Currently, succesful discovery causes the lport to take no
|
||||
+ * action. A failure will cause the lport to reset. There is likely a circular
|
||||
+ * locking problem with this implementation.
|
||||
+ */
|
||||
+
|
||||
+/*
|
||||
+ * LPORT LOCKING
|
||||
*
|
||||
* The critical sections protected by the lport's mutex are quite broad and
|
||||
* may be improved upon in the future. The lport code and its locking doesn't
|
||||
@@ -54,9 +71,9 @@
|
||||
*
|
||||
* The strategy is to lock whenever processing a request or response. Note
|
||||
* that every _enter_* function corresponds to a state change. They generally
|
||||
- * change the lports state and then sends a request out on the wire. We lock
|
||||
+ * change the lports state and then send a request out on the wire. We lock
|
||||
* before calling any of these functions to protect that state change. This
|
||||
- * means that the entry points into the lport block to manage the locks while
|
||||
+ * means that the entry points into the lport block manage the locks while
|
||||
* the state machine can transition between states (i.e. _enter_* functions)
|
||||
* while always staying protected.
|
||||
*
|
||||
@@ -68,9 +85,6 @@
|
||||
* Retries also have to consider the locking. The retries occur from a work
|
||||
* context and the work function will lock the lport and then retry the state
|
||||
* (i.e. _enter_* function).
|
||||
- *
|
||||
- * The implication to all of this is that each lport can only process one
|
||||
- * state at a time.
|
||||
*/
|
||||
|
||||
#include <linux/timer.h>
|
||||
@@ -0,0 +1,50 @@
|
||||
From: Robert Love <robert.w.love@intel.com>
|
||||
Subject: Improve fc_rport.c locking comment block
|
||||
References: 459142
|
||||
|
||||
checkpatch.pl was complaining about having spaces
|
||||
after '*'s. It seemed to be a false positive. I split
|
||||
the comment block into two blocks and it resolved the
|
||||
ERROR.
|
||||
|
||||
Signed-off-by: Robert Love <robert.w.love@intel.com>
|
||||
Acked-by: Bernhard Walle <bwalle@suse.de>
|
||||
---
|
||||
|
||||
drivers/scsi/libfc/fc_rport.c | 17 ++++++++++-------
|
||||
1 file changed, 10 insertions(+), 7 deletions(-)
|
||||
|
||||
|
||||
--- a/drivers/scsi/libfc/fc_rport.c
|
||||
+++ b/drivers/scsi/libfc/fc_rport.c
|
||||
@@ -18,20 +18,23 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
+ * RPORT GENERAL INFO
|
||||
+ *
|
||||
* This file contains all processing regarding fc_rports. It contains the
|
||||
* rport state machine and does all rport interaction with the transport class.
|
||||
* There should be no other places in libfc that interact directly with the
|
||||
* transport class in regards to adding and deleting rports.
|
||||
*
|
||||
* fc_rport's represent N_Port's within the fabric.
|
||||
+ */
|
||||
+
|
||||
+/*
|
||||
+ * RPORT LOCKING
|
||||
*
|
||||
- * rport locking notes:
|
||||
- *
|
||||
- * The rport should never hold the rport mutex and then lock the lport
|
||||
- * mutex. The rport's mutex is considered lesser than the lport's mutex, so
|
||||
- * the lport mutex can be held before locking the rport mutex, but not the
|
||||
- * other way around. See the comment block at the top of fc_lport.c for more
|
||||
- * details.
|
||||
+ * The rport should never hold the rport mutex and then attempt to acquire
|
||||
+ * either the lport or disc mutexes. The rport's mutex is considered lesser
|
||||
+ * than both the lport's mutex and the disc mutex. Refer to fc_lport.c for
|
||||
+ * more comments on the heirarchy.
|
||||
*
|
||||
* The locking strategy is similar to the lport's strategy. The lock protects
|
||||
* the rport's states and is held and released by the entry points to the rport
|
||||
@@ -0,0 +1,217 @@
|
||||
From: Chris Leech <christopher.leech@intel.com>
|
||||
Subject: [FcOE] make fc_disc inline with the fc_lport structure
|
||||
References: bnc #459142
|
||||
|
||||
The extra memory allocation we're not being checked for failure. Rather than
|
||||
further complicating things, just make the discovery code required fields be
|
||||
part of the lport structure.
|
||||
|
||||
Signed-off-by: Chris Leech <christopher.leech@intel.com>
|
||||
Acked-by: Bernhard Walle <bwalle@suse.de>
|
||||
---
|
||||
|
||||
drivers/scsi/libfc/fc_disc.c | 80 +++++++-----------------------------------
|
||||
drivers/scsi/libfc/fc_lport.c | 2 -
|
||||
include/scsi/libfc.h | 22 ++++++++++-
|
||||
3 files changed, 35 insertions(+), 69 deletions(-)
|
||||
|
||||
|
||||
--- a/drivers/scsi/libfc/fc_disc.c
|
||||
+++ b/drivers/scsi/libfc/fc_disc.c
|
||||
@@ -45,26 +45,6 @@ static int fc_disc_debug;
|
||||
FC_DBG(fmt); \
|
||||
} while (0)
|
||||
|
||||
-struct fc_disc {
|
||||
- unsigned char retry_count;
|
||||
- unsigned char delay;
|
||||
- unsigned char pending;
|
||||
- unsigned char requested;
|
||||
- unsigned short seq_count;
|
||||
- unsigned char buf_len;
|
||||
- enum fc_disc_event event;
|
||||
-
|
||||
- void (*disc_callback)(struct fc_lport *,
|
||||
- enum fc_disc_event);
|
||||
-
|
||||
- struct list_head rports;
|
||||
- struct fc_lport *lport;
|
||||
- struct mutex disc_mutex;
|
||||
- struct fc_gpn_ft_resp partial_buf; /* partial name buffer */
|
||||
- struct delayed_work disc_work;
|
||||
-
|
||||
-};
|
||||
-
|
||||
static void fc_disc_gpn_ft_req(struct fc_disc *);
|
||||
static void fc_disc_gpn_ft_resp(struct fc_seq *, struct fc_frame *, void *);
|
||||
static int fc_disc_new_target(struct fc_disc *, struct fc_rport *,
|
||||
@@ -83,14 +63,11 @@ static void fc_disc_restart(struct fc_di
|
||||
struct fc_rport *fc_disc_lookup_rport(const struct fc_lport *lport,
|
||||
u32 port_id)
|
||||
{
|
||||
- struct fc_disc *disc = lport->disc;
|
||||
+ const struct fc_disc *disc = &lport->disc;
|
||||
struct fc_rport *rport, *found = NULL;
|
||||
struct fc_rport_libfc_priv *rdata;
|
||||
int disc_found = 0;
|
||||
|
||||
- if (!disc)
|
||||
- return NULL;
|
||||
-
|
||||
list_for_each_entry(rdata, &disc->rports, peers) {
|
||||
rport = PRIV_TO_RPORT(rdata);
|
||||
if (rport->port_id == port_id) {
|
||||
@@ -108,27 +85,6 @@ struct fc_rport *fc_disc_lookup_rport(co
|
||||
}
|
||||
|
||||
/**
|
||||
- * fc_disc_alloc - Allocate a discovery work object
|
||||
- * @lport: The FC lport associated with the discovery job
|
||||
- */
|
||||
-static inline struct fc_disc *fc_disc_alloc(struct fc_lport *lport)
|
||||
-{
|
||||
- struct fc_disc *disc;
|
||||
-
|
||||
- disc = kzalloc(sizeof(struct fc_disc), GFP_KERNEL);
|
||||
- INIT_DELAYED_WORK(&disc->disc_work, fc_disc_timeout);
|
||||
- mutex_init(&disc->disc_mutex);
|
||||
- INIT_LIST_HEAD(&disc->rports);
|
||||
-
|
||||
- disc->lport = lport;
|
||||
- lport->disc = disc;
|
||||
- disc->delay = FC_DISC_DELAY;
|
||||
- disc->event = DISC_EV_NONE;
|
||||
-
|
||||
- return disc;
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
* fc_disc_stop_rports - delete all the remote ports associated with the lport
|
||||
* @disc: The discovery job to stop rports on
|
||||
*
|
||||
@@ -167,7 +123,7 @@ static void fc_disc_rport_callback(struc
|
||||
enum fc_rport_event event)
|
||||
{
|
||||
struct fc_rport_libfc_priv *rdata = rport->dd_data;
|
||||
- struct fc_disc *disc = lport->disc;
|
||||
+ struct fc_disc *disc = &lport->disc;
|
||||
int found = 0;
|
||||
|
||||
FC_DEBUG_DISC("Received a %d event for port (%6x)\n", event,
|
||||
@@ -304,13 +260,7 @@ static void fc_disc_recv_req(struct fc_s
|
||||
struct fc_lport *lport)
|
||||
{
|
||||
u8 op;
|
||||
- struct fc_disc *disc = lport->disc;
|
||||
-
|
||||
- if (!disc) {
|
||||
- FC_DBG("Received a request for an lport not managed "
|
||||
- "by the discovery engine\n");
|
||||
- return;
|
||||
- }
|
||||
+ struct fc_disc *disc = &lport->disc;
|
||||
|
||||
op = fc_frame_payload_op(fp);
|
||||
switch (op) {
|
||||
@@ -365,17 +315,7 @@ static void fc_disc_start(void (*disc_ca
|
||||
{
|
||||
struct fc_rport *rport;
|
||||
struct fc_rport_identifiers ids;
|
||||
- struct fc_disc *disc = lport->disc;
|
||||
-
|
||||
- if (!disc) {
|
||||
- FC_DEBUG_DISC("No existing discovery job, "
|
||||
- "creating one for lport (%6x)\n",
|
||||
- fc_host_port_id(lport->host));
|
||||
- disc = fc_disc_alloc(lport);
|
||||
- } else
|
||||
- FC_DEBUG_DISC("Found an existing discovery job "
|
||||
- "for lport (%6x)\n",
|
||||
- fc_host_port_id(lport->host));
|
||||
+ struct fc_disc *disc = &lport->disc;
|
||||
|
||||
/*
|
||||
* At this point we may have a new disc job or an existing
|
||||
@@ -831,7 +771,7 @@ out:
|
||||
*/
|
||||
void fc_disc_stop(struct fc_lport *lport)
|
||||
{
|
||||
- struct fc_disc *disc = lport->disc;
|
||||
+ struct fc_disc *disc = &lport->disc;
|
||||
|
||||
if (disc) {
|
||||
cancel_delayed_work_sync(&disc->disc_work);
|
||||
@@ -858,6 +798,7 @@ void fc_disc_stop_final(struct fc_lport
|
||||
*/
|
||||
int fc_disc_init(struct fc_lport *lport)
|
||||
{
|
||||
+ struct fc_disc *disc;
|
||||
|
||||
if (!lport->tt.disc_start)
|
||||
lport->tt.disc_start = fc_disc_start;
|
||||
@@ -874,6 +815,15 @@ int fc_disc_init(struct fc_lport *lport)
|
||||
if (!lport->tt.rport_lookup)
|
||||
lport->tt.rport_lookup = fc_disc_lookup_rport;
|
||||
|
||||
+ disc = &lport->disc;
|
||||
+ INIT_DELAYED_WORK(&disc->disc_work, fc_disc_timeout);
|
||||
+ mutex_init(&disc->disc_mutex);
|
||||
+ INIT_LIST_HEAD(&disc->rports);
|
||||
+
|
||||
+ disc->lport = lport;
|
||||
+ disc->delay = FC_DISC_DELAY;
|
||||
+ disc->event = DISC_EV_NONE;
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(fc_disc_init);
|
||||
--- a/drivers/scsi/libfc/fc_lport.c
|
||||
+++ b/drivers/scsi/libfc/fc_lport.c
|
||||
@@ -627,8 +627,6 @@ int fc_fabric_logoff(struct fc_lport *lp
|
||||
{
|
||||
lport->tt.disc_stop_final(lport);
|
||||
mutex_lock(&lport->lp_mutex);
|
||||
- kfree(lport->disc);
|
||||
- lport->disc = NULL;
|
||||
fc_lport_enter_logo(lport);
|
||||
mutex_unlock(&lport->lp_mutex);
|
||||
return 0;
|
||||
--- a/include/scsi/libfc.h
|
||||
+++ b/include/scsi/libfc.h
|
||||
@@ -572,7 +572,25 @@ struct libfc_function_template {
|
||||
void (*disc_stop_final) (struct fc_lport *);
|
||||
};
|
||||
|
||||
-struct fc_disc;
|
||||
+/* information used by the discovery layer */
|
||||
+struct fc_disc {
|
||||
+ unsigned char retry_count;
|
||||
+ unsigned char delay;
|
||||
+ unsigned char pending;
|
||||
+ unsigned char requested;
|
||||
+ unsigned short seq_count;
|
||||
+ unsigned char buf_len;
|
||||
+ enum fc_disc_event event;
|
||||
+
|
||||
+ void (*disc_callback)(struct fc_lport *,
|
||||
+ enum fc_disc_event);
|
||||
+
|
||||
+ struct list_head rports;
|
||||
+ struct fc_lport *lport;
|
||||
+ struct mutex disc_mutex;
|
||||
+ struct fc_gpn_ft_resp partial_buf; /* partial name buffer */
|
||||
+ struct delayed_work disc_work;
|
||||
+};
|
||||
|
||||
struct fc_lport {
|
||||
struct list_head list;
|
||||
@@ -582,8 +600,8 @@ struct fc_lport {
|
||||
struct fc_exch_mgr *emp;
|
||||
struct fc_rport *dns_rp;
|
||||
struct fc_rport *ptp_rp;
|
||||
- struct fc_disc *disc;
|
||||
void *scsi_priv;
|
||||
+ struct fc_disc disc;
|
||||
|
||||
/* Operational Information */
|
||||
struct libfc_function_template tt;
|
||||
@@ -0,0 +1,59 @@
|
||||
From: Chris Leech <christopher.leech@intel.com>
|
||||
Subject: [FcOE] make RSCN parsing more robust
|
||||
References: bnc #459142
|
||||
|
||||
RSCN parsing needs to verify that the payload length specified in the RSCN ELS
|
||||
message does not exceed the size of the actual frame received.
|
||||
|
||||
Signed-off-by: Chris Leech <christopher.leech@intel.com>
|
||||
Acked-by: Bernhard Walle <bwalle@suse.de>
|
||||
---
|
||||
|
||||
drivers/scsi/libfc/fc_disc.c | 19 +++++++++++++++----
|
||||
1 files changed, 15 insertions(+), 4 deletions(-)
|
||||
|
||||
|
||||
diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c
|
||||
index 0416041..8b609e4 100644
|
||||
--- a/drivers/scsi/libfc/fc_disc.c
|
||||
+++ b/drivers/scsi/libfc/fc_disc.c
|
||||
@@ -173,17 +173,27 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp,
|
||||
FC_DEBUG_DISC("Received an RSCN event on port (%6x)\n",
|
||||
fc_host_port_id(lport->host));
|
||||
|
||||
+ /* make sure the frame contains an RSCN message */
|
||||
rp = fc_frame_payload_get(fp, sizeof(*rp));
|
||||
-
|
||||
- if (!rp || rp->rscn_page_len != sizeof(*pp))
|
||||
+ if (!rp)
|
||||
goto reject;
|
||||
-
|
||||
+ /* make sure the page length is as expected (4 bytes) */
|
||||
+ if (rp->rscn_page_len != sizeof(*pp))
|
||||
+ goto reject;
|
||||
+ /* get the RSCN payload length */
|
||||
len = ntohs(rp->rscn_plen);
|
||||
if (len < sizeof(*rp))
|
||||
goto reject;
|
||||
+ /* make sure the frame contains the expected payload */
|
||||
+ rp = fc_frame_payload_get(fp, len);
|
||||
+ if (!rp)
|
||||
+ goto reject;
|
||||
+ /* payload must be a multiple of the RSCN page size */
|
||||
len -= sizeof(*rp);
|
||||
+ if (len % sizeof(*pp))
|
||||
+ goto reject;
|
||||
|
||||
- for (pp = (void *)(rp + 1); len; len -= sizeof(*pp), pp++) {
|
||||
+ for (pp = (void *)(rp + 1); len > 0; len -= sizeof(*pp), pp++) {
|
||||
ev_qual = pp->rscn_page_flags >> ELS_RSCN_EV_QUAL_BIT;
|
||||
ev_qual &= ELS_RSCN_EV_QUAL_MASK;
|
||||
fmt = pp->rscn_page_flags >> ELS_RSCN_ADDR_FMT_BIT;
|
||||
@@ -239,6 +249,7 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp,
|
||||
fc_frame_free(fp);
|
||||
return;
|
||||
reject:
|
||||
+ FC_DEBUG_DISC("Received a bad RSCN frame\n");
|
||||
rjt_data.fp = NULL;
|
||||
rjt_data.reason = ELS_RJT_LOGIC;
|
||||
rjt_data.explan = ELS_EXPL_NONE;
|
||||
@@ -0,0 +1,114 @@
|
||||
From: Chris Leech <christopher.leech@intel.com>
|
||||
Subject: [FcOE] make sure we access the CRC safely
|
||||
References: bnc #459142
|
||||
|
||||
Even when fcoe verified that the EOF and CRC trailer bytes were there, when
|
||||
the CRC check was delayed for solicited SCSI data libfc would look past what
|
||||
was marked as valid data in the frame to find the CRC in the FCoE trailer.
|
||||
|
||||
Instead, pass the CRC to libfc in the context block.
|
||||
|
||||
Signed-off-by: Chris Leech <christopher.leech@intel.com>
|
||||
Acked-by: Bernhard Walle <bwalle@suse.de>
|
||||
---
|
||||
|
||||
drivers/scsi/fcoe/libfcoe.c | 20 ++++++++++++++------
|
||||
drivers/scsi/libfc/fc_fcp.c | 2 +-
|
||||
drivers/scsi/libfc/fc_frame.c | 2 +-
|
||||
include/scsi/fc_frame.h | 3 +++
|
||||
4 files changed, 19 insertions(+), 8 deletions(-)
|
||||
|
||||
|
||||
--- a/drivers/scsi/fcoe/libfcoe.c
|
||||
+++ b/drivers/scsi/fcoe/libfcoe.c
|
||||
@@ -527,7 +527,7 @@ int fcoe_percpu_receive_thread(void *arg
|
||||
struct fcoe_dev_stats *stats;
|
||||
struct fc_frame_header *fh;
|
||||
struct sk_buff *skb;
|
||||
- struct fcoe_crc_eof *cp;
|
||||
+ struct fcoe_crc_eof crc_eof;
|
||||
struct fc_frame *fp;
|
||||
u8 *mac = NULL;
|
||||
struct fcoe_softc *fc;
|
||||
@@ -604,13 +604,21 @@ int fcoe_percpu_receive_thread(void *arg
|
||||
}
|
||||
|
||||
fp = (struct fc_frame *)skb;
|
||||
- cp = (struct fcoe_crc_eof *)(skb->data + fr_len);
|
||||
fc_frame_init(fp);
|
||||
fr_dev(fp) = lp;
|
||||
fr_sof(fp) = hp->fcoe_sof;
|
||||
- fr_eof(fp) = cp->fcoe_eof;
|
||||
- /* trim off the CRC and EOF trailer*/
|
||||
- skb_trim(skb, fr_len);
|
||||
+
|
||||
+ /* Copy out the CRC and EOF trailer for access */
|
||||
+ if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof))) {
|
||||
+ kfree_skb(skb);
|
||||
+ continue;
|
||||
+ }
|
||||
+ fr_eof(fp) = crc_eof.fcoe_eof;
|
||||
+ fr_crc(fp) = crc_eof.fcoe_crc32;
|
||||
+ if (pskb_trim(skb, fr_len)) {
|
||||
+ kfree_skb(skb);
|
||||
+ continue;
|
||||
+ }
|
||||
|
||||
/*
|
||||
* We only check CRC if no offload is available and if it is
|
||||
@@ -629,7 +637,7 @@ int fcoe_percpu_receive_thread(void *arg
|
||||
continue;
|
||||
}
|
||||
if (fr_flags(fp) & FCPHF_CRC_UNCHECKED) {
|
||||
- if (le32_to_cpu(cp->fcoe_crc32) !=
|
||||
+ if (le32_to_cpu(fr_crc(fp)) !=
|
||||
~crc32(~0, skb->data, fr_len)) {
|
||||
if (debug_fcoe || stats->InvalidCRCCount < 5)
|
||||
printk(KERN_WARNING "fcoe: dropping "
|
||||
--- a/drivers/scsi/libfc/fc_fcp.c
|
||||
+++ b/drivers/scsi/libfc/fc_fcp.c
|
||||
@@ -356,7 +356,7 @@ static void fc_fcp_recv_data(struct fc_f
|
||||
len += 4 - (len % 4);
|
||||
}
|
||||
|
||||
- if (~crc != le32_to_cpu(*(__le32 *)(buf + len))) {
|
||||
+ if (~crc != le32_to_cpu(fr_crc(fp))) {
|
||||
crc_err:
|
||||
stats = lp->dev_stats[smp_processor_id()];
|
||||
stats->ErrorFrames++;
|
||||
--- a/drivers/scsi/libfc/fc_frame.c
|
||||
+++ b/drivers/scsi/libfc/fc_frame.c
|
||||
@@ -42,7 +42,7 @@ u32 fc_frame_crc_check(struct fc_frame *
|
||||
len = (fr_len(fp) + 3) & ~3; /* round up length to include fill */
|
||||
bp = (const u8 *) fr_hdr(fp);
|
||||
crc = ~crc32(~0, bp, len);
|
||||
- error = crc ^ *(u32 *) (bp + len);
|
||||
+ error = crc ^ fr_crc(fp);
|
||||
return error;
|
||||
}
|
||||
EXPORT_SYMBOL(fc_frame_crc_check);
|
||||
--- a/include/scsi/fc_frame.h
|
||||
+++ b/include/scsi/fc_frame.h
|
||||
@@ -56,6 +56,7 @@
|
||||
#define fr_max_payload(fp) (fr_cb(fp)->fr_max_payload)
|
||||
#define fr_cmd(fp) (fr_cb(fp)->fr_cmd)
|
||||
#define fr_dir(fp) (fr_cmd(fp)->sc_data_direction)
|
||||
+#define fr_crc(fp) (fr_cb(fp)->fr_crc)
|
||||
|
||||
struct fc_frame {
|
||||
struct sk_buff skb;
|
||||
@@ -66,12 +67,14 @@ struct fcoe_rcv_info {
|
||||
struct fc_lport *fr_dev; /* transport layer private pointer */
|
||||
struct fc_seq *fr_seq; /* for use with exchange manager */
|
||||
struct scsi_cmnd *fr_cmd; /* for use of scsi command */
|
||||
+ u32 fr_crc;
|
||||
u16 fr_max_payload; /* max FC payload */
|
||||
enum fc_sof fr_sof; /* start of frame delimiter */
|
||||
enum fc_eof fr_eof; /* end of frame delimiter */
|
||||
u8 fr_flags; /* flags - see below */
|
||||
};
|
||||
|
||||
+
|
||||
/*
|
||||
* Get fc_frame pointer for an skb that's already been imported.
|
||||
*/
|
||||
@@ -0,0 +1,90 @@
|
||||
From: Abhijeet Joglekar <abjoglek@cisco.com>
|
||||
Subject: libfc: Pass lport in exch_mgr_reset
|
||||
References: bnc #465596
|
||||
|
||||
fc_exch_mgr structure is private to fc_exch.c. To export exch_mgr_reset to
|
||||
transport, transport needs access to the exch manager. Change
|
||||
exch_mgr_reset to use lport param which is the shared structure between
|
||||
libFC and transport.
|
||||
|
||||
Alternatively, fc_exch_mgr definition can be moved to libfc.h so that lport
|
||||
can be accessed from mp*.
|
||||
|
||||
Signed-off-by: Abhijeet Joglekar <abjoglek@cisco.com>
|
||||
Acked-by: Bernhard Walle <bwalle@suse.de>
|
||||
---
|
||||
|
||||
drivers/scsi/libfc/fc_exch.c | 3 ++-
|
||||
drivers/scsi/libfc/fc_lport.c | 4 ++--
|
||||
drivers/scsi/libfc/fc_rport.c | 4 ++--
|
||||
include/scsi/libfc.h | 4 ++--
|
||||
4 files changed, 8 insertions(+), 7 deletions(-)
|
||||
|
||||
|
||||
--- a/drivers/scsi/libfc/fc_exch.c
|
||||
+++ b/drivers/scsi/libfc/fc_exch.c
|
||||
@@ -1478,10 +1478,11 @@ static void fc_exch_reset(struct fc_exch
|
||||
* If sid is non-zero, reset only exchanges we source from that FID.
|
||||
* If did is non-zero, reset only exchanges destined to that FID.
|
||||
*/
|
||||
-void fc_exch_mgr_reset(struct fc_exch_mgr *mp, u32 sid, u32 did)
|
||||
+void fc_exch_mgr_reset(struct fc_lport *lp, u32 sid, u32 did)
|
||||
{
|
||||
struct fc_exch *ep;
|
||||
struct fc_exch *next;
|
||||
+ struct fc_exch_mgr *mp = lp->emp;
|
||||
|
||||
spin_lock_bh(&mp->em_lock);
|
||||
restart:
|
||||
--- a/drivers/scsi/libfc/fc_lport.c
|
||||
+++ b/drivers/scsi/libfc/fc_lport.c
|
||||
@@ -640,7 +640,7 @@ int fc_lport_destroy(struct fc_lport *lp
|
||||
{
|
||||
lport->tt.frame_send = fc_frame_drop;
|
||||
lport->tt.fcp_abort_io(lport);
|
||||
- lport->tt.exch_mgr_reset(lport->emp, 0, 0);
|
||||
+ lport->tt.exch_mgr_reset(lport, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(fc_lport_destroy);
|
||||
@@ -951,7 +951,7 @@ static void fc_lport_enter_reset(struct
|
||||
|
||||
lport->tt.disc_stop(lport);
|
||||
|
||||
- lport->tt.exch_mgr_reset(lport->emp, 0, 0);
|
||||
+ lport->tt.exch_mgr_reset(lport, 0, 0);
|
||||
fc_host_fabric_name(lport->host) = 0;
|
||||
fc_host_port_id(lport->host) = 0;
|
||||
|
||||
--- a/drivers/scsi/libfc/fc_rport.c
|
||||
+++ b/drivers/scsi/libfc/fc_rport.c
|
||||
@@ -1302,7 +1302,7 @@ void fc_rport_terminate_io(struct fc_rpo
|
||||
struct fc_rport_libfc_priv *rdata = rport->dd_data;
|
||||
struct fc_lport *lport = rdata->local_port;
|
||||
|
||||
- lport->tt.exch_mgr_reset(lport->emp, 0, rport->port_id);
|
||||
- lport->tt.exch_mgr_reset(lport->emp, rport->port_id, 0);
|
||||
+ lport->tt.exch_mgr_reset(lport, 0, rport->port_id);
|
||||
+ lport->tt.exch_mgr_reset(lport, rport->port_id, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(fc_rport_terminate_io);
|
||||
--- a/include/scsi/libfc.h
|
||||
+++ b/include/scsi/libfc.h
|
||||
@@ -469,7 +469,7 @@ struct libfc_function_template {
|
||||
* If s_id is non-zero, reset only exchanges originating from that FID.
|
||||
* If d_id is non-zero, reset only exchanges sending to that FID.
|
||||
*/
|
||||
- void (*exch_mgr_reset)(struct fc_exch_mgr *,
|
||||
+ void (*exch_mgr_reset)(struct fc_lport *,
|
||||
u32 s_id, u32 d_id);
|
||||
|
||||
void (*rport_flush_queue)(void);
|
||||
@@ -908,7 +908,7 @@ struct fc_seq *fc_seq_start_next(struct
|
||||
* If s_id is non-zero, reset only exchanges originating from that FID.
|
||||
* If d_id is non-zero, reset only exchanges sending to that FID.
|
||||
*/
|
||||
-void fc_exch_mgr_reset(struct fc_exch_mgr *, u32 s_id, u32 d_id);
|
||||
+void fc_exch_mgr_reset(struct fc_lport *, u32 s_id, u32 d_id);
|
||||
|
||||
/*
|
||||
* Functions for fc_functions_template
|
||||
@@ -0,0 +1,91 @@
|
||||
From: Robert Love <robert.w.love@intel.com>
|
||||
Subject: [FcOE] Set the release function for the rport's kobject (round 2)
|
||||
References: bnc #459142
|
||||
|
||||
We need to be better about reference counting. The first
|
||||
step is to make use of the release function that is called
|
||||
when the reference count drops to 0.
|
||||
|
||||
There was some inital push back by Joe on this patch. We
|
||||
talked off-list and agreed that the benefit of not having
|
||||
to check whether a rport is rogue or real overweighed the
|
||||
fact that we might be using reference counting on objects
|
||||
(rogue) that cannot be acted on by another thread.
|
||||
|
||||
There is likely room for improvement here, but this should
|
||||
be a stable start.
|
||||
|
||||
Signed-off-by: Robert Love <robert.w.love@intel.com>
|
||||
Acked-by: Bernhard Walle <bwalle@suse.de>
|
||||
---
|
||||
|
||||
drivers/scsi/libfc/fc_rport.c | 18 ++++++++++--------
|
||||
include/scsi/libfc.h | 1 -
|
||||
2 files changed, 10 insertions(+), 9 deletions(-)
|
||||
|
||||
|
||||
--- a/drivers/scsi/libfc/fc_rport.c
|
||||
+++ b/drivers/scsi/libfc/fc_rport.c
|
||||
@@ -93,6 +93,13 @@ static const char *fc_rport_state_names[
|
||||
[RPORT_ST_LOGO] = "LOGO",
|
||||
};
|
||||
|
||||
+static void fc_rport_rogue_destroy(struct device *dev)
|
||||
+{
|
||||
+ struct fc_rport *rport = dev_to_rport(dev);
|
||||
+ FC_DEBUG_RPORT("Destroying rogue rport (%6x)\n", rport->port_id);
|
||||
+ kfree(rport);
|
||||
+}
|
||||
+
|
||||
struct fc_rport *fc_rport_rogue_create(struct fc_disc_port *dp)
|
||||
{
|
||||
struct fc_rport *rport;
|
||||
@@ -115,7 +122,7 @@ struct fc_rport *fc_rport_rogue_create(s
|
||||
* upstream so it fine that this is really ugly and hacky right now.
|
||||
*/
|
||||
device_initialize(&rport->dev);
|
||||
- rport->dev.release = fc_rport_rogue_destroy; // XXX: bwalle
|
||||
+ rport->dev.release = fc_rport_rogue_destroy;
|
||||
|
||||
mutex_init(&rdata->rp_mutex);
|
||||
rdata->local_port = dp->lp;
|
||||
@@ -137,11 +144,6 @@ struct fc_rport *fc_rport_rogue_create(s
|
||||
return rport;
|
||||
}
|
||||
|
||||
-void fc_rport_rogue_destroy(struct fc_rport *rport)
|
||||
-{
|
||||
- kfree(rport);
|
||||
-}
|
||||
-
|
||||
/**
|
||||
* fc_rport_state - return a string for the state the rport is in
|
||||
* @rport: The rport whose state we want to get a string for
|
||||
@@ -263,7 +265,7 @@ static void fc_rport_work(struct work_st
|
||||
"(%6x).\n", ids.port_id);
|
||||
event = RPORT_EV_FAILED;
|
||||
}
|
||||
- fc_rport_rogue_destroy(rport);
|
||||
+ put_device(&rport->dev);
|
||||
rport = new_rport;
|
||||
rdata = new_rport->dd_data;
|
||||
if (rport_ops->event_callback)
|
||||
@@ -276,7 +278,7 @@ static void fc_rport_work(struct work_st
|
||||
if (rport_ops->event_callback)
|
||||
rport_ops->event_callback(lport, rport, event);
|
||||
if (trans_state == FC_PORTSTATE_ROGUE)
|
||||
- fc_rport_rogue_destroy(rport);
|
||||
+ put_device(&rport->dev);
|
||||
else
|
||||
fc_remote_port_delete(rport);
|
||||
} else
|
||||
--- a/include/scsi/libfc.h
|
||||
+++ b/include/scsi/libfc.h
|
||||
@@ -169,7 +169,6 @@ struct fc_rport_libfc_priv {
|
||||
(struct fc_rport_libfc_priv *)((void *)x + sizeof(struct fc_rport));
|
||||
|
||||
struct fc_rport *fc_rport_rogue_create(struct fc_disc_port *);
|
||||
-void fc_rport_rogue_destroy(struct fc_rport *);
|
||||
|
||||
static inline void fc_rport_set_name(struct fc_rport *rport, u64 wwpn, u64 wwnn)
|
||||
{
|
||||
@@ -0,0 +1,56 @@
|
||||
From: Vasu Dev <vasu.dev@intel.com>
|
||||
Subject: [FcOE] updated comment for order of em and ex locks
|
||||
References: bnc #459142
|
||||
|
||||
The fc_exch is public but em_lock is static to fc_exch.c,
|
||||
so updated comment only in fc_exch.c on order of these locks.
|
||||
|
||||
Also removed seq.f_ctl from comments since this field is
|
||||
already removed.
|
||||
|
||||
Signed-off-by: Vasu Dev <vasu.dev@intel.com>
|
||||
Acked-by: Bernhard Walle <bwalle@suse.de>
|
||||
---
|
||||
|
||||
drivers/scsi/libfc/fc_exch.c | 5 ++++-
|
||||
include/scsi/libfc.h | 5 ++---
|
||||
2 files changed, 6 insertions(+), 4 deletions(-)
|
||||
|
||||
|
||||
--- a/drivers/scsi/libfc/fc_exch.c
|
||||
+++ b/drivers/scsi/libfc/fc_exch.c
|
||||
@@ -68,7 +68,8 @@ static struct kmem_cache *fc_em_cachep;
|
||||
*/
|
||||
struct fc_exch_mgr {
|
||||
enum fc_class class; /* default class for sequences */
|
||||
- spinlock_t em_lock; /* exchange manager lock */
|
||||
+ spinlock_t em_lock; /* exchange manager lock,
|
||||
+ must be taken before ex_lock */
|
||||
u16 last_xid; /* last allocated exchange ID */
|
||||
u16 min_xid; /* min exchange ID */
|
||||
u16 max_xid; /* max exchange ID */
|
||||
@@ -179,6 +180,8 @@ static struct fc_seq *fc_seq_start_next_
|
||||
* sequence allocation and deallocation must be locked.
|
||||
* - exchange refcnt can be done atomicly without locks.
|
||||
* - sequence allocation must be locked by exch lock.
|
||||
+ * - If the em_lock and ex_lock must be taken at the same time, then the
|
||||
+ * em_lock must be taken before the ex_lock.
|
||||
*/
|
||||
|
||||
/*
|
||||
--- a/include/scsi/libfc.h
|
||||
+++ b/include/scsi/libfc.h
|
||||
@@ -299,11 +299,10 @@ struct fc_seq {
|
||||
/*
|
||||
* Exchange.
|
||||
*
|
||||
- * Locking notes: The ex_lock protects changes to the following fields:
|
||||
- * esb_stat, f_ctl, seq.ssb_stat, seq.f_ctl.
|
||||
+ * Locking notes: The ex_lock protects following items:
|
||||
+ * state, esb_stat, f_ctl, seq.ssb_stat
|
||||
* seq_id
|
||||
* sequence allocation
|
||||
- *
|
||||
*/
|
||||
struct fc_exch {
|
||||
struct fc_exch_mgr *em; /* exchange manager */
|
||||
@@ -0,0 +1,35 @@
|
||||
From: Vasu Dev <vasu.dev@intel.com>
|
||||
Subject: [FcOE] updated libfc fcoe module ver to 1.0.6
|
||||
References: bnc #459142
|
||||
|
||||
Signed-off-by: Vasu Dev <vasu.dev@intel.com>
|
||||
Acked-by: Bernhard Walle <bwalle@suse.de>
|
||||
---
|
||||
|
||||
drivers/scsi/fcoe/libfcoe.c | 2 +-
|
||||
drivers/scsi/libfc/fc_fcp.c | 2 +-
|
||||
2 files changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
|
||||
--- a/drivers/scsi/fcoe/libfcoe.c
|
||||
+++ b/drivers/scsi/fcoe/libfcoe.c
|
||||
@@ -59,7 +59,7 @@ static int debug_fcoe;
|
||||
MODULE_AUTHOR("Open-FCoE.org");
|
||||
MODULE_DESCRIPTION("FCoE");
|
||||
MODULE_LICENSE("GPL");
|
||||
-MODULE_VERSION("1.0.5");
|
||||
+MODULE_VERSION("1.0.6");
|
||||
|
||||
/* fcoe host list */
|
||||
LIST_HEAD(fcoe_hostlist);
|
||||
--- a/drivers/scsi/libfc/fc_fcp.c
|
||||
+++ b/drivers/scsi/libfc/fc_fcp.c
|
||||
@@ -42,7 +42,7 @@
|
||||
MODULE_AUTHOR("Open-FCoE.org");
|
||||
MODULE_DESCRIPTION("libfc");
|
||||
MODULE_LICENSE("GPL");
|
||||
-MODULE_VERSION("1.0.5");
|
||||
+MODULE_VERSION("1.0.6");
|
||||
|
||||
static int fc_fcp_debug;
|
||||
|
||||
@@ -0,0 +1,275 @@
|
||||
From: Robert Love <robert.w.love@intel.com>
|
||||
Subject: use an operations structure for rport callbacks
|
||||
References: bnc #459142
|
||||
|
||||
This was called out for the disc callbacks in review
|
||||
comments when submitting to linux-scsi. It needed to be
|
||||
fixed for the rport callbacks too.
|
||||
|
||||
This patch also fixes some spacing in the fc_rport
|
||||
structure definition as well as renaming the fc_lport_rport_event()
|
||||
function to fc_lport_rport_callback() to more clearly
|
||||
identify what it's doing.
|
||||
|
||||
Signed-off-by: Robert Love <robert.w.love@intel.com>
|
||||
Acked-by: Bernhard Walle <bwalle@suse.de>
|
||||
---
|
||||
|
||||
drivers/scsi/libfc/fc_disc.c | 18 +++++++++-----
|
||||
drivers/scsi/libfc/fc_lport.c | 16 ++++++++-----
|
||||
drivers/scsi/libfc/fc_rport.c | 19 +++++++--------
|
||||
include/scsi/libfc.h | 51 ++++++++++++++++++++++--------------------
|
||||
4 files changed, 57 insertions(+), 47 deletions(-)
|
||||
|
||||
|
||||
--- a/drivers/scsi/libfc/fc_disc.c
|
||||
+++ b/drivers/scsi/libfc/fc_disc.c
|
||||
@@ -154,7 +154,7 @@ void fc_disc_stop_rports(struct fc_disc
|
||||
}
|
||||
|
||||
/**
|
||||
- * fc_disc_rport_event - Event handler for rport events
|
||||
+ * fc_disc_rport_callback - Event handler for rport events
|
||||
* @lport: The lport which is receiving the event
|
||||
* @rport: The rport which the event has occured on
|
||||
* @event: The event that occured
|
||||
@@ -162,9 +162,9 @@ void fc_disc_stop_rports(struct fc_disc
|
||||
* Locking Note: The rport lock should not be held when calling
|
||||
* this function.
|
||||
*/
|
||||
-static void fc_disc_rport_event(struct fc_lport *lport,
|
||||
- struct fc_rport *rport,
|
||||
- enum fc_lport_event event)
|
||||
+static void fc_disc_rport_callback(struct fc_lport *lport,
|
||||
+ struct fc_rport *rport,
|
||||
+ enum fc_rport_event event)
|
||||
{
|
||||
struct fc_rport_libfc_priv *rdata = rport->dd_data;
|
||||
struct fc_disc *disc = lport->disc;
|
||||
@@ -420,6 +420,10 @@ static void fc_disc_start(void (*disc_ca
|
||||
mutex_unlock(&disc->disc_mutex);
|
||||
}
|
||||
|
||||
+static struct fc_rport_operations fc_disc_rport_ops = {
|
||||
+ .event_callback = fc_disc_rport_callback,
|
||||
+};
|
||||
+
|
||||
/**
|
||||
* fc_disc_new_target - Handle new target found by discovery
|
||||
* @lport: FC local port
|
||||
@@ -475,7 +479,7 @@ static int fc_disc_new_target(struct fc_
|
||||
}
|
||||
if (rport) {
|
||||
rp = rport->dd_data;
|
||||
- rp->event_callback = fc_disc_rport_event;
|
||||
+ rp->ops = &fc_disc_rport_ops;
|
||||
rp->rp_state = RPORT_ST_INIT;
|
||||
lport->tt.rport_login(rport);
|
||||
}
|
||||
@@ -658,7 +662,7 @@ static int fc_disc_gpn_ft_parse(struct f
|
||||
rport = fc_rport_rogue_create(&dp);
|
||||
if (rport) {
|
||||
rdata = rport->dd_data;
|
||||
- rdata->event_callback = fc_disc_rport_event;
|
||||
+ rdata->ops = &fc_disc_rport_ops;
|
||||
rdata->local_port = lport;
|
||||
lport->tt.rport_login(rport);
|
||||
} else
|
||||
@@ -812,7 +816,7 @@ static void fc_disc_single(struct fc_dis
|
||||
new_rport = fc_rport_rogue_create(dp);
|
||||
if (new_rport) {
|
||||
rdata = new_rport->dd_data;
|
||||
- rdata->event_callback = fc_disc_rport_event;
|
||||
+ rdata->ops = &fc_disc_rport_ops;
|
||||
kfree(dp);
|
||||
lport->tt.rport_login(new_rport);
|
||||
}
|
||||
--- a/drivers/scsi/libfc/fc_lport.c
|
||||
+++ b/drivers/scsi/libfc/fc_lport.c
|
||||
@@ -38,7 +38,7 @@
|
||||
* hold the rport's mutex, but not the other way around.
|
||||
*
|
||||
* The only complication to this rule is the callbacks from the rport to
|
||||
- * the lport's event_callback function. When rports become READY they make
|
||||
+ * the lport's rport_callback function. When rports become READY they make
|
||||
* a callback to the lport so that it can track them. In the case of the
|
||||
* directory server that callback might cause the lport to change its
|
||||
* state, implying that the lport mutex would need to be held. This problem
|
||||
@@ -125,7 +125,7 @@ static int fc_frame_drop(struct fc_lport
|
||||
}
|
||||
|
||||
/**
|
||||
- * fc_lport_rport_event - Event handler for rport events
|
||||
+ * fc_lport_rport_callback - Event handler for rport events
|
||||
* @lport: The lport which is receiving the event
|
||||
* @rport: The rport which the event has occured on
|
||||
* @event: The event that occured
|
||||
@@ -133,9 +133,9 @@ static int fc_frame_drop(struct fc_lport
|
||||
* Locking Note: The rport lock should not be held when calling
|
||||
* this function.
|
||||
*/
|
||||
-static void fc_lport_rport_event(struct fc_lport *lport,
|
||||
- struct fc_rport *rport,
|
||||
- enum fc_lport_event event)
|
||||
+static void fc_lport_rport_callback(struct fc_lport *lport,
|
||||
+ struct fc_rport *rport,
|
||||
+ enum fc_rport_event event)
|
||||
{
|
||||
FC_DEBUG_LPORT("Received a %d event for port (%6x)\n", event,
|
||||
rport->port_id);
|
||||
@@ -1265,6 +1265,10 @@ static void fc_lport_enter_rpn_id(struct
|
||||
fc_lport_error(lport, fp);
|
||||
}
|
||||
|
||||
+static struct fc_rport_operations fc_lport_rport_ops = {
|
||||
+ .event_callback = fc_lport_rport_callback,
|
||||
+};
|
||||
+
|
||||
/**
|
||||
* fc_rport_enter_dns - Create a rport to the name server
|
||||
* @lport: Fibre Channel local port requesting a rport for the name server
|
||||
@@ -1294,7 +1298,7 @@ static void fc_lport_enter_dns(struct fc
|
||||
goto err;
|
||||
|
||||
rdata = rport->dd_data;
|
||||
- rdata->event_callback = fc_lport_rport_event;
|
||||
+ rdata->ops = &fc_lport_rport_ops;
|
||||
lport->tt.rport_login(rport);
|
||||
return;
|
||||
|
||||
--- a/drivers/scsi/libfc/fc_rport.c
|
||||
+++ b/drivers/scsi/libfc/fc_rport.c
|
||||
@@ -125,7 +125,7 @@ struct fc_rport *fc_rport_rogue_create(s
|
||||
rdata->rp_state = RPORT_ST_INIT;
|
||||
rdata->event = RPORT_EV_NONE;
|
||||
rdata->flags = FC_RP_FLAGS_REC_SUPPORTED;
|
||||
- rdata->event_callback = NULL;
|
||||
+ rdata->ops = NULL;
|
||||
rdata->e_d_tov = dp->lp->e_d_tov;
|
||||
rdata->r_a_tov = dp->lp->r_a_tov;
|
||||
INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout);
|
||||
@@ -216,16 +216,15 @@ static void fc_rport_work(struct work_st
|
||||
{
|
||||
struct fc_rport_libfc_priv *rdata =
|
||||
container_of(work, struct fc_rport_libfc_priv, event_work);
|
||||
- enum fc_lport_event event;
|
||||
+ enum fc_rport_event event;
|
||||
enum fc_rport_trans_state trans_state;
|
||||
struct fc_lport *lport = rdata->local_port;
|
||||
- void (*event_callback)(struct fc_lport *, struct fc_rport *,
|
||||
- enum fc_lport_event);
|
||||
+ struct fc_rport_operations *rport_ops;
|
||||
struct fc_rport *rport = PRIV_TO_RPORT(rdata);
|
||||
|
||||
mutex_lock(&rdata->rp_mutex);
|
||||
event = rdata->event;
|
||||
- event_callback = rdata->event_callback;
|
||||
+ rport_ops = rdata->ops;
|
||||
|
||||
if (event == RPORT_EV_CREATED) {
|
||||
struct fc_rport *new_rport;
|
||||
@@ -250,7 +249,7 @@ static void fc_rport_work(struct work_st
|
||||
new_rdata = new_rport->dd_data;
|
||||
new_rdata->e_d_tov = rdata->e_d_tov;
|
||||
new_rdata->r_a_tov = rdata->r_a_tov;
|
||||
- new_rdata->event_callback = rdata->event_callback;
|
||||
+ new_rdata->ops = rdata->ops;
|
||||
new_rdata->local_port = rdata->local_port;
|
||||
new_rdata->flags = FC_RP_FLAGS_REC_SUPPORTED;
|
||||
new_rdata->trans_state = FC_PORTSTATE_REAL;
|
||||
@@ -269,15 +268,15 @@ static void fc_rport_work(struct work_st
|
||||
fc_rport_rogue_destroy(rport);
|
||||
rport = new_rport;
|
||||
rdata = new_rport->dd_data;
|
||||
- if (event_callback)
|
||||
- event_callback(lport, rport, event);
|
||||
+ if (rport_ops->event_callback)
|
||||
+ rport_ops->event_callback(lport, rport, event);
|
||||
} else if ((event == RPORT_EV_FAILED) ||
|
||||
(event == RPORT_EV_LOGO) ||
|
||||
(event == RPORT_EV_STOP)) {
|
||||
trans_state = rdata->trans_state;
|
||||
mutex_unlock(&rdata->rp_mutex);
|
||||
- if (event_callback)
|
||||
- event_callback(lport, rport, event);
|
||||
+ if (rport_ops->event_callback)
|
||||
+ rport_ops->event_callback(lport, rport, event);
|
||||
if (trans_state == FC_PORTSTATE_ROGUE)
|
||||
fc_rport_rogue_destroy(rport);
|
||||
else
|
||||
--- a/include/scsi/libfc.h
|
||||
+++ b/include/scsi/libfc.h
|
||||
@@ -89,14 +89,6 @@ enum fc_disc_event {
|
||||
DISC_EV_FAILED
|
||||
};
|
||||
|
||||
-enum fc_lport_event {
|
||||
- RPORT_EV_NONE = 0,
|
||||
- RPORT_EV_CREATED,
|
||||
- RPORT_EV_FAILED,
|
||||
- RPORT_EV_STOP,
|
||||
- RPORT_EV_LOGO
|
||||
-};
|
||||
-
|
||||
enum fc_rport_state {
|
||||
RPORT_ST_NONE = 0,
|
||||
RPORT_ST_INIT, /* initialized */
|
||||
@@ -126,6 +118,19 @@ struct fc_disc_port {
|
||||
struct work_struct rport_work;
|
||||
};
|
||||
|
||||
+enum fc_rport_event {
|
||||
+ RPORT_EV_NONE = 0,
|
||||
+ RPORT_EV_CREATED,
|
||||
+ RPORT_EV_FAILED,
|
||||
+ RPORT_EV_STOP,
|
||||
+ RPORT_EV_LOGO
|
||||
+};
|
||||
+
|
||||
+struct fc_rport_operations {
|
||||
+ void (*event_callback)(struct fc_lport *, struct fc_rport *,
|
||||
+ enum fc_rport_event);
|
||||
+};
|
||||
+
|
||||
/**
|
||||
* struct fc_rport_libfc_priv - libfc internal information about a remote port
|
||||
* @local_port: Fibre Channel host port instance
|
||||
@@ -140,24 +145,22 @@ struct fc_disc_port {
|
||||
* @event_callback: Callback for rport READY, FAILED or LOGO
|
||||
*/
|
||||
struct fc_rport_libfc_priv {
|
||||
- struct fc_lport *local_port;
|
||||
- enum fc_rport_state rp_state;
|
||||
- u16 flags;
|
||||
+ struct fc_lport *local_port;
|
||||
+ enum fc_rport_state rp_state;
|
||||
+ u16 flags;
|
||||
#define FC_RP_FLAGS_REC_SUPPORTED (1 << 0)
|
||||
#define FC_RP_FLAGS_RETRY (1 << 1)
|
||||
- u16 max_seq;
|
||||
- unsigned int retries;
|
||||
- unsigned int e_d_tov;
|
||||
- unsigned int r_a_tov;
|
||||
- enum fc_rport_trans_state trans_state;
|
||||
- struct mutex rp_mutex;
|
||||
- struct delayed_work retry_work;
|
||||
- enum fc_lport_event event;
|
||||
- void (*event_callback)(struct fc_lport *,
|
||||
- struct fc_rport *,
|
||||
- enum fc_lport_event);
|
||||
- struct list_head peers;
|
||||
- struct work_struct event_work;
|
||||
+ u16 max_seq;
|
||||
+ unsigned int retries;
|
||||
+ unsigned int e_d_tov;
|
||||
+ unsigned int r_a_tov;
|
||||
+ enum fc_rport_trans_state trans_state;
|
||||
+ struct mutex rp_mutex;
|
||||
+ struct delayed_work retry_work;
|
||||
+ enum fc_rport_event event;
|
||||
+ struct fc_rport_operations *ops;
|
||||
+ struct list_head peers;
|
||||
+ struct work_struct event_work;
|
||||
};
|
||||
|
||||
#define PRIV_TO_RPORT(x) \
|
||||
@@ -0,0 +1,41 @@
|
||||
From: Abhijeet Joglekar <abjoglek@cisco.com>
|
||||
Subject: libfc: when rport goes away (re-plogi), clean up exchanges to/from rport
|
||||
References: bnc #465596
|
||||
|
||||
When a rport goes away, libFC does a plogi which will reset exchanges
|
||||
at the rport. Clean exchanges at our end, both in transport and libFC.
|
||||
If transport hooks into exch_mgr_reset, it will call back into
|
||||
fc_exch_mgr_reset() to clean up libFC exchanges.
|
||||
|
||||
Signed-off-by: Abhijeet Joglekar <abjoglek@cisco.com>
|
||||
Acked-by: Bernhard Walle <bwalle@suse.de>
|
||||
---
|
||||
|
||||
drivers/scsi/libfc/fc_rport.c | 7 ++++++-
|
||||
1 file changed, 6 insertions(+), 1 deletion(-)
|
||||
|
||||
|
||||
--- a/drivers/scsi/libfc/fc_rport.c
|
||||
+++ b/drivers/scsi/libfc/fc_rport.c
|
||||
@@ -215,6 +215,7 @@ static void fc_rport_state_enter(struct
|
||||
|
||||
static void fc_rport_work(struct work_struct *work)
|
||||
{
|
||||
+ u32 port_id;
|
||||
struct fc_rport_libfc_priv *rdata =
|
||||
container_of(work, struct fc_rport_libfc_priv, event_work);
|
||||
enum fc_rport_event event;
|
||||
@@ -280,8 +281,12 @@ static void fc_rport_work(struct work_st
|
||||
rport_ops->event_callback(lport, rport, event);
|
||||
if (trans_state == FC_PORTSTATE_ROGUE)
|
||||
put_device(&rport->dev);
|
||||
- else
|
||||
+ else {
|
||||
+ port_id = rport->port_id;
|
||||
fc_remote_port_delete(rport);
|
||||
+ lport->tt.exch_mgr_reset(lport, 0, port_id);
|
||||
+ lport->tt.exch_mgr_reset(lport, port_id, 0);
|
||||
+ }
|
||||
} else
|
||||
mutex_unlock(&rdata->rp_mutex);
|
||||
}
|
||||
377
src/patches/suse-2.6.27.25/patches.drivers/libfc_locking.diff
Normal file
377
src/patches/suse-2.6.27.25/patches.drivers/libfc_locking.diff
Normal file
@@ -0,0 +1,377 @@
|
||||
From: Vasu Dev <vasu.dev@intel.com>
|
||||
Subject: libfc, fcoe: fixed locking issues with lport->lp_mutex around lport->link_status
|
||||
Patch-mainline: 6d235742e63f6b8912d8b200b75f9aa6d48f3e07
|
||||
References: bnc #468053
|
||||
|
||||
The fcoe_xmit could call fc_pause in case the pending skb queue len is larger
|
||||
than FCOE_MAX_QUEUE_DEPTH, the fc_pause was trying to grab lport->lp_muex to
|
||||
change lport->link_status and that had these issues :-
|
||||
|
||||
1. The fcoe_xmit was getting called with bh disabled, thus causing
|
||||
"BUG: scheduling while atomic" when grabbing lport->lp_muex with bh disabled.
|
||||
|
||||
2. fc_linkup and fc_linkdown function calls lport_enter function with
|
||||
lport->lp_mutex held and these enter function in turn calls fcoe_xmit to send
|
||||
lport related FC frame, e.g. fc_linkup => fc_lport_enter_flogi to send flogi
|
||||
req. In this case grabbing the same lport->lp_mutex again in fc_puase from
|
||||
fcoe_xmit would cause deadlock.
|
||||
|
||||
The lport->lp_mutex was used for setting FC_PAUSE in fcoe_xmit path but
|
||||
FC_PAUSE bit was not used anywhere beside just setting and clear this
|
||||
bit in lport->link_status, instead used a separate field qfull in fc_lport
|
||||
to eliminate need for lport->lp_mutex to track pending queue full condition
|
||||
and in turn avoid above described two locking issues.
|
||||
|
||||
Also added check for lp->qfull in fc_fcp_lport_queue_ready to trigger
|
||||
SCSI_MLQUEUE_HOST_BUSY when lp->qfull is set to prevent more scsi-ml cmds
|
||||
while lp->qfull is set.
|
||||
|
||||
This patch eliminated FC_LINK_UP and FC_PAUSE and instead used dedicated
|
||||
fields in fc_lport for this, this simplified all related conditional
|
||||
code.
|
||||
|
||||
Also removed fc_pause and fc_unpause functions and instead used newly added
|
||||
lport->qfull directly in fcoe.
|
||||
|
||||
Also fixed a circular locking in fc_exch_recv_abts.
|
||||
|
||||
These issues were blocking large file copy to a 2TB lun.
|
||||
|
||||
Signed-off-by: Vasu Dev <vasu.dev@intel.com>
|
||||
Acked-by: Bernhard Walle <bwalle@suse.de>
|
||||
---
|
||||
drivers/scsi/fcoe/fcoe_sw.c | 6 +++---
|
||||
drivers/scsi/fcoe/libfcoe.c | 41 +++++++++++++++++------------------------
|
||||
drivers/scsi/libfc/fc_exch.c | 2 +-
|
||||
drivers/scsi/libfc/fc_fcp.c | 6 +++---
|
||||
drivers/scsi/libfc/fc_lport.c | 38 +++++++-------------------------------
|
||||
drivers/scsi/libfc/fc_rport.c | 2 +-
|
||||
include/scsi/libfc.h | 12 ++----------
|
||||
7 files changed, 34 insertions(+), 73 deletions(-)
|
||||
|
||||
--- a/drivers/scsi/fcoe/fcoe_sw.c
|
||||
+++ b/drivers/scsi/fcoe/fcoe_sw.c
|
||||
@@ -116,7 +116,8 @@ static int fcoe_sw_lport_config(struct f
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
- lp->link_status = 0;
|
||||
+ lp->link_up = 0;
|
||||
+ lp->qfull = 0;
|
||||
lp->max_retry_count = 3;
|
||||
lp->e_d_tov = 2 * 1000; /* FC-FS default */
|
||||
lp->r_a_tov = 2 * 2 * 1000;
|
||||
@@ -181,9 +182,8 @@ static int fcoe_sw_netdev_config(struct
|
||||
if (fc_set_mfs(lp, mfs))
|
||||
return -EINVAL;
|
||||
|
||||
- lp->link_status = ~FC_PAUSE & ~FC_LINK_UP;
|
||||
if (!fcoe_link_ok(lp))
|
||||
- lp->link_status |= FC_LINK_UP;
|
||||
+ lp->link_up = 1;
|
||||
|
||||
/* offload features support */
|
||||
if (fc->real_dev->features & NETIF_F_SG)
|
||||
--- a/drivers/scsi/fcoe/libfcoe.c
|
||||
+++ b/drivers/scsi/fcoe/libfcoe.c
|
||||
@@ -505,7 +505,7 @@ int fcoe_xmit(struct fc_lport *lp, struc
|
||||
if (rc) {
|
||||
fcoe_insert_wait_queue(lp, skb);
|
||||
if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH)
|
||||
- fc_pause(lp);
|
||||
+ lp->qfull = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -719,7 +719,7 @@ static void fcoe_recv_flogi(struct fcoe_
|
||||
* fcoe_watchdog - fcoe timer callback
|
||||
* @vp:
|
||||
*
|
||||
- * This checks the pending queue length for fcoe and put fcoe to be paused state
|
||||
+ * This checks the pending queue length for fcoe and set lport qfull
|
||||
* if the FCOE_MAX_QUEUE_DEPTH is reached. This is done for all fc_lport on the
|
||||
* fcoe_hostlist.
|
||||
*
|
||||
@@ -729,17 +729,17 @@ void fcoe_watchdog(ulong vp)
|
||||
{
|
||||
struct fc_lport *lp;
|
||||
struct fcoe_softc *fc;
|
||||
- int paused = 0;
|
||||
+ int qfilled = 0;
|
||||
|
||||
read_lock(&fcoe_hostlist_lock);
|
||||
list_for_each_entry(fc, &fcoe_hostlist, list) {
|
||||
lp = fc->lp;
|
||||
if (lp) {
|
||||
if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH)
|
||||
- paused = 1;
|
||||
+ qfilled = 1;
|
||||
if (fcoe_check_wait_queue(lp) < FCOE_MAX_QUEUE_DEPTH) {
|
||||
- if (paused)
|
||||
- fc_unpause(lp);
|
||||
+ if (qfilled)
|
||||
+ lp->qfull = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -768,8 +768,7 @@ void fcoe_watchdog(ulong vp)
|
||||
**/
|
||||
static int fcoe_check_wait_queue(struct fc_lport *lp)
|
||||
{
|
||||
- int rc, unpause = 0;
|
||||
- int paused = 0;
|
||||
+ int rc;
|
||||
struct sk_buff *skb;
|
||||
struct fcoe_softc *fc;
|
||||
|
||||
@@ -777,10 +776,10 @@ static int fcoe_check_wait_queue(struct
|
||||
spin_lock_bh(&fc->fcoe_pending_queue.lock);
|
||||
|
||||
/*
|
||||
- * is this interface paused?
|
||||
+ * if interface pending queue full then set qfull in lport.
|
||||
*/
|
||||
if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH)
|
||||
- paused = 1;
|
||||
+ lp->qfull = 1;
|
||||
if (fc->fcoe_pending_queue.qlen) {
|
||||
while ((skb = __skb_dequeue(&fc->fcoe_pending_queue)) != NULL) {
|
||||
spin_unlock_bh(&fc->fcoe_pending_queue.lock);
|
||||
@@ -792,11 +791,9 @@ static int fcoe_check_wait_queue(struct
|
||||
spin_lock_bh(&fc->fcoe_pending_queue.lock);
|
||||
}
|
||||
if (fc->fcoe_pending_queue.qlen < FCOE_MAX_QUEUE_DEPTH)
|
||||
- unpause = 1;
|
||||
+ lp->qfull = 0;
|
||||
}
|
||||
spin_unlock_bh(&fc->fcoe_pending_queue.lock);
|
||||
- if ((unpause) && (paused))
|
||||
- fc_unpause(lp);
|
||||
return fc->fcoe_pending_queue.qlen;
|
||||
}
|
||||
|
||||
@@ -874,7 +871,7 @@ static int fcoe_device_notification(stru
|
||||
struct net_device *real_dev = ptr;
|
||||
struct fcoe_softc *fc;
|
||||
struct fcoe_dev_stats *stats;
|
||||
- u16 new_status;
|
||||
+ u32 new_link_up;
|
||||
u32 mfs;
|
||||
int rc = NOTIFY_OK;
|
||||
|
||||
@@ -891,17 +888,15 @@ static int fcoe_device_notification(stru
|
||||
goto out;
|
||||
}
|
||||
|
||||
- new_status = lp->link_status;
|
||||
+ new_link_up = lp->link_up;
|
||||
switch (event) {
|
||||
case NETDEV_DOWN:
|
||||
case NETDEV_GOING_DOWN:
|
||||
- new_status &= ~FC_LINK_UP;
|
||||
+ new_link_up = 0;
|
||||
break;
|
||||
case NETDEV_UP:
|
||||
case NETDEV_CHANGE:
|
||||
- new_status &= ~FC_LINK_UP;
|
||||
- if (!fcoe_link_ok(lp))
|
||||
- new_status |= FC_LINK_UP;
|
||||
+ new_link_up = !fcoe_link_ok(lp);
|
||||
break;
|
||||
case NETDEV_CHANGEMTU:
|
||||
mfs = fc->real_dev->mtu -
|
||||
@@ -909,17 +904,15 @@ static int fcoe_device_notification(stru
|
||||
sizeof(struct fcoe_crc_eof));
|
||||
if (mfs >= FC_MIN_MAX_FRAME)
|
||||
fc_set_mfs(lp, mfs);
|
||||
- new_status &= ~FC_LINK_UP;
|
||||
- if (!fcoe_link_ok(lp))
|
||||
- new_status |= FC_LINK_UP;
|
||||
+ new_link_up = !fcoe_link_ok(lp);
|
||||
break;
|
||||
case NETDEV_REGISTER:
|
||||
break;
|
||||
default:
|
||||
FC_DBG("unknown event %ld call", event);
|
||||
}
|
||||
- if (lp->link_status != new_status) {
|
||||
- if ((new_status & FC_LINK_UP) == FC_LINK_UP)
|
||||
+ if (lp->link_up != new_link_up) {
|
||||
+ if (new_link_up)
|
||||
fc_linkup(lp);
|
||||
else {
|
||||
stats = lp->dev_stats[smp_processor_id()];
|
||||
--- a/drivers/scsi/libfc/fc_exch.c
|
||||
+++ b/drivers/scsi/libfc/fc_exch.c
|
||||
@@ -1096,7 +1096,7 @@ static void fc_exch_recv_abts(struct fc_
|
||||
ap->ba_high_seq_cnt = fh->fh_seq_cnt;
|
||||
ap->ba_low_seq_cnt = htons(sp->cnt);
|
||||
}
|
||||
- sp = fc_seq_start_next(sp);
|
||||
+ sp = fc_seq_start_next_locked(sp);
|
||||
spin_unlock_bh(&ep->ex_lock);
|
||||
fc_seq_send_last(sp, fp, FC_RCTL_BA_ACC, FC_TYPE_BLS);
|
||||
fc_frame_free(rx_fp);
|
||||
--- a/drivers/scsi/libfc/fc_fcp.c
|
||||
+++ b/drivers/scsi/libfc/fc_fcp.c
|
||||
@@ -20,13 +20,13 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
+#include <linux/delay.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/crc32.h>
|
||||
-#include <linux/delay.h>
|
||||
|
||||
#include <scsi/scsi_tcq.h>
|
||||
#include <scsi/scsi.h>
|
||||
@@ -1622,7 +1622,7 @@ out:
|
||||
static inline int fc_fcp_lport_queue_ready(struct fc_lport *lp)
|
||||
{
|
||||
/* lock ? */
|
||||
- return (lp->state == LPORT_ST_READY) && (lp->link_status & FC_LINK_UP);
|
||||
+ return (lp->state == LPORT_ST_READY) && lp->link_up && !lp->qfull;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1891,7 +1891,7 @@ int fc_eh_abort(struct scsi_cmnd *sc_cmd
|
||||
lp = shost_priv(sc_cmd->device->host);
|
||||
if (lp->state != LPORT_ST_READY)
|
||||
return rc;
|
||||
- else if (!(lp->link_status & FC_LINK_UP))
|
||||
+ else if (!lp->link_up)
|
||||
return rc;
|
||||
|
||||
spin_lock_irqsave(lp->host->host_lock, flags);
|
||||
--- a/drivers/scsi/libfc/fc_lport.c
|
||||
+++ b/drivers/scsi/libfc/fc_lport.c
|
||||
@@ -250,7 +250,7 @@ void fc_get_host_port_state(struct Scsi_
|
||||
{
|
||||
struct fc_lport *lp = shost_priv(shost);
|
||||
|
||||
- if ((lp->link_status & FC_LINK_UP) == FC_LINK_UP)
|
||||
+ if (lp->link_up)
|
||||
fc_host_port_state(shost) = FC_PORTSTATE_ONLINE;
|
||||
else
|
||||
fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE;
|
||||
@@ -484,7 +484,7 @@ static void fc_lport_recv_rnid_req(struc
|
||||
* @sp: current sequence in the ADISC exchange
|
||||
* @fp: ADISC request frame
|
||||
*
|
||||
- * Locking Note: The lport lock is exected to be held before calling
|
||||
+ * Locking Note: The lport lock is expected to be held before calling
|
||||
* this function.
|
||||
*/
|
||||
static void fc_lport_recv_adisc_req(struct fc_seq *sp, struct fc_frame *in_fp,
|
||||
@@ -577,8 +577,8 @@ void fc_linkup(struct fc_lport *lport)
|
||||
fc_host_port_id(lport->host));
|
||||
|
||||
mutex_lock(&lport->lp_mutex);
|
||||
- if ((lport->link_status & FC_LINK_UP) != FC_LINK_UP) {
|
||||
- lport->link_status |= FC_LINK_UP;
|
||||
+ if (!lport->link_up) {
|
||||
+ lport->link_up = 1;
|
||||
|
||||
if (lport->state == LPORT_ST_RESET)
|
||||
fc_lport_enter_flogi(lport);
|
||||
@@ -597,8 +597,8 @@ void fc_linkdown(struct fc_lport *lport)
|
||||
FC_DEBUG_LPORT("Link is down for port (%6x)\n",
|
||||
fc_host_port_id(lport->host));
|
||||
|
||||
- if ((lport->link_status & FC_LINK_UP) == FC_LINK_UP) {
|
||||
- lport->link_status &= ~(FC_LINK_UP);
|
||||
+ if (lport->link_up) {
|
||||
+ lport->link_up = 0;
|
||||
fc_lport_enter_reset(lport);
|
||||
lport->tt.fcp_cleanup(lport);
|
||||
}
|
||||
@@ -607,30 +607,6 @@ void fc_linkdown(struct fc_lport *lport)
|
||||
EXPORT_SYMBOL(fc_linkdown);
|
||||
|
||||
/**
|
||||
- * fc_pause - Pause the flow of frames
|
||||
- * @lport: The lport to be paused
|
||||
- */
|
||||
-void fc_pause(struct fc_lport *lport)
|
||||
-{
|
||||
- mutex_lock(&lport->lp_mutex);
|
||||
- lport->link_status |= FC_PAUSE;
|
||||
- mutex_unlock(&lport->lp_mutex);
|
||||
-}
|
||||
-EXPORT_SYMBOL(fc_pause);
|
||||
-
|
||||
-/**
|
||||
- * fc_unpause - Unpause the flow of frames
|
||||
- * @lport: The lport to be unpaused
|
||||
- */
|
||||
-void fc_unpause(struct fc_lport *lport)
|
||||
-{
|
||||
- mutex_lock(&lport->lp_mutex);
|
||||
- lport->link_status &= ~(FC_PAUSE);
|
||||
- mutex_unlock(&lport->lp_mutex);
|
||||
-}
|
||||
-EXPORT_SYMBOL(fc_unpause);
|
||||
-
|
||||
-/**
|
||||
* fc_fabric_logoff - Logout of the fabric
|
||||
* @lport: fc_lport pointer to logoff the fabric
|
||||
*
|
||||
@@ -977,7 +953,7 @@ static void fc_lport_enter_reset(struct
|
||||
fc_host_fabric_name(lport->host) = 0;
|
||||
fc_host_port_id(lport->host) = 0;
|
||||
|
||||
- if ((lport->link_status & FC_LINK_UP) == FC_LINK_UP)
|
||||
+ if (lport->link_up)
|
||||
fc_lport_enter_flogi(lport);
|
||||
}
|
||||
|
||||
--- a/drivers/scsi/libfc/fc_rport.c
|
||||
+++ b/drivers/scsi/libfc/fc_rport.c
|
||||
@@ -425,7 +425,7 @@ static void fc_rport_error(struct fc_rpo
|
||||
PTR_ERR(fp), fc_rport_state(rport), rdata->retries);
|
||||
|
||||
if (!fp || PTR_ERR(fp) == -FC_EX_TIMEOUT) {
|
||||
- /*
|
||||
+ /*
|
||||
* Memory allocation failure, or the exchange timed out.
|
||||
* Retry after delay
|
||||
*/
|
||||
--- a/include/scsi/libfc.h
|
||||
+++ b/include/scsi/libfc.h
|
||||
@@ -68,9 +68,6 @@
|
||||
/*
|
||||
* FC HBA status
|
||||
*/
|
||||
-#define FC_PAUSE (1 << 1)
|
||||
-#define FC_LINK_UP (1 << 0)
|
||||
-
|
||||
enum fc_lport_state {
|
||||
LPORT_ST_NONE = 0,
|
||||
LPORT_ST_FLOGI,
|
||||
@@ -603,7 +600,8 @@ struct fc_lport {
|
||||
|
||||
/* Operational Information */
|
||||
struct libfc_function_template tt;
|
||||
- u16 link_status;
|
||||
+ u8 link_up;
|
||||
+ u8 qfull;
|
||||
enum fc_lport_state state;
|
||||
unsigned long boot_time;
|
||||
|
||||
@@ -704,12 +702,6 @@ void fc_linkup(struct fc_lport *);
|
||||
void fc_linkdown(struct fc_lport *);
|
||||
|
||||
/*
|
||||
- * Pause and unpause traffic.
|
||||
- */
|
||||
-void fc_pause(struct fc_lport *);
|
||||
-void fc_unpause(struct fc_lport *);
|
||||
-
|
||||
-/*
|
||||
* Configure the local port.
|
||||
*/
|
||||
int fc_lport_config(struct fc_lport *);
|
||||
265
src/patches/suse-2.6.27.25/patches.drivers/libfc_rport.diff
Normal file
265
src/patches/suse-2.6.27.25/patches.drivers/libfc_rport.diff
Normal file
@@ -0,0 +1,265 @@
|
||||
From: Chris Leech <christopher.leech@intel.com>
|
||||
Subject: libfc: rport retry on LS_RJT from certain ELS
|
||||
Patch-mainline: 6147a1194ba86af4266f36c9522a7b0040af98fe
|
||||
References: bnc #468054
|
||||
|
||||
This allows any rport ELS to retry on LS_RJT.
|
||||
|
||||
The rport error handling would only retry on resource allocation failures
|
||||
and exchange timeouts. I have a target that will occasionally reject PLOGI
|
||||
when we do a quick LOGO/PLOGI. When a critical ELS was rejected, libfc would
|
||||
fail silently leaving the rport in a dead state.
|
||||
|
||||
The retry count and delay are managed by fc_rport_error_retry. If the retry
|
||||
count is exceeded fc_rport_error will be called. When retrying is not the
|
||||
correct course of action, fc_rport_error can be called directly.
|
||||
|
||||
Signed-off-by: Chris Leech <christopher.leech@intel.com>
|
||||
Acked-by: Bernhard Walle <bwalle@suse.de>
|
||||
---
|
||||
drivers/scsi/libfc/fc_exch.c | 2
|
||||
drivers/scsi/libfc/fc_rport.c | 111 ++++++++++++++++++++++++------------------
|
||||
include/scsi/fc/fc_fs.h | 5 +
|
||||
3 files changed, 69 insertions(+), 49 deletions(-)
|
||||
|
||||
--- a/drivers/scsi/libfc/fc_exch.c
|
||||
+++ b/drivers/scsi/libfc/fc_exch.c
|
||||
@@ -32,8 +32,6 @@
|
||||
#include <scsi/libfc.h>
|
||||
#include <scsi/fc_encode.h>
|
||||
|
||||
-#define FC_DEF_R_A_TOV (10 * 1000) /* resource allocation timeout */
|
||||
-
|
||||
/*
|
||||
* fc_exch_debug can be set in debugger or at compile time to get more logs.
|
||||
*/
|
||||
--- a/drivers/scsi/libfc/fc_rport.c
|
||||
+++ b/drivers/scsi/libfc/fc_rport.c
|
||||
@@ -81,6 +81,7 @@ static void fc_rport_recv_logo_req(struc
|
||||
struct fc_seq *, struct fc_frame *);
|
||||
static void fc_rport_timeout(struct work_struct *);
|
||||
static void fc_rport_error(struct fc_rport *, struct fc_frame *);
|
||||
+static void fc_rport_error_retry(struct fc_rport *, struct fc_frame *);
|
||||
static void fc_rport_work(struct work_struct *);
|
||||
|
||||
static const char *fc_rport_state_names[] = {
|
||||
@@ -405,55 +406,71 @@ static void fc_rport_timeout(struct work
|
||||
}
|
||||
|
||||
/**
|
||||
- * fc_rport_error - Handler for any errors
|
||||
+ * fc_rport_error - Error handler, called once retries have been exhausted
|
||||
* @rport: The fc_rport object
|
||||
* @fp: The frame pointer
|
||||
*
|
||||
- * If the error was caused by a resource allocation failure
|
||||
- * then wait for half a second and retry, otherwise retry
|
||||
- * immediately.
|
||||
- *
|
||||
* Locking Note: The rport lock is expected to be held before
|
||||
* calling this routine
|
||||
*/
|
||||
static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp)
|
||||
{
|
||||
struct fc_rport_libfc_priv *rdata = rport->dd_data;
|
||||
- unsigned long delay = 0;
|
||||
|
||||
FC_DEBUG_RPORT("Error %ld in state %s, retries %d\n",
|
||||
PTR_ERR(fp), fc_rport_state(rport), rdata->retries);
|
||||
|
||||
- if (!fp || PTR_ERR(fp) == -FC_EX_TIMEOUT) {
|
||||
- /*
|
||||
- * Memory allocation failure, or the exchange timed out.
|
||||
- * Retry after delay
|
||||
- */
|
||||
- if (rdata->retries < rdata->local_port->max_retry_count) {
|
||||
- rdata->retries++;
|
||||
- if (!fp)
|
||||
- delay = msecs_to_jiffies(500);
|
||||
- get_device(&rport->dev);
|
||||
- schedule_delayed_work(&rdata->retry_work, delay);
|
||||
- } else {
|
||||
- switch (rdata->rp_state) {
|
||||
- case RPORT_ST_PLOGI:
|
||||
- case RPORT_ST_PRLI:
|
||||
- case RPORT_ST_LOGO:
|
||||
- rdata->event = RPORT_EV_FAILED;
|
||||
- queue_work(rport_event_queue,
|
||||
- &rdata->event_work);
|
||||
- break;
|
||||
- case RPORT_ST_RTV:
|
||||
- fc_rport_enter_ready(rport);
|
||||
- break;
|
||||
- case RPORT_ST_NONE:
|
||||
- case RPORT_ST_READY:
|
||||
- case RPORT_ST_INIT:
|
||||
- break;
|
||||
- }
|
||||
- }
|
||||
+ switch (rdata->rp_state) {
|
||||
+ case RPORT_ST_PLOGI:
|
||||
+ case RPORT_ST_PRLI:
|
||||
+ case RPORT_ST_LOGO:
|
||||
+ rdata->event = RPORT_EV_FAILED;
|
||||
+ queue_work(rport_event_queue,
|
||||
+ &rdata->event_work);
|
||||
+ break;
|
||||
+ case RPORT_ST_RTV:
|
||||
+ fc_rport_enter_ready(rport);
|
||||
+ break;
|
||||
+ case RPORT_ST_NONE:
|
||||
+ case RPORT_ST_READY:
|
||||
+ case RPORT_ST_INIT:
|
||||
+ break;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * fc_rport_error_retry - Error handler when retries are desired
|
||||
+ * @rport: The fc_rport object
|
||||
+ * @fp: The frame pointer
|
||||
+ *
|
||||
+ * If the error was an exchange timeout retry immediately,
|
||||
+ * otherwise wait for E_D_TOV.
|
||||
+ *
|
||||
+ * Locking Note: The rport lock is expected to be held before
|
||||
+ * calling this routine
|
||||
+ */
|
||||
+static void fc_rport_error_retry(struct fc_rport *rport, struct fc_frame *fp)
|
||||
+{
|
||||
+ struct fc_rport_libfc_priv *rdata = rport->dd_data;
|
||||
+ unsigned long delay = FC_DEF_E_D_TOV;
|
||||
+
|
||||
+ /* make sure this isn't an FC_EX_CLOSED error, never retry those */
|
||||
+ if (PTR_ERR(fp) == -FC_EX_CLOSED)
|
||||
+ return fc_rport_error(rport, fp);
|
||||
+
|
||||
+ if (rdata->retries < rdata->local_port->max_retry_count) {
|
||||
+ FC_DEBUG_RPORT("Error %ld in state %s, retrying\n",
|
||||
+ PTR_ERR(fp), fc_rport_state(rport));
|
||||
+ rdata->retries++;
|
||||
+ /* no additional delay on exchange timeouts */
|
||||
+ if (PTR_ERR(fp) == -FC_EX_TIMEOUT)
|
||||
+ delay = 0;
|
||||
+ get_device(&rport->dev);
|
||||
+ schedule_delayed_work(&rdata->retry_work, delay);
|
||||
+ return;
|
||||
}
|
||||
+
|
||||
+ return fc_rport_error(rport, fp);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -490,7 +507,7 @@ static void fc_rport_plogi_resp(struct f
|
||||
}
|
||||
|
||||
if (IS_ERR(fp)) {
|
||||
- fc_rport_error(rport, fp);
|
||||
+ fc_rport_error_retry(rport, fp);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -522,7 +539,7 @@ static void fc_rport_plogi_resp(struct f
|
||||
else
|
||||
fc_rport_enter_prli(rport);
|
||||
} else
|
||||
- fc_rport_error(rport, fp);
|
||||
+ fc_rport_error_retry(rport, fp);
|
||||
|
||||
out:
|
||||
fc_frame_free(fp);
|
||||
@@ -552,14 +569,14 @@ static void fc_rport_enter_plogi(struct
|
||||
rport->maxframe_size = FC_MIN_MAX_PAYLOAD;
|
||||
fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi));
|
||||
if (!fp) {
|
||||
- fc_rport_error(rport, fp);
|
||||
+ fc_rport_error_retry(rport, fp);
|
||||
return;
|
||||
}
|
||||
rdata->e_d_tov = lport->e_d_tov;
|
||||
|
||||
if (!lport->tt.elsct_send(lport, rport, fp, ELS_PLOGI,
|
||||
fc_rport_plogi_resp, rport, lport->e_d_tov))
|
||||
- fc_rport_error(rport, fp);
|
||||
+ fc_rport_error_retry(rport, fp);
|
||||
else
|
||||
get_device(&rport->dev);
|
||||
}
|
||||
@@ -599,7 +616,7 @@ static void fc_rport_prli_resp(struct fc
|
||||
}
|
||||
|
||||
if (IS_ERR(fp)) {
|
||||
- fc_rport_error(rport, fp);
|
||||
+ fc_rport_error_retry(rport, fp);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -657,7 +674,7 @@ static void fc_rport_logo_resp(struct fc
|
||||
rport->port_id);
|
||||
|
||||
if (IS_ERR(fp)) {
|
||||
- fc_rport_error(rport, fp);
|
||||
+ fc_rport_error_retry(rport, fp);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -707,13 +724,13 @@ static void fc_rport_enter_prli(struct f
|
||||
|
||||
fp = fc_frame_alloc(lport, sizeof(*pp));
|
||||
if (!fp) {
|
||||
- fc_rport_error(rport, fp);
|
||||
+ fc_rport_error_retry(rport, fp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!lport->tt.elsct_send(lport, rport, fp, ELS_PRLI,
|
||||
fc_rport_prli_resp, rport, lport->e_d_tov))
|
||||
- fc_rport_error(rport, fp);
|
||||
+ fc_rport_error_retry(rport, fp);
|
||||
else
|
||||
get_device(&rport->dev);
|
||||
}
|
||||
@@ -804,13 +821,13 @@ static void fc_rport_enter_rtv(struct fc
|
||||
|
||||
fp = fc_frame_alloc(lport, sizeof(struct fc_els_rtv));
|
||||
if (!fp) {
|
||||
- fc_rport_error(rport, fp);
|
||||
+ fc_rport_error_retry(rport, fp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!lport->tt.elsct_send(lport, rport, fp, ELS_RTV,
|
||||
fc_rport_rtv_resp, rport, lport->e_d_tov))
|
||||
- fc_rport_error(rport, fp);
|
||||
+ fc_rport_error_retry(rport, fp);
|
||||
else
|
||||
get_device(&rport->dev);
|
||||
}
|
||||
@@ -835,13 +852,13 @@ static void fc_rport_enter_logo(struct f
|
||||
|
||||
fp = fc_frame_alloc(lport, sizeof(struct fc_els_logo));
|
||||
if (!fp) {
|
||||
- fc_rport_error(rport, fp);
|
||||
+ fc_rport_error_retry(rport, fp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!lport->tt.elsct_send(lport, rport, fp, ELS_LOGO,
|
||||
fc_rport_logo_resp, rport, lport->e_d_tov))
|
||||
- fc_rport_error(rport, fp);
|
||||
+ fc_rport_error_retry(rport, fp);
|
||||
else
|
||||
get_device(&rport->dev);
|
||||
}
|
||||
--- a/include/scsi/fc/fc_fs.h
|
||||
+++ b/include/scsi/fc/fc_fs.h
|
||||
@@ -337,4 +337,9 @@ enum fc_pf_rjt_reason {
|
||||
FC_RJT_VENDOR = 0xff, /* vendor specific reject */
|
||||
};
|
||||
|
||||
+/* default timeout values */
|
||||
+
|
||||
+#define FC_DEF_E_D_TOV 2000UL
|
||||
+#define FC_DEF_R_A_TOV 10000UL
|
||||
+
|
||||
#endif /* _FC_FS_H_ */
|
||||
@@ -0,0 +1,54 @@
|
||||
From: Danny Kukawka <dkukawka@suse.de>
|
||||
Subject: b43legacy: fix led naming
|
||||
|
||||
Fixed led device naming for the b43legacy driver. Due to the
|
||||
documentation of the led subsystem/class the naming should be
|
||||
"devicename:colour:function" while not applying sections
|
||||
should be left blank.
|
||||
|
||||
This should lead to e.g. "b43legacy-%s::rx" instead of
|
||||
"b43legacy-%s:rx".
|
||||
|
||||
Signed-off-by: Danny Kukawka <dkukawka@suse.de>
|
||||
--
|
||||
leds.c | 8 ++++----
|
||||
1 file changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/wireless/b43legacy/leds.c b/drivers/net/wireless/b43legacy/leds.c
|
||||
index cacb786..cb4511f 100644
|
||||
--- a/drivers/net/wireless/b43legacy/leds.c
|
||||
+++ b/drivers/net/wireless/b43legacy/leds.c
|
||||
@@ -146,12 +146,12 @@ static void b43legacy_map_led(struct b43legacy_wldev *dev,
|
||||
case B43legacy_LED_TRANSFER:
|
||||
case B43legacy_LED_APTRANSFER:
|
||||
snprintf(name, sizeof(name),
|
||||
- "b43legacy-%s:tx", wiphy_name(hw->wiphy));
|
||||
+ "b43legacy-%s::tx", wiphy_name(hw->wiphy));
|
||||
b43legacy_register_led(dev, &dev->led_tx, name,
|
||||
ieee80211_get_tx_led_name(hw),
|
||||
led_index, activelow);
|
||||
snprintf(name, sizeof(name),
|
||||
- "b43legacy-%s:rx", wiphy_name(hw->wiphy));
|
||||
+ "b43legacy-%s::rx", wiphy_name(hw->wiphy));
|
||||
b43legacy_register_led(dev, &dev->led_rx, name,
|
||||
ieee80211_get_rx_led_name(hw),
|
||||
led_index, activelow);
|
||||
@@ -161,7 +161,7 @@ static void b43legacy_map_led(struct b43legacy_wldev *dev,
|
||||
case B43legacy_LED_RADIO_B:
|
||||
case B43legacy_LED_MODE_BG:
|
||||
snprintf(name, sizeof(name),
|
||||
- "b43legacy-%s:radio", wiphy_name(hw->wiphy));
|
||||
+ "b43legacy-%s::radio", wiphy_name(hw->wiphy));
|
||||
b43legacy_register_led(dev, &dev->led_radio, name,
|
||||
b43legacy_rfkill_led_name(dev),
|
||||
led_index, activelow);
|
||||
@@ -172,7 +172,7 @@ static void b43legacy_map_led(struct b43legacy_wldev *dev,
|
||||
case B43legacy_LED_WEIRD:
|
||||
case B43legacy_LED_ASSOC:
|
||||
snprintf(name, sizeof(name),
|
||||
- "b43legacy-%s:assoc", wiphy_name(hw->wiphy));
|
||||
+ "b43legacy-%s::assoc", wiphy_name(hw->wiphy));
|
||||
b43legacy_register_led(dev, &dev->led_assoc, name,
|
||||
ieee80211_get_assoc_led_name(hw),
|
||||
led_index, activelow);
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
From: Jan Kara <jack@suse.cz>
|
||||
Subject: [PATCH] ext2: Do not update mtime of a move directory when parent has not changed
|
||||
References: bnc#493392
|
||||
Patch-mainline: 2.6.30
|
||||
|
||||
If the parent of the moved directory has not changed, there's no real
|
||||
reason to change mtime. Specs doesn't seem to say anything about this
|
||||
particular case and e.g. ext3 does not change mtime in this case.
|
||||
So we become a tiny bit more consistent.
|
||||
|
||||
Spotted by ronny.pretzsch@dfs.de, initial fix by Jörn Engel <joern@logfs.org>.
|
||||
|
||||
Signed-off-by: Jan Kara <jack@suse.cz>
|
||||
---
|
||||
fs/ext2/namei.c | 5 ++++-
|
||||
1 file changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/fs/ext2/namei.c
|
||||
+++ b/fs/ext2/namei.c
|
||||
@@ -355,7 +355,10 @@ static int ext2_rename (struct inode * o
|
||||
inode_dec_link_count(old_inode);
|
||||
|
||||
if (dir_de) {
|
||||
- ext2_set_link(old_inode, dir_de, dir_page, new_dir);
|
||||
+ /* Set link only if parent has changed and thus avoid setting
|
||||
+ * of mtime of the moved directory on a pure rename. */
|
||||
+ if (old_dir != new_dir)
|
||||
+ ext2_set_link(old_inode, dir_de, dir_page, new_dir);
|
||||
inode_dec_link_count(old_dir);
|
||||
}
|
||||
return 0;
|
||||
172
src/patches/suse-2.6.27.25/patches.fixes/ext3_false_EIO_fix.diff
Normal file
172
src/patches/suse-2.6.27.25/patches.fixes/ext3_false_EIO_fix.diff
Normal file
@@ -0,0 +1,172 @@
|
||||
From: Jan Kara <jack@suse.cz>
|
||||
Subject: [PATCH] ext3: Avoid false EIO errors
|
||||
References: bnc#479730
|
||||
|
||||
Sometimes block_write_begin() can map buffers in a page but later we fail to
|
||||
copy data into those buffers (because the source page has been paged out in the
|
||||
mean time). We then end up with !uptodate mapped buffers. To add a bit more to
|
||||
the confusion, block_write_end() does not commit any data (and thus does not
|
||||
any mark buffers as uptodate) if we didn't succeed with copying all the data.
|
||||
|
||||
Commit f4fc66a894546bdc88a775d0e83ad20a65210bcb (ext3: convert to new aops)
|
||||
missed these cases and thus we were inserting non-uptodate buffers to
|
||||
transaction's list which confuses JBD code and it reports IO errors, aborts
|
||||
a transaction and generally makes users afraid about their data ;-P.
|
||||
|
||||
This patch fixes the problem by reorganizing ext3_..._write_end() code to
|
||||
first call block_write_end() to mark buffers with valid data uptodate and
|
||||
after that we file only uptodate buffers to transaction's lists. Also
|
||||
fix a problem where we could leave blocks allocated beyond i_size (i_disksize
|
||||
in fact).
|
||||
|
||||
Signed-off-by: Jan Kara <jack@suse.cz>
|
||||
|
||||
---
|
||||
fs/ext3/inode.c | 99 +++++++++++++++++++++++---------------------------------
|
||||
1 file changed, 42 insertions(+), 57 deletions(-)
|
||||
|
||||
--- a/fs/ext3/inode.c
|
||||
+++ b/fs/ext3/inode.c
|
||||
@@ -1195,6 +1195,18 @@ int ext3_journal_dirty_data(handle_t *ha
|
||||
return err;
|
||||
}
|
||||
|
||||
+/* For ordered writepage and write_end functions */
|
||||
+static int journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh)
|
||||
+{
|
||||
+ /*
|
||||
+ * Write could have mapped the buffer but it didn't copy the data in
|
||||
+ * yet. So avoid filing such buffer into a transaction.
|
||||
+ */
|
||||
+ if (buffer_mapped(bh) && buffer_uptodate(bh))
|
||||
+ return ext3_journal_dirty_data(handle, bh);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
/* For write_end() in data=journal mode */
|
||||
static int write_end_fn(handle_t *handle, struct buffer_head *bh)
|
||||
{
|
||||
@@ -1205,26 +1217,29 @@ static int write_end_fn(handle_t *handle
|
||||
}
|
||||
|
||||
/*
|
||||
- * Generic write_end handler for ordered and writeback ext3 journal modes.
|
||||
- * We can't use generic_write_end, because that unlocks the page and we need to
|
||||
- * unlock the page after ext3_journal_stop, but ext3_journal_stop must run
|
||||
- * after block_write_end.
|
||||
+ * This is nasty and subtle: ext3_write_begin() could have allocated blocks
|
||||
+ * for the whole page but later we failed to copy the data in. So the disk
|
||||
+ * size we really have allocated is pos + len (block_write_end() has zeroed
|
||||
+ * the freshly allocated buffers so we aren't going to write garbage). But we
|
||||
+ * want to keep i_size at the place where data copying finished so that we
|
||||
+ * don't confuse readers. The worst what can happen is that we expose a page
|
||||
+ * of zeros at the end of file after a crash...
|
||||
*/
|
||||
-static int ext3_generic_write_end(struct file *file,
|
||||
- struct address_space *mapping,
|
||||
- loff_t pos, unsigned len, unsigned copied,
|
||||
- struct page *page, void *fsdata)
|
||||
+static void update_file_sizes(struct inode *inode, loff_t pos, unsigned len,
|
||||
+ unsigned copied)
|
||||
{
|
||||
- struct inode *inode = file->f_mapping->host;
|
||||
+ int mark_dirty = 0;
|
||||
|
||||
- copied = block_write_end(file, mapping, pos, len, copied, page, fsdata);
|
||||
-
|
||||
- if (pos+copied > inode->i_size) {
|
||||
- i_size_write(inode, pos+copied);
|
||||
- mark_inode_dirty(inode);
|
||||
+ if (pos + len > EXT3_I(inode)->i_disksize) {
|
||||
+ mark_dirty = 1;
|
||||
+ EXT3_I(inode)->i_disksize = pos + len;
|
||||
}
|
||||
-
|
||||
- return copied;
|
||||
+ if (pos + copied > inode->i_size) {
|
||||
+ i_size_write(inode, pos + copied);
|
||||
+ mark_dirty = 1;
|
||||
+ }
|
||||
+ if (mark_dirty)
|
||||
+ mark_inode_dirty(inode);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1244,29 +1259,17 @@ static int ext3_ordered_write_end(struct
|
||||
unsigned from, to;
|
||||
int ret = 0, ret2;
|
||||
|
||||
+ copied = block_write_end(file, mapping, pos, len, copied, page, fsdata);
|
||||
+
|
||||
+ /* See comment at update_file_sizes() for why we check buffers upto
|
||||
+ * from + len */
|
||||
from = pos & (PAGE_CACHE_SIZE - 1);
|
||||
to = from + len;
|
||||
-
|
||||
ret = walk_page_buffers(handle, page_buffers(page),
|
||||
- from, to, NULL, ext3_journal_dirty_data);
|
||||
+ from, to, NULL, journal_dirty_data_fn);
|
||||
|
||||
- if (ret == 0) {
|
||||
- /*
|
||||
- * generic_write_end() will run mark_inode_dirty() if i_size
|
||||
- * changes. So let's piggyback the i_disksize mark_inode_dirty
|
||||
- * into that.
|
||||
- */
|
||||
- loff_t new_i_size;
|
||||
-
|
||||
- new_i_size = pos + copied;
|
||||
- if (new_i_size > EXT3_I(inode)->i_disksize)
|
||||
- EXT3_I(inode)->i_disksize = new_i_size;
|
||||
- ret2 = ext3_generic_write_end(file, mapping, pos, len, copied,
|
||||
- page, fsdata);
|
||||
- copied = ret2;
|
||||
- if (ret2 < 0)
|
||||
- ret = ret2;
|
||||
- }
|
||||
+ if (ret == 0)
|
||||
+ update_file_sizes(inode, pos, len, copied);
|
||||
ret2 = ext3_journal_stop(handle);
|
||||
if (!ret)
|
||||
ret = ret2;
|
||||
@@ -1283,22 +1286,11 @@ static int ext3_writeback_write_end(stru
|
||||
{
|
||||
handle_t *handle = ext3_journal_current_handle();
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
- int ret = 0, ret2;
|
||||
- loff_t new_i_size;
|
||||
+ int ret;
|
||||
|
||||
- new_i_size = pos + copied;
|
||||
- if (new_i_size > EXT3_I(inode)->i_disksize)
|
||||
- EXT3_I(inode)->i_disksize = new_i_size;
|
||||
-
|
||||
- ret2 = ext3_generic_write_end(file, mapping, pos, len, copied,
|
||||
- page, fsdata);
|
||||
- copied = ret2;
|
||||
- if (ret2 < 0)
|
||||
- ret = ret2;
|
||||
-
|
||||
- ret2 = ext3_journal_stop(handle);
|
||||
- if (!ret)
|
||||
- ret = ret2;
|
||||
+ copied = block_write_end(file, mapping, pos, len, copied, page, fsdata);
|
||||
+ update_file_sizes(inode, pos, len, copied);
|
||||
+ ret = ext3_journal_stop(handle);
|
||||
unlock_page(page);
|
||||
page_cache_release(page);
|
||||
|
||||
@@ -1412,13 +1404,6 @@ static int bput_one(handle_t *handle, st
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh)
|
||||
-{
|
||||
- if (buffer_mapped(bh))
|
||||
- return ext3_journal_dirty_data(handle, bh);
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
/*
|
||||
* Note that we always start a transaction even if we're not journalling
|
||||
* data. This is to preserve ordering: any hole instantiation within
|
||||
@@ -0,0 +1,54 @@
|
||||
From: Jan Blunck <jblunck@suse.de>
|
||||
Subject: ia64-kvm: fix sparse warnings
|
||||
|
||||
This patch fixes some sparse warning about dubious one-bit signed bitfield.
|
||||
|
||||
Signed-off-by: Jan Blunck <jblunck@suse.de>
|
||||
---
|
||||
arch/ia64/kvm/vti.h | 26 +++++++++++++-------------
|
||||
1 file changed, 13 insertions(+), 13 deletions(-)
|
||||
|
||||
Index: b/arch/ia64/kvm/vti.h
|
||||
===================================================================
|
||||
--- a/arch/ia64/kvm/vti.h
|
||||
+++ b/arch/ia64/kvm/vti.h
|
||||
@@ -83,13 +83,13 @@
|
||||
union vac {
|
||||
unsigned long value;
|
||||
struct {
|
||||
- int a_int:1;
|
||||
- int a_from_int_cr:1;
|
||||
- int a_to_int_cr:1;
|
||||
- int a_from_psr:1;
|
||||
- int a_from_cpuid:1;
|
||||
- int a_cover:1;
|
||||
- int a_bsw:1;
|
||||
+ unsigned int a_int:1;
|
||||
+ unsigned int a_from_int_cr:1;
|
||||
+ unsigned int a_to_int_cr:1;
|
||||
+ unsigned int a_from_psr:1;
|
||||
+ unsigned int a_from_cpuid:1;
|
||||
+ unsigned int a_cover:1;
|
||||
+ unsigned int a_bsw:1;
|
||||
long reserved:57;
|
||||
};
|
||||
};
|
||||
@@ -97,12 +97,12 @@ union vac {
|
||||
union vdc {
|
||||
unsigned long value;
|
||||
struct {
|
||||
- int d_vmsw:1;
|
||||
- int d_extint:1;
|
||||
- int d_ibr_dbr:1;
|
||||
- int d_pmc:1;
|
||||
- int d_to_pmd:1;
|
||||
- int d_itm:1;
|
||||
+ unsigned int d_vmsw:1;
|
||||
+ unsigned int d_extint:1;
|
||||
+ unsigned int d_ibr_dbr:1;
|
||||
+ unsigned int d_pmc:1;
|
||||
+ unsigned int d_to_pmd:1;
|
||||
+ unsigned int d_itm:1;
|
||||
long reserved:58;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
From: Russ Anderson <rja@sgi.com>
|
||||
Subject: Add partition id, coherence id, and region size to UV
|
||||
References: bnc#442455
|
||||
|
||||
Add partition id, coherence id, and region size to UV.
|
||||
|
||||
The SGI xp drivers (drivers/misc/sgi-xp) are used on both
|
||||
sn (Itanium) and uv (Tukwilla). Using the same names
|
||||
(sn_partition_id, sn_coherency_id, sn_region_size)
|
||||
simplifies the driver code.
|
||||
|
||||
|
||||
Signed-off-by: Russ Anderson <rja@sgi.com>
|
||||
Acked-by: Bernhard Walle <bwalle@suse.de>
|
||||
|
||||
---
|
||||
|
||||
arch/ia64/uv/kernel/setup.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
--- a/arch/ia64/uv/kernel/setup.c
|
||||
+++ b/arch/ia64/uv/kernel/setup.c
|
||||
@@ -19,6 +19,12 @@ EXPORT_PER_CPU_SYMBOL_GPL(__uv_hub_info)
|
||||
|
||||
#ifdef CONFIG_IA64_SGI_UV
|
||||
int sn_prom_type;
|
||||
+long sn_partition_id;
|
||||
+EXPORT_SYMBOL(sn_partition_id);
|
||||
+long sn_coherency_id;
|
||||
+EXPORT_SYMBOL_GPL(sn_coherency_id);
|
||||
+long sn_region_size;
|
||||
+EXPORT_SYMBOL(sn_region_size);
|
||||
#endif
|
||||
|
||||
struct redir_addr {
|
||||
@@ -0,0 +1,78 @@
|
||||
From: Bernhard Walle <bwalle@suse.de>
|
||||
Subject: Add UV watchlist support
|
||||
References: bnc#442455
|
||||
|
||||
Add UV watchlist support.
|
||||
|
||||
This is used by SGI xp drivers (drivers/misc/sgi-xp).
|
||||
|
||||
Signed-off-by: Russ Anderson <rja@sgi.com>
|
||||
|
||||
---
|
||||
|
||||
arch/ia64/include/asm/sn/sn_sal.h | 45 ++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 45 insertions(+)
|
||||
|
||||
Index: linux/arch/ia64/include/asm/sn/sn_sal.h
|
||||
===================================================================
|
||||
--- linux.orig/arch/ia64/include/asm/sn/sn_sal.h 2008-11-05 09:21:48.690243174 -0600
|
||||
+++ linux/arch/ia64/include/asm/sn/sn_sal.h 2008-11-05 09:22:01.847928152 -0600
|
||||
@@ -90,6 +90,8 @@
|
||||
#define SN_SAL_SET_CPU_NUMBER 0x02000068
|
||||
|
||||
#define SN_SAL_KERNEL_LAUNCH_EVENT 0x02000069
|
||||
+#define SN_SAL_WATCHLIST_ALLOC 0x02000070
|
||||
+#define SN_SAL_WATCHLIST_FREE 0x02000071
|
||||
|
||||
/*
|
||||
* Service-specific constants
|
||||
@@ -1183,6 +1185,49 @@ ia64_sn_kernel_launch_event(void)
|
||||
{
|
||||
struct ia64_sal_retval rv;
|
||||
SAL_CALL_NOLOCK(rv, SN_SAL_KERNEL_LAUNCH_EVENT, 0, 0, 0, 0, 0, 0, 0);
|
||||
+ return rv.status;
|
||||
+}
|
||||
+
|
||||
+union sn_watchlist_u {
|
||||
+ u64 val;
|
||||
+ struct {
|
||||
+ u64 blade : 16,
|
||||
+ size : 32,
|
||||
+ filler : 16;
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+static inline int
|
||||
+sn_mq_watchlist_alloc(int blade, void *mq, unsigned int mq_size,
|
||||
+ unsigned long *intr_mmr_offset)
|
||||
+{
|
||||
+ struct ia64_sal_retval rv;
|
||||
+ unsigned long addr;
|
||||
+ union sn_watchlist_u size_blade;
|
||||
+ int watchlist;
|
||||
+
|
||||
+ addr = (unsigned long)mq;
|
||||
+ size_blade.size = mq_size;
|
||||
+ size_blade.blade = blade;
|
||||
+
|
||||
+ /*
|
||||
+ * bios returns watchlist number or negative error number.
|
||||
+ */
|
||||
+ ia64_sal_oemcall_nolock(&rv, SN_SAL_WATCHLIST_ALLOC, addr,
|
||||
+ size_blade.val, (u64)intr_mmr_offset,
|
||||
+ (u64)&watchlist, 0, 0, 0);
|
||||
+ if (rv.status < 0)
|
||||
+ return rv.status;
|
||||
+
|
||||
+ return watchlist;
|
||||
+}
|
||||
+
|
||||
+static inline int
|
||||
+sn_mq_watchlist_free(int blade, int watchlist_num)
|
||||
+{
|
||||
+ struct ia64_sal_retval rv;
|
||||
+ ia64_sal_oemcall_nolock(&rv, SN_SAL_WATCHLIST_FREE, blade,
|
||||
+ watchlist_num, 0, 0, 0, 0, 0);
|
||||
return rv.status;
|
||||
}
|
||||
#endif /* _ASM_IA64_SN_SN_SAL_H */
|
||||
@@ -0,0 +1,57 @@
|
||||
From: Danny Kukawka <dkukawka@suse.de>
|
||||
Subject: iwlwifi: another led naming fix
|
||||
|
||||
Fixed led device naming for the iwlwifi (iwl-3945) driver. Due
|
||||
to the documentation of the led subsystem/class the naming should
|
||||
be "devicename:colour:function" while not applying sections
|
||||
should be left blank.
|
||||
|
||||
This should lead to e.g. "iwl-%s::RX" instead of "iwl-%s:RX".
|
||||
|
||||
Signed-off-by: Danny Kukawka <dkukawka@suse.de>
|
||||
Acked-by: Reinette Chatre <reinette.chatre@intel.com>
|
||||
--
|
||||
iwl-led.c | 8 ++++----
|
||||
1 file changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
|
||||
index 4c63890..09f9350 100644
|
||||
--- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c
|
||||
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
|
||||
@@ -317,7 +317,7 @@ int iwl3945_led_register(struct iwl3945_priv *priv)
|
||||
|
||||
trigger = ieee80211_get_radio_led_name(priv->hw);
|
||||
snprintf(priv->led[IWL_LED_TRG_RADIO].name,
|
||||
- sizeof(priv->led[IWL_LED_TRG_RADIO].name), "iwl-%s:radio",
|
||||
+ sizeof(priv->led[IWL_LED_TRG_RADIO].name), "iwl-%s::radio",
|
||||
wiphy_name(priv->hw->wiphy));
|
||||
|
||||
priv->led[IWL_LED_TRG_RADIO].led_on = iwl3945_led_on;
|
||||
@@ -333,7 +333,7 @@ int iwl3945_led_register(struct iwl3945_priv *priv)
|
||||
|
||||
trigger = ieee80211_get_assoc_led_name(priv->hw);
|
||||
snprintf(priv->led[IWL_LED_TRG_ASSOC].name,
|
||||
- sizeof(priv->led[IWL_LED_TRG_ASSOC].name), "iwl-%s:assoc",
|
||||
+ sizeof(priv->led[IWL_LED_TRG_ASSOC].name), "iwl-%s::assoc",
|
||||
wiphy_name(priv->hw->wiphy));
|
||||
|
||||
ret = iwl3945_led_register_led(priv,
|
||||
@@ -350,7 +350,7 @@ int iwl3945_led_register(struct iwl3945_priv *priv)
|
||||
|
||||
trigger = ieee80211_get_rx_led_name(priv->hw);
|
||||
snprintf(priv->led[IWL_LED_TRG_RX].name,
|
||||
- sizeof(priv->led[IWL_LED_TRG_RX].name), "iwl-%s:RX",
|
||||
+ sizeof(priv->led[IWL_LED_TRG_RX].name), "iwl-%s::RX",
|
||||
wiphy_name(priv->hw->wiphy));
|
||||
|
||||
ret = iwl3945_led_register_led(priv,
|
||||
@@ -366,7 +366,7 @@ int iwl3945_led_register(struct iwl3945_priv *priv)
|
||||
|
||||
trigger = ieee80211_get_tx_led_name(priv->hw);
|
||||
snprintf(priv->led[IWL_LED_TRG_TX].name,
|
||||
- sizeof(priv->led[IWL_LED_TRG_TX].name), "iwl-%s:TX",
|
||||
+ sizeof(priv->led[IWL_LED_TRG_TX].name), "iwl-%s::TX",
|
||||
wiphy_name(priv->hw->wiphy));
|
||||
|
||||
ret = iwl3945_led_register_led(priv,
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
From: Danny Kukawka <dkukawka@suse.de>
|
||||
Subject: iwlwifi: fix led naming
|
||||
|
||||
Fixed led device naming for the iwl driver. Due to the
|
||||
documentation of the led subsystem/class the naming should be
|
||||
"devicename:colour:function" while not applying sections
|
||||
should be left blank.
|
||||
|
||||
This should lead to e.g. "iwl-phy0::RX" instead of "iwl-phy0:RX".
|
||||
|
||||
Signed-off-by: Danny Kukawka <dkukawka@suse.de>
|
||||
Acked-by: Reinette Chatre <reinette.chatre@intel.com>
|
||||
--
|
||||
drivers/net/wireless/iwlwifi/iwl-led.c | 8 ++++----
|
||||
1 file changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/net/wireless/iwlwifi/iwl-led.c
|
||||
+++ b/drivers/net/wireless/iwlwifi/iwl-led.c
|
||||
@@ -353,7 +353,7 @@ int iwl_leds_register(struct iwl_priv *p
|
||||
|
||||
trigger = ieee80211_get_radio_led_name(priv->hw);
|
||||
snprintf(priv->led[IWL_LED_TRG_RADIO].name,
|
||||
- sizeof(priv->led[IWL_LED_TRG_RADIO].name), "iwl-%s:radio",
|
||||
+ sizeof(priv->led[IWL_LED_TRG_RADIO].name), "iwl-%s::radio",
|
||||
wiphy_name(priv->hw->wiphy));
|
||||
|
||||
priv->led[IWL_LED_TRG_RADIO].led_on = iwl4965_led_on_reg;
|
||||
@@ -367,7 +367,7 @@ int iwl_leds_register(struct iwl_priv *p
|
||||
|
||||
trigger = ieee80211_get_assoc_led_name(priv->hw);
|
||||
snprintf(priv->led[IWL_LED_TRG_ASSOC].name,
|
||||
- sizeof(priv->led[IWL_LED_TRG_ASSOC].name), "iwl-%s:assoc",
|
||||
+ sizeof(priv->led[IWL_LED_TRG_ASSOC].name), "iwl-%s::assoc",
|
||||
wiphy_name(priv->hw->wiphy));
|
||||
|
||||
ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_ASSOC],
|
||||
@@ -383,7 +383,7 @@ int iwl_leds_register(struct iwl_priv *p
|
||||
|
||||
trigger = ieee80211_get_rx_led_name(priv->hw);
|
||||
snprintf(priv->led[IWL_LED_TRG_RX].name,
|
||||
- sizeof(priv->led[IWL_LED_TRG_RX].name), "iwl-%s:RX",
|
||||
+ sizeof(priv->led[IWL_LED_TRG_RX].name), "iwl-%s::RX",
|
||||
wiphy_name(priv->hw->wiphy));
|
||||
|
||||
ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RX],
|
||||
@@ -398,7 +398,7 @@ int iwl_leds_register(struct iwl_priv *p
|
||||
|
||||
trigger = ieee80211_get_tx_led_name(priv->hw);
|
||||
snprintf(priv->led[IWL_LED_TRG_TX].name,
|
||||
- sizeof(priv->led[IWL_LED_TRG_TX].name), "iwl-%s:TX",
|
||||
+ sizeof(priv->led[IWL_LED_TRG_TX].name), "iwl-%s::TX",
|
||||
wiphy_name(priv->hw->wiphy));
|
||||
|
||||
ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_TX],
|
||||
60
src/patches/suse-2.6.27.25/patches.fixes/kdb-kdump.diff
Normal file
60
src/patches/suse-2.6.27.25/patches.fixes/kdb-kdump.diff
Normal file
@@ -0,0 +1,60 @@
|
||||
From: Jay Lan <jlan@sgi.com>
|
||||
Subject: Fix CONFIG_KDB_KDUMP on xSeries
|
||||
Patch-mainline: not yet
|
||||
References: bnc#436454
|
||||
|
||||
This patch fixes a problem that the capture kernel crashes with various
|
||||
backtraces after the machine has been crashed (both sysrq-trigger and panic()).
|
||||
Machines were that problem could reproduced at SUSE were molitor.suse.de and
|
||||
korner.suse.de.
|
||||
|
||||
KDB was turned off in that scenarios.
|
||||
|
||||
That patch succeeds in following scenarios:
|
||||
|
||||
a) kdb=0
|
||||
modprobe crasher call_panic
|
||||
|
||||
b) kdb=1/0
|
||||
echo c > /proc/sysrq-trigger
|
||||
|
||||
b) kdb=1
|
||||
ESC KDB
|
||||
kdb> kdump
|
||||
|
||||
But it fails in:
|
||||
|
||||
kdb=1
|
||||
modprobe crasher call_panic
|
||||
|
||||
That has to be investigated. But I think that's unrelated to that patch,
|
||||
and it's no regression.
|
||||
|
||||
|
||||
Signed-off-by: Jay Lan <jlan@sgi.com>
|
||||
Signed-off-by: Bernhard Walle <bwalle@suse.de>
|
||||
|
||||
---
|
||||
arch/x86/kdb/kdba_support.c | 4 +---
|
||||
1 file changed, 1 insertion(+), 3 deletions(-)
|
||||
|
||||
--- a/arch/x86/kdb/kdba_support.c
|
||||
+++ b/arch/x86/kdb/kdba_support.c
|
||||
@@ -35,8 +35,6 @@ void kdba_kdump_prepare(struct pt_regs *
|
||||
if (regs == NULL)
|
||||
regs = &r;
|
||||
|
||||
- machine_crash_shutdown_begin();
|
||||
-
|
||||
for (i = 1; i < NR_CPUS; ++i) {
|
||||
if (!cpu_online(i))
|
||||
continue;
|
||||
@@ -44,7 +42,7 @@ void kdba_kdump_prepare(struct pt_regs *
|
||||
KDB_STATE_SET_CPU(KEXEC, i);
|
||||
}
|
||||
|
||||
- machine_crash_shutdown_end(regs);
|
||||
+ machine_crash_shutdown(regs);
|
||||
}
|
||||
|
||||
extern void halt_current_cpu(struct pt_regs *);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user