Update kernel patches for 2.6.28

This commit is contained in:
John Johansen 2008-12-10 17:57:41 +00:00
parent 9d87470a60
commit 28ba83a313
63 changed files with 13390 additions and 0 deletions

View file

@ -0,0 +1,506 @@
security/apparmor/apparmor.h | 5 +++
security/apparmor/apparmorfs.c | 10 ++-----
security/apparmor/inline.h | 2 -
security/apparmor/list.c | 2 -
security/apparmor/lsm.c | 35 ++++++++++++++-------------
security/apparmor/main.c | 21 ++++++++--------
security/apparmor/match.c | 8 ++----
security/apparmor/match.h | 2 -
security/apparmor/module_interface.c | 44 +++++++++++++----------------------
security/apparmor/procattr.c | 5 +--
10 files changed, 61 insertions(+), 73 deletions(-)
--- a/security/apparmor/apparmor.h
+++ b/security/apparmor/apparmor.h
@@ -297,6 +297,9 @@ enum aa_lock_class {
aa_lock_task_release
};
+/* apparmor/profiles */
+extern struct seq_operations apparmorfs_profiles_op;
+
/* main.c */
extern int alloc_default_namespace(void);
extern void free_default_namespace(void);
@@ -334,7 +337,7 @@ extern int aa_change_profile(const char
extern struct aa_profile *__aa_replace_profile(struct task_struct *task,
struct aa_profile *profile);
extern struct aa_task_context *lock_task_and_profiles(struct task_struct *task,
- struct aa_profile *profile);
+ struct aa_profile *profile);
extern void unlock_task_and_profiles(struct task_struct *task,
struct aa_task_context *cxt,
struct aa_profile *profile);
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -13,7 +13,7 @@
#include <linux/vmalloc.h>
#include <linux/module.h>
#include <linux/seq_file.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/namei.h>
#include "apparmor.h"
@@ -65,9 +65,6 @@ out:
return data;
}
-/* apparmor/profiles */
-extern struct seq_operations apparmorfs_profiles_op;
-
static int aa_profiles_open(struct inode *inode, struct file *file)
{
return seq_open(file, &apparmorfs_profiles_op);
@@ -236,8 +233,7 @@ int create_apparmorfs(void)
return 0;
if (apparmor_dentry) {
- AA_ERROR("%s: AppArmor securityfs already exists\n",
- __FUNCTION__);
+ AA_ERROR("%s: AppArmor securityfs already exists\n", __func__);
return -EEXIST;
}
@@ -245,7 +241,7 @@ int create_apparmorfs(void)
if (IS_ERR(apparmor_dentry)) {
error = PTR_ERR(apparmor_dentry);
apparmor_dentry = NULL;
- goto error;
+ goto error;
}
error = aafs_create("profiles", 0440, &apparmorfs_profiles_fops);
if (error)
--- a/security/apparmor/inline.h
+++ b/security/apparmor/inline.h
@@ -213,7 +213,7 @@ static inline void lock_both_profiles(st
* gives us RCU reader safety.
*/
static inline void unlock_both_profiles(struct aa_profile *profile1,
- struct aa_profile *profile2)
+ struct aa_profile *profile2)
{
/* Unlock the two profiles. */
if (!profile1 || profile1 == profile2) {
--- a/security/apparmor/list.c
+++ b/security/apparmor/list.c
@@ -15,7 +15,7 @@
/* list of profile namespaces and lock */
LIST_HEAD(profile_ns_list);
-rwlock_t profile_ns_list_lock = RW_LOCK_UNLOCKED;
+DEFINE_RWLOCK(profile_ns_list_lock);
/**
* __aa_find_namespace - look up a profile namespace on the namespace list
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -24,7 +24,7 @@
#include "inline.h"
/* Flag indicating whether initialization completed */
-int apparmor_initialized = 0;
+int apparmor_initialized;
static int param_set_aabool(const char *val, struct kernel_param *kp);
static int param_get_aabool(char *buffer, struct kernel_param *kp);
@@ -43,22 +43,22 @@ static int param_get_aauint(char *buffer
* Value is also togglable per profile and referenced when global value is
* enforce.
*/
-int apparmor_complain = 0;
+int apparmor_complain;
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;
+int apparmor_debug;
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;
+int apparmor_audit;
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;
+int apparmor_logsyscall;
module_param_named(logsyscall, apparmor_logsyscall, aabool, S_IRUSR | S_IWUSR);
MODULE_PARM_DESC(apparmor_logsyscall, "Toggle AppArmor logsyscall mode");
@@ -117,7 +117,6 @@ static int param_get_aauint(char *buffer
/* 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) {
@@ -134,8 +133,7 @@ static int param_set_aa_enabled(const ch
if (!val)
return -EINVAL;
- l = simple_strtoul(val, &endp, 0);
- if (endp == val || l != 0)
+ if (strict_strtoul(val, 0, &l) || l != 0)
return -EINVAL;
apparmor_enabled = 0;
@@ -238,7 +236,7 @@ static int apparmor_sysctl(struct ctl_ta
mask |= MAY_WRITE;
error = -ENOMEM;
- buffer = (char*)__get_free_page(GFP_KERNEL);
+ buffer = (char *)__get_free_page(GFP_KERNEL);
if (!buffer)
goto out;
name = sysctl_pathname(table, buffer, PAGE_SIZE);
@@ -271,7 +269,7 @@ static int apparmor_bprm_secureexec(stru
if (!ret && (unsigned long)bprm->security & AA_SECURE_EXEC_NEEDED) {
AA_DEBUG("%s: secureexec required for %s\n",
- __FUNCTION__, bprm->filename);
+ __func__, bprm->filename);
ret = 1;
}
@@ -522,7 +520,7 @@ static int apparmor_inode_removexattr(st
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;
+ struct aa_profile *file_profile = file->f_security;
int error = 0;
if (!file_profile)
@@ -559,7 +557,7 @@ static int apparmor_file_permission(stru
aa_mask_permissions(mask));
}
-static inline int apparmor_file_lock (struct file *file, unsigned int cmd)
+static inline int apparmor_file_lock(struct file *file, unsigned int cmd)
{
int mask = AA_MAY_LOCK;
if (cmd == F_WRLCK)
@@ -580,7 +578,7 @@ static int apparmor_file_alloc_security(
static void apparmor_file_free_security(struct file *file)
{
- struct aa_profile *file_profile = (struct aa_profile*)file->f_security;
+ struct aa_profile *file_profile = file->f_security;
aa_put_profile(file_profile);
}
@@ -967,17 +965,20 @@ static int __init apparmor_init(void)
return 0;
}
- if ((error = create_apparmorfs())) {
+ error = create_apparmorfs();
+ if (error) {
AA_ERROR("Unable to activate AppArmor filesystem\n");
goto createfs_out;
}
- if ((error = alloc_default_namespace())){
+ error = alloc_default_namespace();
+ if (error) {
AA_ERROR("Unable to allocate default profile namespace\n");
goto alloc_out;
}
- if ((error = register_security(&apparmor_ops))) {
+ error = register_security(&apparmor_ops);
+ if (error) {
AA_ERROR("Unable to register AppArmor\n");
goto register_security_out;
}
@@ -995,7 +996,7 @@ register_security_out:
free_default_namespace();
alloc_out:
- destroy_apparmorfs();
+ destroy_apparmorfs();
createfs_out:
return error;
--- a/security/apparmor/main.c
+++ b/security/apparmor/main.c
@@ -416,7 +416,7 @@ static int aa_link_denied(struct aa_prof
*
* If the link has 'x', an exact match of all the execute flags
* must match.
- */
+ */
denied_mask |= ~l_mode & link_mask;
t_mode = aa_match(profile->file_rules, target, NULL);
@@ -445,8 +445,10 @@ static int aa_link_denied(struct aa_prof
(x & AA_USER_EXEC_TYPE) != (t_x & AA_USER_EXEC_TYPE))
denied_mask = AA_USER_EXEC | (l_x & AA_USER_EXEC_TYPE);
if ((l_mode & AA_OTHER_EXEC) &&
- (x & AA_OTHER_EXEC_TYPE) != (t_x & AA_OTHER_EXEC_TYPE))
- denied_mask = AA_OTHER_EXEC | (l_x & AA_OTHER_EXEC_TYPE);
+ (x & AA_OTHER_EXEC_TYPE) != (t_x & AA_OTHER_EXEC_TYPE)) {
+ denied_mask =
+ AA_OTHER_EXEC | (l_x & AA_OTHER_EXEC_TYPE);
+ }
}
return denied_mask;
@@ -866,7 +868,7 @@ int aa_revalidate_sk(struct sock *sk, ch
/* 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");
+ printk(KERN_WARNING "AppArmor Debug: Hook being called from interrupt context\n");
dump_stack();
return 0;
}
@@ -1019,7 +1021,7 @@ repeat:
}
static struct aa_profile *
-aa_register_find(struct aa_profile *profile, const char* ns_name,
+aa_register_find(struct aa_profile *profile, const char *ns_name,
const char *name, int mandatory, int complain,
struct aa_audit *sa)
{
@@ -1053,7 +1055,7 @@ aa_register_find(struct aa_profile *prof
if (new_profile) {
AA_DEBUG("%s: setting profile %s\n",
- __FUNCTION__, new_profile->name);
+ __func__, new_profile->name);
} else if (mandatory && profile) {
sa->info = "mandatory profile missing";
sa->denied_mask = sa->request_mask; /* shifted MAY_EXEC */
@@ -1072,8 +1074,7 @@ aa_register_find(struct aa_profile *prof
* is unconfined, pix, nix.
*/
AA_DEBUG("%s: No profile found for exec image '%s'\n",
- __FUNCTION__,
- name);
+ __func__, name);
}
if (ns_ref)
aa_put_namespace(ns);
@@ -1158,7 +1159,7 @@ int aa_register(struct linux_binprm *bpr
int exec_mode, complain = 0, shift;
struct aa_audit sa;
- AA_DEBUG("%s\n", __FUNCTION__);
+ AA_DEBUG("%s\n", __func__);
profile = aa_get_profile(current);
@@ -1266,7 +1267,7 @@ repeat:
unsigned long bprm_flags;
bprm_flags = AA_SECURE_EXEC_NEEDED;
- bprm->security = (void*)
+ bprm->security = (void *)
((unsigned long)bprm->security | bprm_flags);
}
--- a/security/apparmor/match.c
+++ b/security/apparmor/match.c
@@ -82,7 +82,7 @@ int unpack_dfa(struct aa_dfa *dfa, void
if (!table)
goto fail;
- switch(table->td_id) {
+ switch (table->td_id) {
case YYTD_ID_ACCEPT:
case YYTD_ID_ACCEPT2:
case YYTD_ID_BASE:
@@ -115,10 +115,8 @@ int unpack_dfa(struct aa_dfa *dfa, void
fail:
for (i = 0; i < ARRAY_SIZE(dfa->tables); i++) {
- if (dfa->tables[i]) {
- kfree(dfa->tables[i]);
- dfa->tables[i] = NULL;
- }
+ kfree(dfa->tables[i]);
+ dfa->tables[i] = NULL;
}
return error;
}
--- a/security/apparmor/match.h
+++ b/security/apparmor/match.h
@@ -61,7 +61,7 @@ struct table_header {
#define CHECK_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_CHK - 1]->td_data))
#define EQUIV_TABLE(DFA) ((u8 *)((DFA)->tables[YYTD_ID_EC - 1]->td_data))
#define ACCEPT_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT - 1]->td_data))
-#define ACCEPT_TABLE2(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT2 -1]->td_data))
+#define ACCEPT_TABLE2(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT2 - 1]->td_data))
struct aa_dfa {
struct table_header *tables[YYTD_ID_NXT];
--- a/security/apparmor/module_interface.c
+++ b/security/apparmor/module_interface.c
@@ -219,7 +219,7 @@ static size_t aa_is_blob(struct aa_ext *
size = le32_to_cpu(get_unaligned((u32 *)e->pos));
e->pos += sizeof(u32);
if (aa_inbounds(e, (size_t) size)) {
- * blob = e->pos;
+ *blob = e->pos;
e->pos += size;
return size;
}
@@ -237,8 +237,8 @@ static int aa_is_dynstring(struct aa_ext
*string = NULL;
if (aa_is_nameX(e, AA_STRING, name) &&
(size = aa_is_u16_chunk(e, &src_str))) {
- char *str;
- if (!(str = kmalloc(size, GFP_KERNEL)))
+ char *str = kmalloc(size, GFP_KERNEL);
+ if (!str)
goto fail;
memcpy(str, src_str, size);
*string = str;
@@ -495,9 +495,8 @@ static int aa_verify_header(struct aa_ex
}
/* read the namespace if present */
- if (!aa_is_dynstring(e, &e->ns_name, "namespace")) {
+ if (!aa_is_dynstring(e, &e->ns_name, "namespace"))
e->ns_name = NULL;
- }
return 0;
}
@@ -592,11 +591,8 @@ static inline void task_replace(struct t
{
struct aa_task_context *cxt = aa_task_context(task);
- AA_DEBUG("%s: replacing profile for task %d "
- "profile=%s (%p)\n",
- __FUNCTION__,
- cxt->task->pid,
- cxt->profile->name, cxt->profile);
+ AA_DEBUG("%s: replacing profile for task %d profile=%s (%p)\n",
+ __func__, cxt->task->pid, cxt->profile->name, cxt->profile);
aa_change_task_context(task, new_cxt, new_profile, cxt->cookie,
cxt->previous_profile);
@@ -797,9 +793,7 @@ noent:
*/
void free_aa_namespace_kref(struct kref *kref)
{
- struct aa_namespace *ns=container_of(kref, struct aa_namespace, count);
-
- free_aa_namespace(ns);
+ free_aa_namespace(container_of(kref, struct aa_namespace, count));
}
/**
@@ -812,7 +806,7 @@ struct aa_namespace *alloc_aa_namespace(
struct aa_namespace *ns;
ns = kzalloc(sizeof(*ns), GFP_KERNEL);
- AA_DEBUG("%s(%p)\n", __FUNCTION__, ns);
+ AA_DEBUG("%s(%p)\n", __func__, ns);
if (ns) {
ns->name = name;
INIT_LIST_HEAD(&ns->list);
@@ -854,7 +848,7 @@ struct aa_namespace *alloc_aa_namespace(
*/
void free_aa_namespace(struct aa_namespace *ns)
{
- AA_DEBUG("%s(%p)\n", __FUNCTION__, ns);
+ AA_DEBUG("%s(%p)\n", __func__, ns);
if (!ns)
return;
@@ -863,15 +857,12 @@ void free_aa_namespace(struct aa_namespa
if (!list_empty(&ns->profiles)) {
AA_ERROR("%s: internal error, "
"namespace '%s' still contains profiles\n",
- __FUNCTION__,
- ns->name);
+ __func__, ns->name);
BUG();
}
if (!list_empty(&ns->list)) {
- AA_ERROR("%s: internal error, "
- "namespace '%s' still on list\n",
- __FUNCTION__,
- ns->name);
+ AA_ERROR("%s: internal error, namespace '%s' still on list\n",
+ __func__, ns->name);
BUG();
}
/* null_complain_profile doesn't contribute to ns ref counting */
@@ -887,7 +878,7 @@ void free_aa_namespace(struct aa_namespa
*/
void free_aa_profile_kref(struct kref *kref)
{
- struct aa_profile *p=container_of(kref, struct aa_profile, count);
+ struct aa_profile *p = container_of(kref, struct aa_profile, count);
free_aa_profile(p);
}
@@ -901,7 +892,7 @@ struct aa_profile *alloc_aa_profile(void
struct aa_profile *profile;
profile = kzalloc(sizeof(*profile), GFP_KERNEL);
- AA_DEBUG("%s(%p)\n", __FUNCTION__, profile);
+ AA_DEBUG("%s(%p)\n", __func__, profile);
if (profile) {
INIT_LIST_HEAD(&profile->list);
kref_init(&profile->count);
@@ -923,7 +914,7 @@ struct aa_profile *alloc_aa_profile(void
*/
void free_aa_profile(struct aa_profile *profile)
{
- AA_DEBUG("%s(%p)\n", __FUNCTION__, profile);
+ AA_DEBUG("%s(%p)\n", __func__, profile);
if (!profile)
return;
@@ -932,8 +923,7 @@ void free_aa_profile(struct aa_profile *
if (!list_empty(&profile->list)) {
AA_ERROR("%s: internal error, "
"profile '%s' still on global list\n",
- __FUNCTION__,
- profile->name);
+ __func__, profile->name);
BUG();
}
aa_put_namespace(profile->ns);
@@ -941,7 +931,7 @@ void free_aa_profile(struct aa_profile *
aa_match_free(profile->file_rules);
if (profile->name) {
- AA_DEBUG("%s: %s\n", __FUNCTION__, profile->name);
+ AA_DEBUG("%s: %s\n", __func__, profile->name);
kfree(profile->name);
}
--- a/security/apparmor/procattr.c
+++ b/security/apparmor/procattr.c
@@ -88,7 +88,7 @@ int aa_setprocattr_changehat(char *args)
}
AA_DEBUG("%s: Magic 0x%llx Hat '%s'\n",
- __FUNCTION__, cookie, hat ? hat : NULL);
+ __func__, cookie, hat ? hat : NULL);
return aa_change_hat(hat, cookie);
}
@@ -121,8 +121,7 @@ int aa_setprocattr_setprofile(struct tas
sa.gfp_mask = GFP_KERNEL;
sa.task = task->pid;
- AA_DEBUG("%s: current %d\n",
- __FUNCTION__, current->pid);
+ AA_DEBUG("%s: current %d\n", __func__, current->pid);
name = args;
if (args[0] != '/') {

View file

@ -0,0 +1,260 @@
security/apparmor/Kconfig | 1 +
security/apparmor/apparmor.h | 7 +++----
security/apparmor/inline.h | 4 ++--
security/apparmor/list.c | 2 ++
security/apparmor/lsm.c | 22 ++++++----------------
security/apparmor/main.c | 5 +++--
security/apparmor/match.c | 5 +++--
security/apparmor/module_interface.c | 13 ++++++-------
8 files changed, 26 insertions(+), 33 deletions(-)
--- a/security/apparmor/Kconfig
+++ b/security/apparmor/Kconfig
@@ -3,6 +3,7 @@ config SECURITY_APPARMOR
depends on SECURITY
depends on SECURITY_NETWORK
select AUDIT
+ default n
help
This enables the AppArmor security module.
Required userspace tools (if they are not included in your
--- a/security/apparmor/apparmor.h
+++ b/security/apparmor/apparmor.h
@@ -214,9 +214,9 @@ struct aa_profile {
char **exec_table;
struct aa_dfa *file_rules;
struct {
- int hat;
- int complain;
- int audit;
+ u32 hat;
+ u32 complain;
+ u32 audit;
} flags;
int isstale;
@@ -310,7 +310,6 @@ void aa_audit_status(struct aa_profile *
int aa_audit_reject(struct aa_profile *profile, struct aa_audit *sa);
extern int aa_audit_syscallreject(struct aa_profile *profile, gfp_t gfp,
const char *);
-extern int aa_audit(struct aa_profile *profile, struct aa_audit *);
extern int aa_attr(struct aa_profile *profile, struct dentry *dentry,
struct vfsmount *mnt, struct iattr *iattr);
--- a/security/apparmor/inline.h
+++ b/security/apparmor/inline.h
@@ -21,7 +21,7 @@ static inline int mediated_filesystem(st
static inline struct aa_task_context *aa_task_context(struct task_struct *task)
{
- return (struct aa_task_context *) rcu_dereference(task->security);
+ return rcu_dereference(task->security);
}
static inline struct aa_namespace *aa_get_namespace(struct aa_namespace *ns)
@@ -91,7 +91,7 @@ static inline struct aa_profile *aa_get_
static inline struct aa_profile *aa_find_profile(struct aa_namespace *ns,
const char *name)
{
- struct aa_profile *profile = NULL;
+ struct aa_profile *profile;
read_lock(&ns->lock);
profile = aa_dup_profile(__aa_find_profile(name, &ns->profiles));
--- a/security/apparmor/list.c
+++ b/security/apparmor/list.c
@@ -112,6 +112,7 @@ static struct aa_profile *next_profile(s
}
static void *p_start(struct seq_file *f, loff_t *pos)
+ __acquires(profile_ns_list_lock)
{
struct aa_namespace *ns;
loff_t l = *pos;
@@ -144,6 +145,7 @@ static void *p_next(struct seq_file *f,
}
static void p_stop(struct seq_file *f, void *p)
+ __releases(profile_ns_list_lock)
{
struct aa_profile *profile = (struct aa_profile *) p;
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -10,7 +10,7 @@
*/
#include <linux/security.h>
-#include <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/mount.h>
@@ -45,27 +45,21 @@ static int param_get_aauint(char *buffer
*/
int apparmor_complain;
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;
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;
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;
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
@@ -74,10 +68,9 @@ MODULE_PARM_DESC(apparmor_path_max, "Max
#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;
+static 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)
{
@@ -557,7 +550,7 @@ static int apparmor_file_permission(stru
aa_mask_permissions(mask));
}
-static inline int apparmor_file_lock(struct file *file, unsigned int cmd)
+static int apparmor_file_lock(struct file *file, unsigned int cmd)
{
int mask = AA_MAY_LOCK;
if (cmd == F_WRLCK)
@@ -583,8 +576,8 @@ static void apparmor_file_free_security(
aa_put_profile(file_profile);
}
-static inline int aa_mmap(struct file *file, const char *operation,
- unsigned long prot, unsigned long flags)
+static int aa_mmap(struct file *file, const char *operation,
+ unsigned long prot, unsigned long flags)
{
struct dentry *dentry;
int mask = 0;
@@ -883,7 +876,7 @@ static int apparmor_task_setrlimit(unsig
return error;
}
-struct security_operations apparmor_ops = {
+static struct security_operations apparmor_ops = {
.name = "apparmor",
.ptrace_may_access = apparmor_ptrace_may_access,
.ptrace_traceme = apparmor_ptrace_traceme,
@@ -1029,6 +1022,3 @@ void apparmor_disable(void)
info_message("AppArmor protection removed");
}
-MODULE_DESCRIPTION("AppArmor process confinement");
-MODULE_AUTHOR("Novell/Immunix, http://bugs.opensuse.org");
-MODULE_LICENSE("GPL");
--- a/security/apparmor/main.c
+++ b/security/apparmor/main.c
@@ -299,7 +299,7 @@ int aa_audit_reject(struct aa_profile *p
* @profile: profile to check against
* @sa: audit event
*/
-int aa_audit(struct aa_profile *profile, struct aa_audit *sa)
+static int aa_audit(struct aa_profile *profile, struct aa_audit *sa)
{
int type = AUDIT_APPARMOR_DENIED;
struct audit_context *audit_cxt;
@@ -520,7 +520,8 @@ static char *new_compound_name(const cha
sprintf(name, "%s//%s", n1, n2);
return name;
}
-static inline void aa_put_name_buffer(char *buffer)
+
+static void aa_put_name_buffer(char *buffer)
{
kfree(buffer);
}
--- a/security/apparmor/match.c
+++ b/security/apparmor/match.c
@@ -226,8 +226,9 @@ void aa_match_free(struct aa_dfa *dfa)
* but that would require traversing the string twice and be slightly
* slower.
*/
-unsigned int aa_dfa_next_state_len(struct aa_dfa *dfa, unsigned int start,
- const char *str, int len)
+static unsigned int aa_dfa_next_state_len(struct aa_dfa *dfa,
+ unsigned int start,
+ const char *str, int len)
{
u16 *def = DEFAULT_TABLE(dfa);
u32 *base = BASE_TABLE(dfa);
--- a/security/apparmor/module_interface.c
+++ b/security/apparmor/module_interface.c
@@ -61,7 +61,7 @@ struct aa_ext {
char *ns_name;
};
-static inline int aa_inbounds(struct aa_ext *e, size_t size)
+static int aa_inbounds(struct aa_ext *e, size_t size)
{
return (size <= e->end - e->pos);
}
@@ -94,7 +94,7 @@ fail:
return 0;
}
-static inline int aa_is_X(struct aa_ext *e, enum aa_code code)
+static int aa_is_X(struct aa_ext *e, enum aa_code code)
{
if (!aa_inbounds(e, 1))
return 0;
@@ -369,7 +369,7 @@ fail:
static struct aa_profile *aa_unpack_profile(struct aa_ext *e,
struct aa_audit *sa)
{
- struct aa_profile *profile = NULL;
+ struct aa_profile *profile;
size_t size = 0;
int i, error = -EPROTO;
@@ -465,8 +465,7 @@ fail:
sa->info = "failed to unpack profile";
aa_audit_status(NULL, sa);
- if (profile)
- free_aa_profile(profile);
+ free_aa_profile(profile);
return ERR_PTR(error);
}
@@ -508,7 +507,7 @@ static int aa_verify_header(struct aa_ex
*/
ssize_t aa_add_profile(void *data, size_t size)
{
- struct aa_profile *profile = NULL;
+ struct aa_profile *profile;
struct aa_namespace *ns = NULL;
struct aa_ext e = {
.start = data,
@@ -585,7 +584,7 @@ ssize_t aa_add_profile(void *data, size_
* @new_cxt: new aa_task_context to do replacement with
* @new_profile: new profile
*/
-static inline void task_replace(struct task_struct *task,
+static void task_replace(struct task_struct *task,
struct aa_task_context *new_cxt,
struct aa_profile *new_profile)
{

View file

@ -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
@@ -226,7 +226,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;
@@ -256,7 +256,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;
@@ -264,6 +269,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
@@ -276,7 +290,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);
}
/**
@@ -293,7 +307,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);
}
/*
@@ -434,8 +448,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)
@@ -460,7 +475,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);
}
/*
@@ -857,7 +872,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)
@@ -1216,7 +1231,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);
@@ -2862,6 +2877,7 @@ EXPORT_SYMBOL(path_lookup);
EXPORT_SYMBOL(kern_path);
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
@@ -250,7 +250,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;
@@ -474,7 +474,7 @@ asmlinkage long sys_faccessat(int dfd, c
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;
@@ -517,7 +517,7 @@ asmlinkage long sys_chdir(const char __u
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;
@@ -546,7 +546,7 @@ asmlinkage long sys_fchdir(unsigned int
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:
@@ -564,7 +564,7 @@ asmlinkage long sys_chroot(const char __
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
@@ -1242,6 +1242,11 @@ int fiemap_fill_next_extent(struct fiema
int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags);
/*
+ * VFS path helper functions.
+ */
+extern int path_permission(struct path *, int);
+
+/*
* File types
*
* NOTE! These match bits 12..15 of stat.st_mode

View file

@ -0,0 +1,109 @@
From: Jeff Mahoney <jeffm@suse.com>
Subject: [PATCH] security: add ->path_permission
This patch adds a security_ops->path_permission hook that is identical to
security_ops->inode_permission except that it is passed a struct path
instead of a struct inode.
LSMs which don't implement it will have their ->inode_permission call
used instead.
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
include/linux/security.h | 21 +++++++++++++++++++++
security/capability.c | 6 ++++++
security/security.c | 9 +++++++++
3 files changed, 36 insertions(+)
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -592,6 +592,20 @@ static inline void security_free_mnt_opt
* file_permission, and recheck access if anything has changed
* since inode_permission.
*
+ * Security hook for path
+ *
+ * @path_permission:
+ * Check permission before accessing a path. This hook is called by the
+ * existing Linux permission function, so a security module can use it to
+ * provide additional checking for existing Linux permission checks.
+ * Notice that this hook is called when a file is opened (as well as many
+ * other operations), whereas the file_security_ops permission hook is
+ * called when the actual read/write operations are performed. This
+ * hook is optional and if absent, inode_permission will be substituted.
+ * @path contains the path structure to check.
+ * @mask contains the permission mask.
+ * Return 0 if permission is granted.
+
* Security hooks for task operations.
*
* @task_create:
@@ -1434,6 +1448,7 @@ struct security_operations {
struct fown_struct *fown, int sig);
int (*file_receive) (struct file *file);
int (*dentry_open) (struct file *file);
+ int (*path_permission) (struct path *path, int mask);
int (*task_create) (unsigned long clone_flags);
int (*task_alloc_security) (struct task_struct *p);
@@ -1704,6 +1719,7 @@ int security_file_send_sigiotask(struct
struct fown_struct *fown, int sig);
int security_file_receive(struct file *file);
int security_dentry_open(struct file *file);
+int security_path_permission(struct path *path, int mask);
int security_task_create(unsigned long clone_flags);
int security_task_alloc(struct task_struct *p);
void security_task_free(struct task_struct *p);
@@ -2245,6 +2261,11 @@ static inline int security_dentry_open(s
{
return 0;
}
+
+static inline int security_path_permission(struct path *path, int mask)
+{
+ return 0;
+}
static inline int security_task_create(unsigned long clone_flags)
{
--- a/security/capability.c
+++ b/security/capability.c
@@ -343,6 +343,11 @@ static int cap_dentry_open(struct file *
return 0;
}
+static int cap_path_permission(struct path *path, int mask)
+{
+ return security_inode_permission(path->dentry->d_inode, mask);
+}
+
static int cap_task_create(unsigned long clone_flags)
{
return 0;
@@ -897,6 +902,7 @@ void security_fixup_ops(struct security_
set_to_cap_if_null(ops, file_send_sigiotask);
set_to_cap_if_null(ops, file_receive);
set_to_cap_if_null(ops, dentry_open);
+ set_to_cap_if_null(ops, path_permission);
set_to_cap_if_null(ops, task_create);
set_to_cap_if_null(ops, task_alloc_security);
set_to_cap_if_null(ops, task_free_security);
--- a/security/security.c
+++ b/security/security.c
@@ -624,6 +624,15 @@ int security_dentry_open(struct file *fi
return security_ops->dentry_open(file);
}
+int security_path_permission(struct path *path, int mask)
+{
+ struct inode *inode = path->dentry->d_inode;
+ if (unlikely(IS_PRIVATE(inode)))
+ return 0;
+
+ return security_ops->path_permission(path, mask);
+}
+
int security_task_create(unsigned long clone_flags)
{
return security_ops->task_create(clone_flags);

View file

@ -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;

View file

@ -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 */
@@ -547,6 +554,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
@@ -1243,8 +1243,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;
@@ -1518,3 +1517,6 @@ EXPORT_SYMBOL(audit_log_start);
EXPORT_SYMBOL(audit_log_end);
EXPORT_SYMBOL(audit_log_format);
EXPORT_SYMBOL(audit_log);
+EXPORT_SYMBOL_GPL(audit_log_vformat);
+EXPORT_SYMBOL_GPL(audit_log_untrustedstring);
+EXPORT_SYMBOL_GPL(audit_log_d_path);

View file

@ -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
@@ -134,6 +134,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
@@ -15,5 +15,6 @@ obj-$(CONFIG_SECURITYFS) += inode.o
# 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

View 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 (error && 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");

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -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=");
@@ -768,6 +807,72 @@ int aa_link(struct aa_profile *profile,
return error;
}
+
+int aa_net_perm(struct aa_profile *profile, char *operation,
+ int family, int type, int protocol)
+{
+ struct aa_audit sa;
+ int error = 0;
+ u16 family_mask, audit_mask, quiet_mask;
+
+ if ((family < 0) || (family >= AF_MAX))
+ return -EINVAL;
+
+ if ((type < 0) || (type >= SOCK_MAX))
+ return -EINVAL;
+
+ /* unix domain and netlink sockets are handled by ipc */
+ if (family == AF_UNIX || family == AF_NETLINK)
+ return 0;
+
+ family_mask = profile->network_families[family];
+ audit_mask = profile->audit_network[family];
+ quiet_mask = profile->quiet_network[family];
+
+ error = (family_mask & (1 << type)) ? 0 : -EACCES;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.operation = operation;
+ sa.gfp_mask = GFP_KERNEL;
+ sa.family = family;
+ sa.type = type;
+ sa.protocol = protocol;
+ sa.error_code = error;
+
+ if (likely(!error)) {
+ if (!PROFILE_AUDIT(profile) && !(family_mask & audit_mask))
+ return 0;
+ } else if (!((1 << type) & ~quiet_mask)) {
+ return error;
+ }
+
+ error = aa_audit(profile, &sa);
+
+ return error;
+}
+
+int aa_revalidate_sk(struct sock *sk, char *operation)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ /* this is some debugging code to flush out the network hooks that
+ that are called in interrupt context */
+ if (in_interrupt()) {
+ printk("AppArmor Debug: Hook being called from interrupt context\n");
+ dump_stack();
+ return 0;
+ }
+
+ profile = aa_get_profile(current);
+ if (profile)
+ error = aa_net_perm(profile, operation,
+ sk->sk_family, sk->sk_type,
+ sk->sk_protocol);
+ aa_put_profile(profile);
+
+ return error;
+}
/*******************************
* Global task related functions
--- a/security/apparmor/module_interface.c
+++ b/security/apparmor/module_interface.c
@@ -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)) {

View file

@ -0,0 +1,78 @@
From: Jeff Mahoney <jeffm@suse.com>
Subject: [PATCH] apparmor: convert apparmor_inode_permission to path
patches.apparmor/add-security_path_permission added the ->path_permission
call. This patch converts apparmor_inode_permission to
apparmor_path_permission. The former is now a pass-all, which is how
it behaved in 2.6.26 if a NULL nameidata was passed.
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
security/apparmor/lsm.c | 41 +++++++++++++++++++++++++++--------------
1 file changed, 27 insertions(+), 14 deletions(-)
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -448,21 +448,9 @@ out:
return error;
}
-static int apparmor_inode_permission(struct inode *inode, int mask,
- struct nameidata *nd)
+static int apparmor_inode_permission(struct inode *inode, int mask)
{
- 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);
+ return 0;
}
static int apparmor_inode_setattr(struct dentry *dentry, struct vfsmount *mnt,
@@ -656,6 +644,29 @@ static int apparmor_file_mprotect(struct
!(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
}
+static int apparmor_path_permission(struct path *path, int mask)
+{
+ struct inode *inode;
+ int check = 0;
+
+ if (!path)
+ return 0;
+
+ inode = path->dentry->d_inode;
+
+ mask = aa_mask_permissions(mask);
+ if (S_ISDIR(inode->i_mode)) {
+ check |= AA_CHECK_DIR;
+ /* allow traverse accesses to directories */
+ mask &= ~MAY_EXEC;
+ if (!mask)
+ return 0;
+ }
+
+ return aa_permission("inode_permission", inode, path->dentry,
+ path->mnt, mask, check);
+}
+
static int apparmor_task_alloc_security(struct task_struct *task)
{
return aa_clone(task);
@@ -800,6 +811,8 @@ struct security_operations apparmor_ops
.file_mprotect = apparmor_file_mprotect,
.file_lock = apparmor_file_lock,
+ .path_permission = apparmor_path_permission,
+
.task_alloc_security = apparmor_task_alloc_security,
.task_free_security = apparmor_task_free_security,
.task_post_setuid = cap_task_post_setuid,

View file

@ -0,0 +1,113 @@
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>
Signed-off-by: John Johansen <jjohansen@suse.de>
---
security/apparmor/lsm.c | 51 ++++++++++++++++++++++++++++++------------------
1 file changed, 32 insertions(+), 19 deletions(-)
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -157,47 +157,47 @@ static int aa_reject_syscall(struct task
return error;
}
-static int apparmor_ptrace(struct task_struct *parent,
- struct task_struct *child, unsigned int mode)
+static int apparmor_ptrace(struct task_struct *tracer,
+ struct task_struct *tracee)
{
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
+ * tracer can ptrace tracee when
+ * - tracer is unconfined
+ * - tracer & tracee are in the same namespace &&
+ * - tracer is in complain mode
+ * - tracer and tracee are confined by the same profile
+ * - tracer profile has CAP_SYS_PTRACE
*/
rcu_read_lock();
- cxt = aa_task_context(parent);
+ cxt = aa_task_context(tracer);
if (cxt) {
- if (parent->nsproxy != child->nsproxy) {
+ if (tracer->nsproxy != tracee->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.parent = tracer->pid;
+ sa.task = tracee->pid;
sa.info = "different namespaces";
aa_audit_reject(cxt->profile, &sa);
error = -EPERM;
} else {
- struct aa_task_context *child_cxt =
- aa_task_context(child);
+ struct aa_task_context *tracee_cxt =
+ aa_task_context(tracee);
- error = aa_may_ptrace(cxt, child_cxt ?
- child_cxt->profile : NULL);
+ error = aa_may_ptrace(cxt, tracee_cxt ?
+ tracee_cxt->profile : NULL);
if (error && 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;
+ sa.parent = tracer->pid;
+ sa.task = tracee->pid;
aa_audit_hint(cxt->profile, &sa);
}
}
@@ -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(current, 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,

View file

@ -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;
@@ -873,6 +876,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
@@ -886,6 +962,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;
@@ -895,6 +972,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) {
@@ -911,18 +993,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);
@@ -1157,6 +1243,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;
}
@@ -1304,6 +1394,12 @@ static int do_change_profile(struct aa_p
goto out;
}
+ if ((error = aa_rlimit_nproc(new_profile))) {
+ sa->info = "rlimit nproc limit exceeded";
+ aa_audit_reject(cxt->profile, sa);
+ goto out;
+ }
+
if (new_profile == ns->null_complain_profile)
aa_audit_hint(cxt->profile, sa);
@@ -1482,17 +1578,18 @@ struct aa_profile *__aa_replace_profile(
cxt = lock_task_and_profiles(task, profile);
if (unlikely(profile && profile->isstale)) {
- task_unlock(task);
- unlock_both_profiles(profile, cxt ? cxt->profile : NULL);
- aa_free_task_context(new_cxt);
- return ERR_PTR(-ESTALE);
+ old_profile = ERR_PTR(-ESTALE);
+ goto error;
}
if ((current->ptrace & PT_PTRACED) && aa_may_ptrace(cxt, profile)) {
- task_unlock(task);
- unlock_both_profiles(profile, cxt ? cxt->profile : NULL);
- aa_free_task_context(new_cxt);
- return ERR_PTR(-EPERM);
+ old_profile = ERR_PTR(-EPERM);
+ goto error;
+ }
+
+ if (aa_rlimit_nproc(profile)) {
+ old_profile = ERR_PTR(-EAGAIN);
+ goto error;
}
if (cxt)
@@ -1500,8 +1597,15 @@ struct aa_profile *__aa_replace_profile(
aa_change_task_context(task, new_cxt, profile, 0, NULL);
task_unlock(task);
+ aa_set_rlimits(task, profile);
unlock_both_profiles(profile, old_profile);
return old_profile;
+
+error:
+ task_unlock(task);
+ unlock_both_profiles(profile, cxt ? cxt->profile : NULL);
+ aa_free_task_context(new_cxt);
+ return old_profile;
}
/**
@@ -1566,6 +1670,7 @@ void aa_change_task_context(struct task_
if (old_cxt) {
list_del_init(&old_cxt->list);
+ old_cxt->profile->task_count--;
call_rcu(&old_cxt->rcu, free_aa_task_context_rcu_callback);
}
if (new_cxt) {
@@ -1577,6 +1682,7 @@ void aa_change_task_context(struct task_
new_cxt->cookie = cookie;
new_cxt->task = task;
new_cxt->profile = aa_dup_profile(profile);
+ profile->task_count++;
new_cxt->previous_profile = aa_dup_profile(previous_profile);
list_move(&new_cxt->list, &profile->task_contexts);
}
--- a/security/apparmor/module_interface.c
+++ b/security/apparmor/module_interface.c
@@ -177,6 +177,22 @@ fail:
return 0;
}
+static int aa_is_u64(struct aa_ext *e, u64 *data, const char *name)
+{
+ void *pos = e->pos;
+ if (aa_is_nameX(e, AA_U64, name)) {
+ if (!aa_inbounds(e, sizeof(u64)))
+ goto fail;
+ if (data)
+ *data = le64_to_cpu(get_unaligned((u64 *)e->pos));
+ e->pos += sizeof(u64);
+ return 1;
+ }
+fail:
+ e->pos = pos;
+ return 0;
+}
+
static size_t aa_is_array(struct aa_ext *e, const char *name)
{
void *pos = e->pos;
@@ -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)
{

View file

@ -0,0 +1,87 @@
From: Jeff Mahoney <jeffm@suse.com>
Subject: aufs: AppArmor compatibility
This patch adds NULL vfsmounts for AppArmor enabled kernels.
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
fs/aufs25/vfsub.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
--- a/fs/aufs25/vfsub.c
+++ b/fs/aufs25/vfsub.c
@@ -127,9 +127,9 @@ int do_vfsub_create(struct inode *dir, s
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
-#define VfsubSymlinkArgs dir, dentry, symname
+#define VfsubSymlinkArgs dir, dentry, NULL, symname
#else
-#define VfsubSymlinkArgs dir, dentry, symname, mode
+#define VfsubSymlinkArgs dir, dentry, NULL, symname, mode
#endif
int do_vfsub_symlink(struct inode *dir, struct dentry *dentry,
@@ -158,7 +158,7 @@ int do_vfsub_mknod(struct inode *dir, st
LKTRTrace("i%lu, %.*s, 0x%x\n", dir->i_ino, AuDLNPair(dentry), mode);
IMustLock(dir);
- err = vfs_mknod(dir, dentry, mode, dev);
+ err = vfs_mknod(dir, dentry, NULL, mode, dev);
if (!err) {
/* dir inode is locked */
au_update_fuse_h_inode(NULL, dentry->d_parent); /*ignore*/
@@ -177,7 +177,7 @@ int do_vfsub_link(struct dentry *src_den
IMustLock(dir);
lockdep_off();
- err = vfs_link(src_dentry, dir, dentry);
+ err = vfs_link(src_dentry, NULL, dir, dentry, 0);
lockdep_on();
if (!err) {
LKTRTrace("src_i %p, dst_i %p\n",
@@ -203,7 +203,7 @@ int do_vfsub_rename(struct inode *src_di
IMustLock(src_dir);
lockdep_off();
- err = vfs_rename(src_dir, src_dentry, dir, dentry);
+ err = vfs_rename(src_dir, src_dentry, NULL, dir, dentry, 0);
lockdep_on();
if (!err) {
/* dir inode is locked */
@@ -221,7 +221,7 @@ int do_vfsub_mkdir(struct inode *dir, st
LKTRTrace("i%lu, %.*s, 0x%x\n", dir->i_ino, AuDLNPair(dentry), mode);
IMustLock(dir);
- err = vfs_mkdir(dir, dentry, mode);
+ err = vfs_mkdir(dir, dentry, NULL, mode);
if (!err) {
/* dir inode is locked */
au_update_fuse_h_inode(NULL, dentry->d_parent); /*ignore*/
@@ -238,7 +238,7 @@ int do_vfsub_rmdir(struct inode *dir, st
IMustLock(dir);
lockdep_off();
- err = vfs_rmdir(dir, dentry);
+ err = vfs_rmdir(dir, dentry, 0);
lockdep_on();
/* dir inode is locked */
if (!err)
@@ -255,7 +255,7 @@ int do_vfsub_unlink(struct inode *dir, s
/* vfs_unlink() locks inode */
lockdep_off();
- err = vfs_unlink(dir, dentry);
+ err = vfs_unlink(dir, dentry, 0);
lockdep_on();
/* dir inode is locked */
if (!err)
@@ -493,7 +493,7 @@ static void call_notify_change(void *arg
if (!IS_IMMUTABLE(h_inode) && !IS_APPEND(h_inode)) {
vfsub_ignore(a->vargs);
lockdep_off();
- *a->errp = notify_change(a->h_dentry, a->ia);
+ *a->errp = notify_change(a->h_dentry, NULL, a->ia);
lockdep_on();
if (!*a->errp)
au_update_fuse_h_inode(NULL, a->h_dentry); /*ignore*/

View file

@ -0,0 +1,179 @@
From: Jeff Mahoney <jeffm@suse.com>
Subject: Add fsetattr
An AppArmor patch removed ia_file and ATTR_FILE from struct iattr and
replaced it with the fsetattr file_operation.
This patch fixes aufs to use it.
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
fs/aufs25/dir.c | 1 +
fs/aufs25/f_op.c | 1 +
fs/aufs25/i_op.c | 25 ++++++++++++++-----------
fs/aufs25/inode.h | 1 +
fs/aufs25/misc.c | 5 ++---
fs/aufs25/vfsub.c | 13 ++++++++++---
fs/aufs25/vfsub.h | 2 ++
7 files changed, 31 insertions(+), 17 deletions(-)
--- a/fs/aufs25/dir.c
+++ b/fs/aufs25/dir.c
@@ -546,4 +546,5 @@ struct file_operations aufs_dir_fop = {
.release = aufs_release_dir,
.flush = aufs_flush,
.fsync = aufs_fsync_dir,
+ .fsetattr = aufs_fsetattr,
};
--- a/fs/aufs25/f_op.c
+++ b/fs/aufs25/f_op.c
@@ -665,4 +665,5 @@ struct file_operations aufs_file_fop = {
.splice_write = aufs_splice_write,
.splice_read = aufs_splice_read,
#endif
+ .fsetattr = aufs_fsetattr,
};
--- a/fs/aufs25/i_op.c
+++ b/fs/aufs25/i_op.c
@@ -727,13 +727,13 @@ static int au_lock_and_icpup(struct dent
return err;
}
-static int aufs_setattr(struct dentry *dentry, struct iattr *ia)
+static int aufs_do_setattr(struct dentry *dentry, struct iattr *ia,
+ struct file *file)
{
int err;
struct inode *inode;
struct super_block *sb;
__u32 events;
- struct file *file;
loff_t sz;
struct au_icpup_args *a;
@@ -751,12 +751,8 @@ static int aufs_setattr(struct dentry *d
si_read_lock(sb, AuLock_FLUSH);
vfsub_args_init(&a->vargs, a->ign, au_test_dlgt(au_mntflags(sb)), 0);
- if (ia->ia_valid & ATTR_FILE) {
- /* currently ftruncate(2) only */
- file = ia->ia_file;
+ if (file)
fi_write_lock(file);
- ia->ia_file = au_h_fptr(file, au_fbstart(file));
- }
sz = -1;
if ((ia->ia_valid & ATTR_SIZE)
@@ -800,11 +796,8 @@ static int aufs_setattr(struct dentry *d
au_unpin(&a->pin);
di_write_unlock(dentry);
out_si:
- if (file) {
+ if (file)
fi_write_unlock(file);
- ia->ia_file = file;
- ia->ia_valid |= ATTR_FILE;
- }
si_read_unlock(sb);
kfree(a);
out:
@@ -812,6 +805,16 @@ static int aufs_setattr(struct dentry *d
return err;
}
+static int aufs_setattr(struct dentry *dentry, struct iattr *ia)
+{
+ return aufs_do_setattr(dentry, ia, NULL);
+}
+
+int aufs_fsetattr(struct file *file, struct iattr *ia)
+{
+ return aufs_do_setattr(file->f_dentry, ia, file);
+}
+
/* ---------------------------------------------------------------------- */
static int h_readlink(struct dentry *dentry, int bindex, char __user *buf,
--- a/fs/aufs25/inode.h
+++ b/fs/aufs25/inode.h
@@ -84,6 +84,7 @@ int au_test_h_perm_sio(struct inode *h_i
/* i_op.c */
extern struct inode_operations aufs_iop, aufs_symlink_iop, aufs_dir_iop;
+int aufs_fsetattr(struct file *file, struct iattr *ia);
/* au_wr_dir flags */
#define AuWrDir_ADD_ENTRY 1
--- a/fs/aufs25/misc.c
+++ b/fs/aufs25/misc.c
@@ -267,13 +267,12 @@ int au_copy_file(struct file *dst, struc
if (err == 1) {
ia = (void *)buf;
ia->ia_size = dst->f_pos;
- ia->ia_valid = ATTR_SIZE | ATTR_FILE;
- ia->ia_file = dst;
+ ia->ia_valid = ATTR_SIZE;
vfsub_args_reinit(vargs);
vfsub_ign_hinode(vargs, vfsub_events_notify_change(ia),
hdir);
mutex_lock_nested(&h_i->i_mutex, AuLsc_I_CHILD2);
- err = vfsub_notify_change(h_d, ia, vargs);
+ err = vfsub_fnotify_change(h_d, ia, vargs, dst);
mutex_unlock(&h_i->i_mutex);
}
}
--- a/fs/aufs25/vfsub.c
+++ b/fs/aufs25/vfsub.c
@@ -477,6 +477,7 @@ struct notify_change_args {
struct dentry *h_dentry;
struct iattr *ia;
struct vfsub_args *vargs;
+ struct file *file;
};
static void call_notify_change(void *args)
@@ -493,7 +494,7 @@ static void call_notify_change(void *arg
if (!IS_IMMUTABLE(h_inode) && !IS_APPEND(h_inode)) {
vfsub_ignore(a->vargs);
lockdep_off();
- *a->errp = notify_change(a->h_dentry, NULL, a->ia);
+ *a->errp = fnotify_change(a->h_dentry, NULL, a->ia, a->file);
lockdep_on();
if (!*a->errp)
au_update_fuse_h_inode(NULL, a->h_dentry); /*ignore*/
@@ -525,8 +526,8 @@ static void vfsub_notify_change_dlgt(str
}
#endif
-int vfsub_notify_change(struct dentry *dentry, struct iattr *ia,
- struct vfsub_args *vargs)
+int vfsub_fnotify_change(struct dentry *dentry, struct iattr *ia,
+ struct vfsub_args *vargs, struct file *file)
{
int err;
struct notify_change_args args = {
@@ -570,6 +571,12 @@ int vfsub_sio_notify_change(struct au_hi
return err;
}
+int vfsub_notify_change(struct dentry *dentry, struct iattr *ia,
+ struct vfsub_args *vargs)
+{
+ return vfsub_fnotify_change(dentry, ia, vargs, NULL);
+}
+
/* ---------------------------------------------------------------------- */
struct unlink_args {
--- a/fs/aufs25/vfsub.h
+++ b/fs/aufs25/vfsub.h
@@ -508,6 +508,8 @@ int vfsub_sio_notify_change(struct au_hi
/* ---------------------------------------------------------------------- */
+int vfsub_fnotify_change(struct dentry *dentry, struct iattr *ia,
+ struct vfsub_args *vargs, struct file *file);
int vfsub_notify_change(struct dentry *dentry, struct iattr *ia,
struct vfsub_args *vargs);
int vfsub_unlink(struct inode *dir, struct dentry *dentry,

View file

@ -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
@@ -2349,3 +2349,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(&current->fs->lock);
+ root = current->fs->root;
+ path_get(&current->fs->root);
+ read_unlock(&current->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
@@ -112,4 +112,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 */

View file

@ -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
@@ -1067,24 +1067,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);

View file

@ -0,0 +1,26 @@
From: Jeff Mahoney <jeffm@suse.com>
Subject: [PATCH] LSM: Export security_inode_permission for aufs
Patch-mainline: Never
References: 356902
In order for aufs to work with AppArmor, it needs to be able to call
security_inode_permission itself.
This patch is a _workaround_ since the author will need to find a
mainline-compatible solution moving forward.
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
security/security.c | 1 +
1 file changed, 1 insertion(+)
--- a/security/security.c
+++ b/security/security.c
@@ -424,6 +424,7 @@ int security_inode_mknod(struct inode *d
return 0;
return security_ops->inode_mknod(dir, dentry, mnt, mode, dev);
}
+EXPORT_SYMBOL_GPL(security_inode_permission);
int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
struct vfsmount *old_mnt, struct inode *new_dir,

View file

@ -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
@@ -413,7 +413,7 @@ static ssize_t nfsd_getxattr(struct dent
ssize_t buflen;
ssize_t ret;
- buflen = vfs_getxattr(dentry, mnt, key, NULL, 0);
+ buflen = vfs_getxattr(dentry, mnt, key, NULL, 0, NULL);
if (buflen <= 0)
return buflen;
@@ -421,7 +421,7 @@ static ssize_t nfsd_getxattr(struct dent
if (!*buf)
return -ENOMEM;
- ret = vfs_getxattr(dentry, mnt, key, *buf, buflen);
+ ret = vfs_getxattr(dentry, mnt, key, *buf, buflen, NULL);
if (ret < 0)
kfree(*buf);
return ret;
@@ -450,7 +450,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;
@@ -2212,12 +2212,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
@@ -604,7 +604,7 @@ asmlinkage long sys_fchmod(unsigned int
if (mode == (mode_t) -1)
mode = inode->i_mode;
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
- newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
+ newattrs.ia_valid = ATTR_MODE | ATTR_CTIME | ATTR_FILE;
err = fnotify_change(dentry, file->f_path.mnt, &newattrs, file);
mutex_unlock(&inode->i_mutex);
mnt_drop_write(file->f_path.mnt);
@@ -668,6 +668,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);

View file

@ -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 */

View file

@ -0,0 +1,14 @@
---
security/apparmor/Kconfig | 1 +
1 file changed, 1 insertion(+)
--- a/security/apparmor/Kconfig
+++ b/security/apparmor/Kconfig
@@ -1,6 +1,7 @@
config SECURITY_APPARMOR
bool "AppArmor support"
depends on SECURITY
+ depends on SECURITY_NETWORK
select AUDIT
help
This enables the AppArmor security module.

View file

@ -0,0 +1,15 @@
---
fs/namespace.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -2362,7 +2362,7 @@ char *d_namespace_path(struct dentry *de
path_get(&current->fs->root);
read_unlock(&current->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);

View file

@ -0,0 +1,35 @@
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/apparmor/lsm.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
--- 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;
}

View file

@ -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
@@ -2125,6 +2125,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);
@@ -2132,12 +2136,9 @@ int vfs_rmdir(struct inode *dir, struct
if (d_mountpoint(dentry))
error = -EBUSY;
else {
- error = security_inode_rmdir(dir, dentry, mnt);
- if (!error) {
- error = dir->i_op->rmdir(dir, dentry);
- if (!error)
- dentry->d_inode->i_flags |= S_DEAD;
- }
+ error = dir->i_op->rmdir(dir, dentry);
+ if (!error)
+ dentry->d_inode->i_flags |= S_DEAD;
}
mutex_unlock(&dentry->d_inode->i_mutex);
if (!error) {

View file

@ -0,0 +1,56 @@
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/main.c | 10 +++++-----
security/apparmor/module_interface.c | 2 +-
2 files changed, 6 insertions(+), 6 deletions(-)
--- 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);
@@ -1007,10 +1011,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)))

View file

@ -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
@@ -210,6 +210,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);

View file

@ -0,0 +1,61 @@
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 | 15 +++++++++++++--
include/linux/fs.h | 11 +++++++++++
2 files changed, 24 insertions(+), 2 deletions(-)
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -168,10 +168,21 @@ int fnotify_change(struct dentry *dentry
down_write(&dentry->d_inode->i_alloc_sem);
if (inode->i_op && inode->i_op->setattr) {
- if (file && file->f_op && file->f_op->fsetattr)
+ 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);
if (!error) {
--- 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;
};
/*

View file

@ -0,0 +1,411 @@
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 | 16 +++++++++++++---
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, 66 insertions(+), 41 deletions(-)
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -46,6 +46,7 @@ const struct file_operations afs_dir_fil
.readdir = afs_readdir,
.lock = afs_lock,
.llseek = generic_file_llseek,
+ .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;
@@ -168,7 +168,10 @@ int notify_change(struct dentry *dentry,
down_write(&dentry->d_inode->i_alloc_sem);
if (inode->i_op && inode->i_op->setattr) {
- error = inode->i_op->setattr(dentry, attr);
+ 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 +191,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
@@ -1470,6 +1470,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,
@@ -1483,6 +1488,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,
};
@@ -1496,6 +1502,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
@@ -554,6 +554,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
@@ -209,16 +209,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;
}
@@ -606,7 +602,7 @@ asmlinkage long sys_fchmod(unsigned int
mode = inode->i_mode;
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
- err = notify_change(dentry, file->f_path.mnt, &newattrs);
+ err = fnotify_change(dentry, file->f_path.mnt, &newattrs, file);
mutex_unlock(&inode->i_mutex);
mnt_drop_write(file->f_path.mnt);
out_putf:
@@ -651,7 +647,7 @@ asmlinkage long sys_chmod(const char __u
}
static int chown_common(struct dentry * dentry, struct vfsmount *mnt,
- uid_t user, gid_t group)
+ uid_t user, gid_t group, struct file *file)
{
struct inode *inode = dentry->d_inode;
int error;
@@ -670,7 +666,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;
@@ -687,7 +683,7 @@ asmlinkage long sys_chown(const char __u
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);
@@ -712,7 +708,7 @@ asmlinkage long sys_fchownat(int dfd, co
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);
@@ -731,7 +727,7 @@ asmlinkage long sys_lchown(const char __
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);
@@ -755,7 +751,7 @@ asmlinkage long sys_fchown(unsigned int
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;
};
/*
@@ -1306,6 +1299,7 @@ struct file_operations {
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **);
+ int (*fsetattr)(struct file *, struct iattr *);
};
struct inode_operations {
@@ -1831,6 +1825,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));

View file

@ -0,0 +1,55 @@
---
security/apparmor/lsm.c | 28 ----------------------------
1 file changed, 28 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 *tracer,
struct task_struct *tracee)
{
@@ -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,

View 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
@@ -1773,12 +1773,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)
@@ -1793,7 +1793,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;
}

View file

@ -0,0 +1,34 @@
---
security/Kconfig | 9 +++++++++
security/security.c | 2 +-
2 files changed, 10 insertions(+), 1 deletion(-)
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -59,6 +59,15 @@ config SECURITYFS
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/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;

View 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
@@ -1481,7 +1481,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);
@@ -1618,7 +1619,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);
@@ -1973,6 +1975,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
@@ -367,11 +367,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
@@ -2564,7 +2564,8 @@ static int selinux_inode_init_security(s
return 0;
}
-static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int mask)
+static int selinux_inode_create(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt, int mask)
{
return may_create(dir, dentry, SECCLASS_FILE);
}

View file

@ -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);
@@ -1672,7 +1673,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);
@@ -2118,7 +2120,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
@@ -500,11 +500,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
@@ -2794,7 +2794,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
@@ -671,11 +671,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);
}

View 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
@@ -2391,7 +2391,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);
@@ -1628,8 +1631,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);
@@ -1992,8 +1996,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
@@ -375,12 +375,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
@@ -2570,11 +2570,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;

View file

@ -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);
@@ -1675,7 +1675,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);
@@ -2126,7 +2126,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
@@ -508,11 +508,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
@@ -2800,7 +2800,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);
}

View 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
@@ -2037,7 +2037,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);
@@ -1628,7 +1630,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,
@@ -2006,6 +2009,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
@@ -398,11 +398,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
@@ -2595,7 +2595,8 @@ static int selinux_inode_symlink(struct
return may_create(dir, dentry, SECCLASS_LNK_FILE);
}
-static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, int mask)
+static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt, int mask)
{
return may_create(dir, dentry, SECCLASS_DIR);
}

View file

@ -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
@@ -1942,7 +1942,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;
@@ -2004,11 +2004,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);
@@ -1633,7 +1634,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);
@@ -2023,6 +2025,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
@@ -413,11 +413,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
@@ -2606,11 +2606,12 @@ static int selinux_inode_rmdir(struct in
return may_link(dir, dentry, MAY_RMDIR);
}
-static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
+static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt, int mode, dev_t dev)
{
int rc;
- rc = secondary_ops->inode_mknod(dir, dentry, mode, dev);
+ rc = secondary_ops->inode_mknod(dir, dentry, mnt, mode, dev);
if (rc)
return rc;

View file

@ -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
@@ -306,7 +306,7 @@ asmlinkage long sys_readlinkat(int dfd,
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 *,
@@ -1639,7 +1640,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,
@@ -2041,7 +2042,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
@@ -431,11 +431,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
@@ -2625,7 +2625,7 @@ static int selinux_inode_rename(struct i
return may_rename(old_inode, old_dentry, new_inode, new_dentry);
}
-static int selinux_inode_readlink(struct dentry *dentry)
+static int selinux_inode_readlink(struct dentry *dentry, struct vfsmount *mnt)
{
return dentry_has_perm(current, NULL, dentry, FILE__READ);
}

View file

@ -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);
@@ -1676,7 +1678,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);
@@ -2133,9 +2136,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
@@ -426,7 +426,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
@@ -515,11 +515,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
@@ -2805,7 +2805,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
@@ -685,13 +685,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;
@@ -701,7 +703,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);

View 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
@@ -2518,7 +2518,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;
@@ -2552,7 +2553,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);
@@ -1649,7 +1653,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);
@@ -2050,8 +2055,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
@@ -426,13 +426,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
@@ -2626,8 +2626,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;

View 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
@@ -2132,7 +2132,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,
@@ -1639,7 +1641,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,
@@ -2027,7 +2030,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
@@ -408,11 +408,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
@@ -2607,7 +2607,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;

View file

@ -0,0 +1,139 @@
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 | 2 +-
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, 19 insertions(+), 11 deletions(-)
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -160,7 +160,7 @@ int notify_change(struct dentry *dentry,
if (!(attr->ia_valid & ~(ATTR_KILL_SUID | ATTR_KILL_SGID)))
return 0;
- error = security_inode_setattr(dentry, attr);
+ error = security_inode_setattr(dentry, mnt, attr);
if (error)
return error;
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -93,7 +93,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,
@@ -1634,7 +1636,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,
@@ -2046,7 +2049,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
@@ -450,11 +450,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
@@ -2654,11 +2654,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.

View file

@ -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);
@@ -1662,10 +1666,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);
@@ -2097,13 +2103,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
@@ -411,8 +411,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
@@ -480,20 +480,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
@@ -2711,8 +2711,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;
@@ -2766,7 +2767,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;
@@ -615,7 +617,7 @@ static int smack_inode_setxattr(struct d
if (!capable(CAP_MAC_ADMIN))
rc = -EPERM;
} 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);
@@ -626,6 +628,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
@@ -634,7 +637,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;

View file

@ -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
@@ -2312,7 +2312,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);
@@ -1630,7 +1631,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);
@@ -2004,6 +2005,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
@@ -391,11 +391,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
@@ -2590,7 +2590,8 @@ static int selinux_inode_unlink(struct i
return may_link(dir, dentry, MAY_UNLINK);
}
-static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name)
+static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry,
+ struct vfsmount *mnt, const char *name)
{
return may_create(dir, dentry, SECCLASS_LNK_FILE);
}

View file

@ -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
@@ -2215,7 +2215,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,
@@ -1636,7 +1638,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,
@@ -2008,7 +2011,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
@@ -385,11 +385,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
@@ -2585,11 +2585,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;

View file

@ -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 @@ sys_setxattr(const char __user *pathname
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 @@ sys_lsetxattr(const char __user *pathnam
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);
@@ -307,7 +308,8 @@ sys_fsetxattr(int fd, const char __user
audit_inode(NULL, dentry);
error = mnt_want_write(f->f_path.mnt);
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);
@@ -319,7 +321,7 @@ sys_fsetxattr(int fd, const char __user
*/
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;
@@ -339,7 +341,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;
@@ -362,7 +364,7 @@ sys_getxattr(const char __user *pathname
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;
}
@@ -377,7 +379,7 @@ sys_lgetxattr(const char __user *pathnam
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;
}
@@ -392,7 +394,7 @@ sys_fgetxattr(int fd, const char __user
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;
}
@@ -402,7 +404,7 @@ sys_fgetxattr(int fd, const char __user
*/
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;
@@ -415,7 +417,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;
@@ -437,7 +439,7 @@ sys_listxattr(const char __user *pathnam
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;
}
@@ -451,7 +453,7 @@ sys_llistxattr(const char __user *pathna
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;
}
@@ -466,7 +468,7 @@ sys_flistxattr(int fd, char __user *list
if (!f)
return error;
audit_inode(NULL, f->f_path.dentry);
- error = listxattr(f->f_path.dentry, f->f_path.mnt, list, size);
+ error = listxattr(f->f_path.dentry, f->f_path.mnt, list, size, f);
fput(f);
return error;
}
@@ -475,7 +477,8 @@ sys_flistxattr(int fd, char __user *list
* 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];
@@ -486,7 +489,7 @@ removexattr(struct dentry *dentry, struc
if (error < 0)
return error;
- return vfs_removexattr(dentry, mnt, kname);
+ return vfs_removexattr(dentry, mnt, kname, file);
}
asmlinkage long
@@ -500,7 +503,7 @@ sys_removexattr(const char __user *pathn
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);
@@ -518,7 +521,7 @@ sys_lremovexattr(const char __user *path
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);
@@ -539,7 +542,7 @@ sys_fremovexattr(int fd, const char __us
audit_inode(NULL, dentry);
error = mnt_want_write(f->f_path.mnt);
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);
@@ -1671,15 +1672,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);
@@ -2110,9 +2112,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,
@@ -2124,22 +2127,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
@@ -413,7 +413,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))
@@ -427,7 +427,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
@@ -482,12 +482,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,
@@ -501,26 +501,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
@@ -2713,7 +2713,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;
@@ -2795,18 +2795,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;
@@ -617,7 +618,8 @@ static int smack_inode_setxattr(struct d
if (!capable(CAP_MAC_ADMIN))
rc = -EPERM;
} 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);
@@ -673,11 +675,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);
}
@@ -687,13 +690,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;
@@ -703,7 +707,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);

View file

@ -0,0 +1,63 @@
securit_default.diff
security-create.diff
remove_suid.diff
vfs-notify_change.diff
security-setattr.diff
vfs-mkdir.diff
security-mkdir.diff
vfs-mknod.diff
security-mknod.diff
vfs-symlink.diff
security-symlink.diff
security-readlink.diff
vfs-link.diff
security-link.diff
vfs-rmdir.diff
security-rmdir.diff
fix-vfs_rmdir.diff
vfs-unlink.diff
security-unlink.diff
vfs-rename.diff
security-rename.diff
vfs-setxattr.diff
security-setxattr.diff
vfs-getxattr.diff
security-getxattr.diff
vfs-listxattr.diff
security-listxattr.diff
vfs-removexattr.diff
security-removexattr.diff
unambiguous-__d_path.diff
d_namespace_path.diff
fsetattr.diff
fsetattr-reintro-ATTR_FILE.diff
fsetattr-restore-ia_file.diff
file-handle-ops.diff
security-xattr-file.diff
sysctl-pathname.diff
add-security_path_permission
add-path_permission.diff
do_path_lookup-nameidata.diff
apparmor-audit.diff
apparmor-main.diff
apparmor-lsm.diff
apparmor-path_permission
apparmor-module_interface.diff
apparmor-misc.diff
apparmor-intree.diff
apparmor-network.diff
apparmor-rlimits.diff
apparmor-2.6.25.diff
apparmor-ptrace-2.6.27.diff
export-security_inode_permission-for-aufs
#aufs/aa-hack
#aufs/aufs-fsetattr
fix-security-param.diff
fix-complain.diff
fix-d_namespace_path.diff
fork-tracking.diff
mount-capability.diff
fix-config.diff
AppArmor-checkpatch.diff
AppArmor-misc-cleanups.diff

View 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
@@ -1528,6 +1528,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
@@ -1814,40 +1814,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;

View file

@ -0,0 +1,258 @@
From: Andreas Gruenbacher <agruen@suse.de>
Subject: Fix __d_path() for lazy unmounts and make it unambiguous
First, when __d_path() hits a lazily unmounted mount point, it tries to prepend
the name of the lazily unmounted dentry to the path name. It gets this wrong,
and also overwrites the slash that separates the name from the following
pathname component. This patch fixes that; if a process was in directory
/foo/bar and /foo got lazily unmounted, the old result was ``foobar'' (note the
missing slash), while the new result with this patch is ``foo/bar''.
Second, it isn't always possible to tell from the __d_path() result whether the
specified root and rootmnt (i.e., the chroot) was reached. We need an
unambiguous result for AppArmor at least though, so we make sure that paths
will only start with a slash if the path leads all the way up to the root.
We also add a @fail_deleted argument, which allows to get rid of some of the
mess in sys_getcwd().
This patch leaves getcwd() and d_path() as they were before for everything
except for bind-mounted directories; for them, it reports ``/foo/bar'' instead
of ``foobar'' in the example described above.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: John Johansen <jjohansen@suse.de>
Acked-by: Alan Cox <alan@lxorguk.ukuu.org.uk>
---
fs/dcache.c | 126 +++++++++++++++++++++++++++----------------------
fs/seq_file.c | 4 -
include/linux/dcache.h | 5 +
3 files changed, 75 insertions(+), 60 deletions(-)
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1907,44 +1907,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(&vfsmount_lock);
- prepend(&end, &buflen, "\0", 1);
- if (!IS_ROOT(dentry) && d_unhashed(dentry) &&
- (prepend(&end, &buflen, " (deleted)", 10) != 0))
+ spin_lock(&dcache_lock);
+ 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;
}
@@ -1954,27 +1956,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(&dcache_lock);
spin_unlock(&vfsmount_lock);
- return retval;
+ 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;
}
@@ -2011,10 +2037,8 @@ char *d_path(const struct path *path, ch
root = current->fs->root;
path_get(&root);
read_unlock(&current->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;
}
@@ -2097,9 +2121,9 @@ Elong:
*/
asmlinkage long sys_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;
@@ -2111,30 +2135,20 @@ asmlinkage long sys_getcwd(char __user *
path_get(&root);
read_unlock(&current->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);
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -412,9 +412,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);
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -300,9 +300,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);

View file

@ -0,0 +1,191 @@
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
@@ -1458,7 +1458,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
@@ -407,12 +407,13 @@ 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;
ssize_t ret;
- buflen = vfs_getxattr(dentry, key, NULL, 0);
+ buflen = vfs_getxattr(dentry, mnt, key, NULL, 0);
if (buflen <= 0)
return buflen;
@@ -420,7 +421,7 @@ static ssize_t nfsd_getxattr(struct dent
if (!*buf)
return -ENOMEM;
- ret = vfs_getxattr(dentry, key, *buf, buflen);
+ ret = vfs_getxattr(dentry, mnt, key, *buf, buflen);
if (ret < 0)
kfree(*buf);
return ret;
@@ -504,13 +505,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)
@@ -522,14 +523,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)) {
@@ -539,7 +541,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)) {
@@ -2159,7 +2161,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;
@@ -315,8 +316,8 @@ sys_fsetxattr(int fd, const char __user
* 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;
@@ -336,7 +337,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;
@@ -359,7 +360,7 @@ sys_getxattr(const char __user *pathname
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;
}
@@ -374,7 +375,7 @@ sys_lgetxattr(const char __user *pathnam
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;
}
@@ -389,7 +390,7 @@ sys_fgetxattr(int fd, const char __user
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
@@ -86,7 +86,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 *);

View 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
@@ -2366,7 +2366,7 @@ asmlinkage long sys_symlink(const char _
return sys_symlinkat(oldname, AT_FDCWD, newname);
}
-int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
+int vfs_link(struct dentry *old_dentry, struct vfsmount *old_mnt, struct inode *dir, struct dentry *new_dentry, struct vfsmount *new_mnt)
{
struct inode *inode = old_dentry->d_inode;
int error;
@@ -2445,7 +2445,9 @@ asmlinkage long sys_linkat(int olddfd, c
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
@@ -1625,7 +1625,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
@@ -1208,7 +1208,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 *);

View 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;
}
@@ -399,7 +401,8 @@ sys_fgetxattr(int fd, const char __user
* 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;
@@ -412,7 +415,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;
@@ -434,7 +437,7 @@ sys_listxattr(const char __user *pathnam
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;
}
@@ -448,7 +451,7 @@ sys_llistxattr(const char __user *pathna
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;
}
@@ -463,7 +466,7 @@ sys_flistxattr(int fd, char __user *list
if (!f)
return error;
audit_inode(NULL, f->f_path.dentry);
- error = listxattr(f->f_path.dentry, list, size);
+ error = listxattr(f->f_path.dentry, f->f_path.mnt, list, size);
fput(f);
return error;
}
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -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 *);

View 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
@@ -2025,7 +2025,8 @@ asmlinkage long sys_mknod(const char __u
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);
@@ -2068,7 +2069,7 @@ asmlinkage long sys_mkdirat(int dfd, con
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.mnt);
if (status)
goto out_put;
- status = vfs_mkdir(rec_dir.dentry->d_inode, dentry, S_IRWXU);
+ status = vfs_mkdir(rec_dir.dentry->d_inode, dentry, rec_dir.mnt,
+ S_IRWXU);
mnt_drop_write(rec_dir.mnt);
out_put:
dput(dentry);
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1190,6 +1190,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;
@@ -1207,6 +1208,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;
@@ -1223,7 +1225,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 {
@@ -1273,7 +1275,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:
@@ -1287,7 +1289,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
@@ -1205,7 +1205,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
@@ -2966,7 +2966,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) {

View 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
@@ -1924,7 +1924,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);
@@ -2002,11 +2003,12 @@ asmlinkage long sys_mknodat(int dfd, con
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
@@ -1281,7 +1281,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
@@ -1206,7 +1206,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
@@ -829,7 +829,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;

View file

@ -0,0 +1,321 @@
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/reiserfs/xattr.c | 6 +++---
fs/utimes.c | 2 +-
include/linux/fs.h | 6 +++---
mm/filemap.c | 2 +-
11 files changed, 36 insertions(+), 30 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
@@ -849,6 +849,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;
@@ -859,6 +860,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);
@@ -910,7 +912,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
@@ -1821,7 +1821,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
@@ -1557,7 +1557,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
@@ -387,7 +387,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);
err = nfserrno(host_err);
fh_unlock(fhp);
}
@@ -947,13 +947,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);
}
@@ -1012,7 +1012,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
@@ -197,8 +197,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;
@@ -218,7 +218,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;
}
@@ -274,7 +274,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:
@@ -329,7 +329,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:
@@ -605,7 +606,7 @@ asmlinkage long sys_fchmod(unsigned int
mode = inode->i_mode;
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
- err = notify_change(dentry, &newattrs);
+ err = notify_change(dentry, file->f_path.mnt, &newattrs);
mutex_unlock(&inode->i_mutex);
mnt_drop_write(file->f_path.mnt);
out_putf:
@@ -635,7 +636,7 @@ asmlinkage long sys_fchmodat(int dfd, co
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:
@@ -649,7 +650,8 @@ asmlinkage long sys_chmod(const char __u
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;
@@ -668,7 +670,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;
@@ -685,7 +687,7 @@ asmlinkage long sys_chown(const char __u
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);
@@ -710,7 +712,7 @@ asmlinkage long sys_fchownat(int dfd, co
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);
@@ -729,7 +731,7 @@ asmlinkage long sys_lchown(const char __
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);
@@ -753,7 +755,7 @@ asmlinkage long sys_fchown(unsigned int
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/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -459,7 +459,7 @@ reiserfs_xattr_set(struct inode *inode,
newattrs.ia_size = buffer_size;
newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
mutex_lock_nested(&xinode->i_mutex, I_MUTEX_XATTR);
- err = notify_change(dentry, &newattrs);
+ err = notify_change(dentry, NULL, &newattrs);
if (err)
goto out_filp;
@@ -790,7 +790,7 @@ reiserfs_chown_xattrs_filler(void *buf,
}
if (!S_ISDIR(xafile->d_inode->i_mode))
- err = notify_change(xafile, attrs);
+ err = notify_change(xafile, NULL, attrs);
dput(xafile);
return err;
@@ -834,7 +834,7 @@ int reiserfs_chown_xattrs(struct inode *
goto out_dir;
}
- err = notify_change(dir, attrs);
+ err = notify_change(dir, NULL, attrs);
unlock_kernel();
out_dir:
--- 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
@@ -1669,8 +1669,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);
@@ -1830,7 +1830,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
@@ -1778,7 +1778,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)

View 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(-)
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -2174,6 +2174,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;
@@ -2206,22 +2207,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);
--- a/fs/xattr.c
+++ b/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;
@@ -475,7 +475,7 @@ sys_flistxattr(int fd, char __user *list
* 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];
@@ -486,7 +486,7 @@ removexattr(struct dentry *d, const char
if (error < 0)
return error;
- return vfs_removexattr(d, kname);
+ return vfs_removexattr(dentry, mnt, kname);
}
asmlinkage long
@@ -500,7 +500,7 @@ sys_removexattr(const char __user *pathn
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);
@@ -518,7 +518,7 @@ sys_lremovexattr(const char __user *path
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);
@@ -539,7 +539,7 @@ sys_fremovexattr(int fd, const char __us
audit_inode(NULL, dentry);
error = mnt_want_write(f->f_path.mnt);
if (!error) {
- error = removexattr(dentry, name);
+ error = removexattr(dentry, f->f_path.mnt, name);
mnt_drop_write(f->f_path.mnt);
}
fput(f);
--- a/include/linux/xattr.h
+++ b/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);

View 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
@@ -2502,7 +2502,8 @@ asmlinkage long sys_link(const char __us
* 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;
@@ -2545,7 +2546,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;
@@ -2573,7 +2575,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);
@@ -2602,9 +2605,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,
@@ -2685,8 +2690,8 @@ asmlinkage long sys_renameat(int olddfd,
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
@@ -1727,7 +1727,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
@@ -1211,7 +1211,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.

View file

@ -0,0 +1,135 @@
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 +++++---
fs/reiserfs/xattr.c | 2 +-
include/linux/fs.h | 2 +-
6 files changed, 13 insertions(+), 9 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
@@ -2115,7 +2115,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);
@@ -2181,7 +2181,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
@@ -1765,6 +1765,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;
@@ -1779,6 +1780,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);
@@ -1800,21 +1802,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/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -746,7 +746,7 @@ int reiserfs_delete_xattrs(struct inode
if (dir->d_inode->i_nlink <= 2) {
root = get_xa_root(inode->i_sb, XATTR_REPLACE);
reiserfs_write_lock_xattrs(inode->i_sb);
- err = vfs_rmdir(root->d_inode, dir);
+ err = vfs_rmdir(root->d_inode, dir, NULL);
reiserfs_write_unlock_xattrs(inode->i_sb);
dput(root);
} else {
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1209,7 +1209,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 *);

View 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(-)
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -429,7 +429,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;
@@ -448,7 +449,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;
@@ -461,6 +462,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;
@@ -471,6 +473,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;
@@ -481,12 +484,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);
@@ -2202,7 +2207,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;
--- a/fs/xattr.c
+++ b/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 @@ sys_setxattr(const char __user *pathname
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 @@ sys_lsetxattr(const char __user *pathnam
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);
@@ -304,7 +304,7 @@ sys_fsetxattr(int fd, const char __user
audit_inode(NULL, dentry);
error = mnt_want_write(f->f_path.mnt);
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);
--- a/include/linux/xattr.h
+++ b/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);

View 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
@@ -2301,7 +2301,8 @@ asmlinkage long sys_unlink(const char __
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);
@@ -2347,7 +2348,7 @@ asmlinkage long sys_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
@@ -1520,6 +1520,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;
@@ -1544,6 +1545,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)
@@ -1551,14 +1553,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);
@@ -1566,7 +1570,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
@@ -1207,7 +1207,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 *);

View 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
@@ -2199,7 +2199,7 @@ asmlinkage long sys_rmdir(const char __u
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);
@@ -2267,7 +2267,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
@@ -1807,7 +1807,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
@@ -1210,7 +1210,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
@@ -753,7 +753,7 @@ asmlinkage long sys_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);