diff --git a/fs/xattr.c b/fs/xattr.c
index b3444e06cded..f2b6af1719fd 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -570,6 +570,7 @@ setxattr(struct user_namespace *mnt_userns, struct dentry *d,
posix_acl_fix_xattr_from_user(mnt_userns, kvalue, size);
}
+ audit_xattr(name, value, flags);
error = vfs_setxattr(mnt_userns, d, kname, kvalue, size, flags);
out:
kvfree(kvalue);
@@ -816,6 +817,7 @@ removexattr(struct user_namespace *mnt_userns, struct dentry *d,
if (error < 0)
return error;
+ audit_xattr(name, "(null)", 0);
return vfs_removexattr(mnt_userns, d, kname);
}
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 82b7c1116a85..784d34888c8a 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -404,6 +404,7 @@ extern void __audit_tk_injoffset(struct timespec64 offset);
extern void __audit_ntp_log(const struct audit_ntp_data *ad);
extern void __audit_log_nfcfg(const char *name, u8 af, unsigned int nentries,
enum audit_nfcfgop op, gfp_t gfp);
+extern void __audit_xattr(const char *name, const char *value, int flags);
static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp)
{@@ -547,6 +548,12 @@ static inline void audit_log_nfcfg(const char *name, u8 af,
__audit_log_nfcfg(name, af, nentries, op, gfp);
}
+static inline void audit_xattr(const char *name, const char *value, int flags)
+{
+ if (!audit_dummy_context())
+ __audit_xattr(name, value, flags);
+}
+
extern int audit_n_rules;
extern int audit_signals;
#else /* CONFIG_AUDITSYSCALL */@@ -677,6 +684,9 @@ static inline void audit_log_nfcfg(const char *name, u8 af,
enum audit_nfcfgop op, gfp_t gfp)
{ }
+static inline void audit_xattr(const char *name, const char *value, int flags)
+{ }
+
#define audit_n_rules 0
#define audit_signals 0
#endif /* CONFIG_AUDITSYSCALL */diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
index cd2d8279a5e4..4477ff80a24d 100644
--- a/include/uapi/linux/audit.h
+++ b/include/uapi/linux/audit.h
@@ -118,6 +118,7 @@
#define AUDIT_TIME_ADJNTPVAL 1333 /* NTP value adjustment */
#define AUDIT_BPF 1334 /* BPF subsystem */
#define AUDIT_EVENT_LISTENER 1335 /* Task joined multicast read socket */
+#define AUDIT_XATTR 1336 /* xattr arguments */
#define AUDIT_AVC 1400 /* SE Linux avc denial or grant */
#define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */
diff --git a/kernel/audit.h b/kernel/audit.h
index 1522e100fd17..9544284fce57 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -191,6 +191,11 @@ struct audit_context {
struct {
char *name;
} module;
+ struct {
+ char *name;
+ char *value;
+ int flags;
+ } xattr;
};
int fds[2];
struct audit_proctitle proctitle;diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 8bb9ac84d2fb..7f2b56136fa4 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -884,6 +884,7 @@ static inline void audit_free_module(struct audit_context *context)
context->module.name = NULL;
}
}
+
static inline void audit_free_names(struct audit_context *context)
{
struct audit_names *n, *next;@@ -915,6 +916,16 @@ static inline void audit_free_aux(struct audit_context *context)
}
}
+static inline void audit_free_xattr(struct audit_context *context)
+{
+ if (context->type == AUDIT_XATTR) {
+ kfree(context->xattr.name);
+ context->xattr.name = NULL;
+ kfree(context->xattr.value);
+ context->xattr.value = NULL;
+ }
+}
+
static inline struct audit_context *audit_alloc_context(enum audit_state state)
{
struct audit_context *context;@@ -969,6 +980,7 @@ int audit_alloc(struct task_struct *tsk)
static inline void audit_free_context(struct audit_context *context)
{
+ audit_free_xattr(context);
audit_free_module(context);
audit_free_names(context);
unroll_tree_refs(context, NULL, 0);@@ -1317,6 +1329,20 @@ static void show_special(struct audit_context *context, int *call_panic)
} else
audit_log_format(ab, "(null)");
+ break;
+ case AUDIT_XATTR:
+ audit_log_format(ab, "xattr=");
+ if (context->xattr.name)
+ audit_log_untrustedstring(ab, context->xattr.name);
+ else
+ audit_log_format(ab, "(null)");
+ audit_log_format(ab, " val=");
+ if (context->xattr.value)
+ audit_log_untrustedstring(ab, context->xattr.value);
+ else
+ audit_log_format(ab, "(null)");
+ audit_log_format(ab, " xflags=0x%x", context->xattr.flags);
+
break;
}
audit_log_end(ab);
@@ -1742,6 +1768,7 @@ void __audit_syscall_exit(int success, long return_code)
context->in_syscall = 0;
context->prio = context->state == AUDIT_RECORD_CONTEXT ? ~0ULL : 0;
+ audit_free_xattr(context);
audit_free_module(context);
audit_free_names(context);
unroll_tree_refs(context, NULL, 0);
@@ -2536,6 +2563,24 @@ void __audit_log_kern_module(char *name)
context->type = AUDIT_KERN_MODULE;
}
+void __audit_xattr(const char *name, const char *value, int flags)
+{
+ struct audit_context *context = audit_context();
+
+ context->type = AUDIT_XATTR;
+ context->xattr.flags = flags;
+ context->xattr.name = kstrdup(name, GFP_KERNEL);
+ if (!context->xattr.name)
+ goto out;
+ context->xattr.value = kstrdup(value, GFP_KERNEL);
+ if (!context->xattr.value)
+ goto out;
+ return;
+out:
+ kfree(context->xattr.name);
+ audit_log_lost("out of memory in __audit_xattr");
+}
+
void __audit_fanotify(unsigned int response)
{
audit_log(audit_context(), GFP_KERNEL,