[PATCH] audit: add FSCONFIG auxiliary record to log filesystem configuration

Ricardo Robaina posted 1 patch 1 week, 5 days ago
fs/fsopen.c                |  7 +++++++
include/linux/audit.h      | 13 +++++++++++++
include/uapi/linux/audit.h |  1 +
kernel/auditsc.c           | 27 +++++++++++++++++++++++++++
4 files changed, 48 insertions(+)
[PATCH] audit: add FSCONFIG auxiliary record to log filesystem configuration
Posted by Ricardo Robaina 1 week, 5 days ago
Modern mount tools (util-linux >= 2.39.1) use the new mount API
(fsopen, fsconfig, fsmount, move_mount) instead of the legacy mount(2)
syscall. The generic SYSCALL audit record logs the fsconfig syscall but
does not capture the configuration parameters, creating an audit gap for
critical mount information such as the device being mounted.

Add an FSCONFIG auxiliary record that logs the command type, parameter
name (key), parameter value, and aux parameter passed to fsconfig(2).

 ----
 type=SYSCALL : syscall=fsconfig a1=FSCONFIG_SET_STRING ...
 type=FSCONFIG : fs_cmd=1 fs_key=source fs_val="tmpfs" fs_aux=0
 ----
 type=SYSCALL : syscall=fsconfig a1=FSCONFIG_CMD_CREATE ...
 type=FSCONFIG : fs_cmd=6 fs_key=(null) fs_val=(null) fs_aux=0
 ----
 type=SYSCALL : syscall=fsconfig a0=0x4 a1=FSCONFIG_SET_BINARY ...
 type=FSCONFIG : fs_cmd=2 fs_key=hidepid fs_val="<binary>" fs_aux=4

Link: https://github.com/linux-audit/audit-kernel/issues/153
Signed-off-by: Ricardo Robaina <rrobaina@redhat.com>
---
 fs/fsopen.c                |  7 +++++++
 include/linux/audit.h      | 13 +++++++++++++
 include/uapi/linux/audit.h |  1 +
 kernel/auditsc.c           | 27 +++++++++++++++++++++++++++
 4 files changed, 48 insertions(+)

diff --git a/fs/fsopen.c b/fs/fsopen.c
index ae19e5136598..9b3c02f59df4 100644
--- a/fs/fsopen.c
+++ b/fs/fsopen.c
@@ -15,6 +15,7 @@
 #include <linux/namei.h>
 #include <linux/file.h>
 #include <uapi/linux/mount.h>
+#include <linux/audit.h>
 #include "internal.h"
 #include "mount.h"
 
@@ -357,6 +358,7 @@ SYSCALL_DEFINE5(fsconfig,
 	struct fs_context *fc;
 	int ret;
 	int lookup_flags = 0;
+	const char *value_str = NULL;
 
 	struct fs_parameter param = {
 		.type	= fs_value_is_undefined,
@@ -423,6 +425,7 @@ SYSCALL_DEFINE5(fsconfig,
 			goto out_key;
 		}
 		param.size = strlen(param.string);
+		value_str = param.string;
 		break;
 	case FSCONFIG_SET_BINARY:
 		param.type = fs_value_is_blob;
@@ -432,6 +435,7 @@ SYSCALL_DEFINE5(fsconfig,
 			ret = PTR_ERR(param.blob);
 			goto out_key;
 		}
+		value_str = "<binary>";
 		break;
 	case FSCONFIG_SET_PATH_EMPTY:
 		lookup_flags = LOOKUP_EMPTY;
@@ -445,6 +449,7 @@ SYSCALL_DEFINE5(fsconfig,
 		}
 		param.dirfd = aux;
 		param.size = strlen(param.name->name);
+		value_str = param.name->name;
 		break;
 	case FSCONFIG_SET_FD:
 		param.type = fs_value_is_file;
@@ -458,6 +463,8 @@ SYSCALL_DEFINE5(fsconfig,
 		break;
 	}
 
+	audit_log_fsconfig(cmd, param.key, value_str, aux);
+
 	ret = mutex_lock_interruptible(&fc->uapi_mutex);
 	if (ret == 0) {
 		ret = vfs_fsconfig_locked(fc, cmd, &param);
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 45abb3722d30..978eb881974c 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -449,6 +449,8 @@ 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_log_fsconfig(unsigned int cmd, const char *key,
+				 const char *value, int aux);
 
 static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp)
 {
@@ -598,6 +600,13 @@ static inline void audit_log_nfcfg(const char *name, u8 af,
 		__audit_log_nfcfg(name, af, nentries, op, gfp);
 }
 
+static inline void audit_log_fsconfig(unsigned int cmd, const char *key,
+				      const char *value, int aux)
+{
+	if (!audit_dummy_context())
+		__audit_log_fsconfig(cmd, key, value, aux);
+}
+
 extern int audit_n_rules;
 extern int audit_signals;
 #else /* CONFIG_AUDITSYSCALL */
@@ -730,6 +739,10 @@ static inline void audit_log_nfcfg(const char *name, u8 af,
 				   enum audit_nfcfgop op, gfp_t gfp)
 { }
 
+static inline void audit_log_fsconfig(unsigned int cmd, const char *key,
+				      const char *value, int aux)
+{ }
+
 #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 e8f5ce677df7..5cd0eb602528 100644
--- a/include/uapi/linux/audit.h
+++ b/include/uapi/linux/audit.h
@@ -122,6 +122,7 @@
 #define AUDIT_OPENAT2		1337	/* Record showing openat2 how args */
 #define AUDIT_DM_CTRL		1338	/* Device Mapper target control */
 #define AUDIT_DM_EVENT		1339	/* Device Mapper events */
+#define AUDIT_FSCONFIG		1341	/* Record showing fsconfig args */
 
 #define AUDIT_AVC		1400	/* SE Linux avc denial or grant */
 #define AUDIT_SELINUX_ERR	1401	/* Internal SE Linux Errors */
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 6610e667c728..222bf79ee9bd 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2882,6 +2882,33 @@ void __audit_log_nfcfg(const char *name, u8 af, unsigned int nentries,
 }
 EXPORT_SYMBOL_GPL(__audit_log_nfcfg);
 
+void __audit_log_fsconfig(unsigned int cmd, const char *key,
+			  const char *value, int aux)
+{
+	struct audit_buffer *ab;
+
+	ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_FSCONFIG);
+	if (!ab)
+		return;
+
+	audit_log_format(ab, "fs_cmd=%u", cmd);
+	audit_log_format(ab, " fs_key=");
+	if (value)
+		audit_log_untrustedstring(ab, key);
+	else
+		audit_log_format(ab, "(null)");
+
+	audit_log_format(ab, " fs_val=");
+	if (value)
+		audit_log_untrustedstring(ab, value);
+	else
+		audit_log_format(ab, "(null)");
+
+	audit_log_format(ab, " fs_aux=%d", aux);
+
+	audit_log_end(ab);
+}
+
 static void audit_log_task(struct audit_buffer *ab)
 {
 	kuid_t auid, uid;
-- 
2.53.0
Re: [PATCH] audit: add FSCONFIG auxiliary record to log filesystem configuration
Posted by Christian Brauner 3 days, 6 hours ago
On 2026-07-13 14:00 -0300, Ricardo Robaina wrote:
> Modern mount tools (util-linux >= 2.39.1) use the new mount API
> (fsopen, fsconfig, fsmount, move_mount) instead of the legacy mount(2)
> syscall. The generic SYSCALL audit record logs the fsconfig syscall but
> does not capture the configuration parameters, creating an audit gap for
> critical mount information such as the device being mounted.
> 
> Add an FSCONFIG auxiliary record that logs the command type, parameter
> name (key), parameter value, and aux parameter passed to fsconfig(2).
> 
>  ----
>  type=SYSCALL : syscall=fsconfig a1=FSCONFIG_SET_STRING ...
>  type=FSCONFIG : fs_cmd=1 fs_key=source fs_val="tmpfs" fs_aux=0
>  ----
>  type=SYSCALL : syscall=fsconfig a1=FSCONFIG_CMD_CREATE ...
>  type=FSCONFIG : fs_cmd=6 fs_key=(null) fs_val=(null) fs_aux=0
>  ----
>  type=SYSCALL : syscall=fsconfig a0=0x4 a1=FSCONFIG_SET_BINARY ...
>  type=FSCONFIG : fs_cmd=2 fs_key=hidepid fs_val="<binary>" fs_aux=4
> 
> Link: https://github.com/linux-audit/audit-kernel/issues/153
> Signed-off-by: Ricardo Robaina <rrobaina@redhat.com>
> ---

Acked-by: Christian Brauner <brauner@kernel.org>
Re: [PATCH] audit: add FSCONFIG auxiliary record to log filesystem configuration
Posted by Richard Guy Briggs 3 days, 22 hours ago
On 2026-07-13 14:00, Ricardo Robaina wrote:
> Modern mount tools (util-linux >= 2.39.1) use the new mount API
> (fsopen, fsconfig, fsmount, move_mount) instead of the legacy mount(2)
> syscall. The generic SYSCALL audit record logs the fsconfig syscall but
> does not capture the configuration parameters, creating an audit gap for
> critical mount information such as the device being mounted.
> 
> Add an FSCONFIG auxiliary record that logs the command type, parameter
> name (key), parameter value, and aux parameter passed to fsconfig(2).
> 
>  ----
>  type=SYSCALL : syscall=fsconfig a1=FSCONFIG_SET_STRING ...

This looks like it is missing "a0=..."?

>  type=FSCONFIG : fs_cmd=1 fs_key=source fs_val="tmpfs" fs_aux=0
>  ----
>  type=SYSCALL : syscall=fsconfig a1=FSCONFIG_CMD_CREATE ...

This looks like it is missing "a0=..."?
I'm guessing this isn't actually real test output?

>  type=FSCONFIG : fs_cmd=6 fs_key=(null) fs_val=(null) fs_aux=0

Was there a fs_key output here that didn't make it due to the issue below?

>  ----
>  type=SYSCALL : syscall=fsconfig a0=0x4 a1=FSCONFIG_SET_BINARY ...
>  type=FSCONFIG : fs_cmd=2 fs_key=hidepid fs_val="<binary>" fs_aux=4
> 
> Link: https://github.com/linux-audit/audit-kernel/issues/153
> Signed-off-by: Ricardo Robaina <rrobaina@redhat.com>
> ---
>  fs/fsopen.c                |  7 +++++++
>  include/linux/audit.h      | 13 +++++++++++++
>  include/uapi/linux/audit.h |  1 +
>  kernel/auditsc.c           | 27 +++++++++++++++++++++++++++
>  4 files changed, 48 insertions(+)
> 
> diff --git a/fs/fsopen.c b/fs/fsopen.c
> index ae19e5136598..9b3c02f59df4 100644
> --- a/fs/fsopen.c
> +++ b/fs/fsopen.c
> @@ -15,6 +15,7 @@
>  #include <linux/namei.h>
>  #include <linux/file.h>
>  #include <uapi/linux/mount.h>
> +#include <linux/audit.h>
>  #include "internal.h"
>  #include "mount.h"
>  
> @@ -357,6 +358,7 @@ SYSCALL_DEFINE5(fsconfig,
>  	struct fs_context *fc;
>  	int ret;
>  	int lookup_flags = 0;
> +	const char *value_str = NULL;
>  
>  	struct fs_parameter param = {
>  		.type	= fs_value_is_undefined,
> @@ -423,6 +425,7 @@ SYSCALL_DEFINE5(fsconfig,
>  			goto out_key;
>  		}
>  		param.size = strlen(param.string);
> +		value_str = param.string;
>  		break;
>  	case FSCONFIG_SET_BINARY:
>  		param.type = fs_value_is_blob;
> @@ -432,6 +435,7 @@ SYSCALL_DEFINE5(fsconfig,
>  			ret = PTR_ERR(param.blob);
>  			goto out_key;
>  		}
> +		value_str = "<binary>";
>  		break;
>  	case FSCONFIG_SET_PATH_EMPTY:
>  		lookup_flags = LOOKUP_EMPTY;
> @@ -445,6 +449,7 @@ SYSCALL_DEFINE5(fsconfig,
>  		}
>  		param.dirfd = aux;
>  		param.size = strlen(param.name->name);
> +		value_str = param.name->name;
>  		break;
>  	case FSCONFIG_SET_FD:
>  		param.type = fs_value_is_file;
> @@ -458,6 +463,8 @@ SYSCALL_DEFINE5(fsconfig,
>  		break;
>  	}
>  
> +	audit_log_fsconfig(cmd, param.key, value_str, aux);
> +
>  	ret = mutex_lock_interruptible(&fc->uapi_mutex);
>  	if (ret == 0) {
>  		ret = vfs_fsconfig_locked(fc, cmd, &param);
> diff --git a/include/linux/audit.h b/include/linux/audit.h
> index 45abb3722d30..978eb881974c 100644
> --- a/include/linux/audit.h
> +++ b/include/linux/audit.h
> @@ -449,6 +449,8 @@ 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_log_fsconfig(unsigned int cmd, const char *key,
> +				 const char *value, int aux);
>  
>  static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp)
>  {
> @@ -598,6 +600,13 @@ static inline void audit_log_nfcfg(const char *name, u8 af,
>  		__audit_log_nfcfg(name, af, nentries, op, gfp);
>  }
>  
> +static inline void audit_log_fsconfig(unsigned int cmd, const char *key,
> +				      const char *value, int aux)
> +{
> +	if (!audit_dummy_context())
> +		__audit_log_fsconfig(cmd, key, value, aux);
> +}
> +
>  extern int audit_n_rules;
>  extern int audit_signals;
>  #else /* CONFIG_AUDITSYSCALL */
> @@ -730,6 +739,10 @@ static inline void audit_log_nfcfg(const char *name, u8 af,
>  				   enum audit_nfcfgop op, gfp_t gfp)
>  { }
>  
> +static inline void audit_log_fsconfig(unsigned int cmd, const char *key,
> +				      const char *value, int aux)
> +{ }
> +
>  #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 e8f5ce677df7..5cd0eb602528 100644
> --- a/include/uapi/linux/audit.h
> +++ b/include/uapi/linux/audit.h
> @@ -122,6 +122,7 @@
>  #define AUDIT_OPENAT2		1337	/* Record showing openat2 how args */
>  #define AUDIT_DM_CTRL		1338	/* Device Mapper target control */
>  #define AUDIT_DM_EVENT		1339	/* Device Mapper events */
> +#define AUDIT_FSCONFIG		1341	/* Record showing fsconfig args */
>  
>  #define AUDIT_AVC		1400	/* SE Linux avc denial or grant */
>  #define AUDIT_SELINUX_ERR	1401	/* Internal SE Linux Errors */
> diff --git a/kernel/auditsc.c b/kernel/auditsc.c
> index 6610e667c728..222bf79ee9bd 100644
> --- a/kernel/auditsc.c
> +++ b/kernel/auditsc.c
> @@ -2882,6 +2882,33 @@ void __audit_log_nfcfg(const char *name, u8 af, unsigned int nentries,
>  }
>  EXPORT_SYMBOL_GPL(__audit_log_nfcfg);
>  
> +void __audit_log_fsconfig(unsigned int cmd, const char *key,
> +			  const char *value, int aux)
> +{
> +	struct audit_buffer *ab;
> +
> +	ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_FSCONFIG);
> +	if (!ab)
> +		return;
> +
> +	audit_log_format(ab, "fs_cmd=%u", cmd);
> +	audit_log_format(ab, " fs_key=");
> +	if (value)

This looks like it should be "if (key)".

> +		audit_log_untrustedstring(ab, key);
> +	else
> +		audit_log_format(ab, "(null)");
> +
> +	audit_log_format(ab, " fs_val=");
> +	if (value)
> +		audit_log_untrustedstring(ab, value);
> +	else
> +		audit_log_format(ab, "(null)");
> +
> +	audit_log_format(ab, " fs_aux=%d", aux);
> +
> +	audit_log_end(ab);
> +}
> +
>  static void audit_log_task(struct audit_buffer *ab)
>  {
>  	kuid_t auid, uid;
> -- 
> 2.53.0

- RGB

--
Richard Guy Briggs <rgb@redhat.com>
Sr. S/W Engineer, Kernel Security, Base Operating Systems
Remote, Ottawa, Red Hat Canada
Upstream IRC: SunRaycer
Voice: +1.613.860 2354 SMS: +1.613.518.6570
Re: [PATCH] audit: add FSCONFIG auxiliary record to log filesystem configuration
Posted by Ricardo Robaina 3 days, 7 hours ago
On Tue, Jul 21, 2026 at 7:18 PM Richard Guy Briggs <rgb@redhat.com> wrote:
>
> On 2026-07-13 14:00, Ricardo Robaina wrote:
> > Modern mount tools (util-linux >= 2.39.1) use the new mount API
> > (fsopen, fsconfig, fsmount, move_mount) instead of the legacy mount(2)
> > syscall. The generic SYSCALL audit record logs the fsconfig syscall but
> > does not capture the configuration parameters, creating an audit gap for
> > critical mount information such as the device being mounted.
> >
> > Add an FSCONFIG auxiliary record that logs the command type, parameter
> > name (key), parameter value, and aux parameter passed to fsconfig(2).
> >
> >  ----
> >  type=SYSCALL : syscall=fsconfig a1=FSCONFIG_SET_STRING ...
>
> This looks like it is missing "a0=..."?
>
> >  type=FSCONFIG : fs_cmd=1 fs_key=source fs_val="tmpfs" fs_aux=0
> >  ----
> >  type=SYSCALL : syscall=fsconfig a1=FSCONFIG_CMD_CREATE ...
>
> This looks like it is missing "a0=..."?
> I'm guessing this isn't actually real test output?
>

Thanks for reviewing this patch, Richard!

That's real test output; I just trimmed the SYSCALL record output to
fit in the commit message. Since this patch does not touch this
record, I don't see a problem. I can
add a0=... for consistency if you prefer, though.

> >  type=FSCONFIG : fs_cmd=6 fs_key=(null) fs_val=(null) fs_aux=0
>
> Was there a fs_key output here that didn't make it due to the issue below?

Actually, in this case, the test result happened to be right (that's
why I missed it).
FSCONFIG_CMD_CREATE has no key or value, so both are NULL[1].

[1] https://man7.org/linux/man-pages/man2/fsconfig.2.html

>
> >  ----
> >  type=SYSCALL : syscall=fsconfig a0=0x4 a1=FSCONFIG_SET_BINARY ...
> >  type=FSCONFIG : fs_cmd=2 fs_key=hidepid fs_val="<binary>" fs_aux=4
> >
> > Link: https://github.com/linux-audit/audit-kernel/issues/153
> > Signed-off-by: Ricardo Robaina <rrobaina@redhat.com>
> > ---
> >  fs/fsopen.c                |  7 +++++++
> >  include/linux/audit.h      | 13 +++++++++++++
> >  include/uapi/linux/audit.h |  1 +
> >  kernel/auditsc.c           | 27 +++++++++++++++++++++++++++
> >  4 files changed, 48 insertions(+)
> >
> > diff --git a/fs/fsopen.c b/fs/fsopen.c
> > index ae19e5136598..9b3c02f59df4 100644
> > --- a/fs/fsopen.c
> > +++ b/fs/fsopen.c
> > @@ -15,6 +15,7 @@
> >  #include <linux/namei.h>
> >  #include <linux/file.h>
> >  #include <uapi/linux/mount.h>
> > +#include <linux/audit.h>
> >  #include "internal.h"
> >  #include "mount.h"
> >
> > @@ -357,6 +358,7 @@ SYSCALL_DEFINE5(fsconfig,
> >       struct fs_context *fc;
> >       int ret;
> >       int lookup_flags = 0;
> > +     const char *value_str = NULL;
> >
> >       struct fs_parameter param = {
> >               .type   = fs_value_is_undefined,
> > @@ -423,6 +425,7 @@ SYSCALL_DEFINE5(fsconfig,
> >                       goto out_key;
> >               }
> >               param.size = strlen(param.string);
> > +             value_str = param.string;
> >               break;
> >       case FSCONFIG_SET_BINARY:
> >               param.type = fs_value_is_blob;
> > @@ -432,6 +435,7 @@ SYSCALL_DEFINE5(fsconfig,
> >                       ret = PTR_ERR(param.blob);
> >                       goto out_key;
> >               }
> > +             value_str = "<binary>";
> >               break;
> >       case FSCONFIG_SET_PATH_EMPTY:
> >               lookup_flags = LOOKUP_EMPTY;
> > @@ -445,6 +449,7 @@ SYSCALL_DEFINE5(fsconfig,
> >               }
> >               param.dirfd = aux;
> >               param.size = strlen(param.name->name);
> > +             value_str = param.name->name;
> >               break;
> >       case FSCONFIG_SET_FD:
> >               param.type = fs_value_is_file;
> > @@ -458,6 +463,8 @@ SYSCALL_DEFINE5(fsconfig,
> >               break;
> >       }
> >
> > +     audit_log_fsconfig(cmd, param.key, value_str, aux);
> > +
> >       ret = mutex_lock_interruptible(&fc->uapi_mutex);
> >       if (ret == 0) {
> >               ret = vfs_fsconfig_locked(fc, cmd, &param);
> > diff --git a/include/linux/audit.h b/include/linux/audit.h
> > index 45abb3722d30..978eb881974c 100644
> > --- a/include/linux/audit.h
> > +++ b/include/linux/audit.h
> > @@ -449,6 +449,8 @@ 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_log_fsconfig(unsigned int cmd, const char *key,
> > +                              const char *value, int aux);
> >
> >  static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp)
> >  {
> > @@ -598,6 +600,13 @@ static inline void audit_log_nfcfg(const char *name, u8 af,
> >               __audit_log_nfcfg(name, af, nentries, op, gfp);
> >  }
> >
> > +static inline void audit_log_fsconfig(unsigned int cmd, const char *key,
> > +                                   const char *value, int aux)
> > +{
> > +     if (!audit_dummy_context())
> > +             __audit_log_fsconfig(cmd, key, value, aux);
> > +}
> > +
> >  extern int audit_n_rules;
> >  extern int audit_signals;
> >  #else /* CONFIG_AUDITSYSCALL */
> > @@ -730,6 +739,10 @@ static inline void audit_log_nfcfg(const char *name, u8 af,
> >                                  enum audit_nfcfgop op, gfp_t gfp)
> >  { }
> >
> > +static inline void audit_log_fsconfig(unsigned int cmd, const char *key,
> > +                                   const char *value, int aux)
> > +{ }
> > +
> >  #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 e8f5ce677df7..5cd0eb602528 100644
> > --- a/include/uapi/linux/audit.h
> > +++ b/include/uapi/linux/audit.h
> > @@ -122,6 +122,7 @@
> >  #define AUDIT_OPENAT2                1337    /* Record showing openat2 how args */
> >  #define AUDIT_DM_CTRL                1338    /* Device Mapper target control */
> >  #define AUDIT_DM_EVENT               1339    /* Device Mapper events */
> > +#define AUDIT_FSCONFIG               1341    /* Record showing fsconfig args */
> >
> >  #define AUDIT_AVC            1400    /* SE Linux avc denial or grant */
> >  #define AUDIT_SELINUX_ERR    1401    /* Internal SE Linux Errors */
> > diff --git a/kernel/auditsc.c b/kernel/auditsc.c
> > index 6610e667c728..222bf79ee9bd 100644
> > --- a/kernel/auditsc.c
> > +++ b/kernel/auditsc.c
> > @@ -2882,6 +2882,33 @@ void __audit_log_nfcfg(const char *name, u8 af, unsigned int nentries,
> >  }
> >  EXPORT_SYMBOL_GPL(__audit_log_nfcfg);
> >
> > +void __audit_log_fsconfig(unsigned int cmd, const char *key,
> > +                       const char *value, int aux)
> > +{
> > +     struct audit_buffer *ab;
> > +
> > +     ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_FSCONFIG);
> > +     if (!ab)
> > +             return;
> > +
> > +     audit_log_format(ab, "fs_cmd=%u", cmd);
> > +     audit_log_format(ab, " fs_key=");
> > +     if (value)
>
> This looks like it should be "if (key)".

Good catch!

>
> > +             audit_log_untrustedstring(ab, key);
> > +     else
> > +             audit_log_format(ab, "(null)");
> > +
> > +     audit_log_format(ab, " fs_val=");
> > +     if (value)
> > +             audit_log_untrustedstring(ab, value);
> > +     else
> > +             audit_log_format(ab, "(null)");
> > +
> > +     audit_log_format(ab, " fs_aux=%d", aux);
> > +
> > +     audit_log_end(ab);
> > +}
> > +
> >  static void audit_log_task(struct audit_buffer *ab)
> >  {
> >       kuid_t auid, uid;
> > --
> > 2.53.0
>
> - RGB
>
> --
> Richard Guy Briggs <rgb@redhat.com>
> Sr. S/W Engineer, Kernel Security, Base Operating Systems
> Remote, Ottawa, Red Hat Canada
> Upstream IRC: SunRaycer
> Voice: +1.613.860 2354 SMS: +1.613.518.6570
>

-Ricardo
Re: [PATCH] audit: add FSCONFIG auxiliary record to log filesystem configuration
Posted by Richard Guy Briggs 3 days, 7 hours ago
On 2026-07-22 10:05, Ricardo Robaina wrote:
> On Tue, Jul 21, 2026 at 7:18 PM Richard Guy Briggs <rgb@redhat.com> wrote:
> >
> > On 2026-07-13 14:00, Ricardo Robaina wrote:
> > > Modern mount tools (util-linux >= 2.39.1) use the new mount API
> > > (fsopen, fsconfig, fsmount, move_mount) instead of the legacy mount(2)
> > > syscall. The generic SYSCALL audit record logs the fsconfig syscall but
> > > does not capture the configuration parameters, creating an audit gap for
> > > critical mount information such as the device being mounted.
> > >
> > > Add an FSCONFIG auxiliary record that logs the command type, parameter
> > > name (key), parameter value, and aux parameter passed to fsconfig(2).
> > >
> > >  ----
> > >  type=SYSCALL : syscall=fsconfig a1=FSCONFIG_SET_STRING ...
> >
> > This looks like it is missing "a0=..."?
> >
> > >  type=FSCONFIG : fs_cmd=1 fs_key=source fs_val="tmpfs" fs_aux=0
> > >  ----
> > >  type=SYSCALL : syscall=fsconfig a1=FSCONFIG_CMD_CREATE ...
> >
> > This looks like it is missing "a0=..."?
> > I'm guessing this isn't actually real test output?
> >
> 
> Thanks for reviewing this patch, Richard!
> 
> That's real test output; I just trimmed the SYSCALL record output to
> fit in the commit message. Since this patch does not touch this
> record, I don't see a problem. I can
> add a0=... for consistency if you prefer, though.

Consistent use of ... would help to clarify that.

> > >  type=FSCONFIG : fs_cmd=6 fs_key=(null) fs_val=(null) fs_aux=0
> >
> > Was there a fs_key output here that didn't make it due to the issue below?
> 
> Actually, in this case, the test result happened to be right (that's
> why I missed it).
> FSCONFIG_CMD_CREATE has no key or value, so both are NULL[1].

Yup, fair, had to ask.  :-)

> [1] https://man7.org/linux/man-pages/man2/fsconfig.2.html
> 
> > >  ----
> > >  type=SYSCALL : syscall=fsconfig a0=0x4 a1=FSCONFIG_SET_BINARY ...
> > >  type=FSCONFIG : fs_cmd=2 fs_key=hidepid fs_val="<binary>" fs_aux=4
> > >
> > > Link: https://github.com/linux-audit/audit-kernel/issues/153
> > > Signed-off-by: Ricardo Robaina <rrobaina@redhat.com>
> > > ---
> > >  fs/fsopen.c                |  7 +++++++
> > >  include/linux/audit.h      | 13 +++++++++++++
> > >  include/uapi/linux/audit.h |  1 +
> > >  kernel/auditsc.c           | 27 +++++++++++++++++++++++++++
> > >  4 files changed, 48 insertions(+)
> > >
> > > diff --git a/fs/fsopen.c b/fs/fsopen.c
> > > index ae19e5136598..9b3c02f59df4 100644
> > > --- a/fs/fsopen.c
> > > +++ b/fs/fsopen.c
> > > @@ -15,6 +15,7 @@
> > >  #include <linux/namei.h>
> > >  #include <linux/file.h>
> > >  #include <uapi/linux/mount.h>
> > > +#include <linux/audit.h>
> > >  #include "internal.h"
> > >  #include "mount.h"
> > >
> > > @@ -357,6 +358,7 @@ SYSCALL_DEFINE5(fsconfig,
> > >       struct fs_context *fc;
> > >       int ret;
> > >       int lookup_flags = 0;
> > > +     const char *value_str = NULL;
> > >
> > >       struct fs_parameter param = {
> > >               .type   = fs_value_is_undefined,
> > > @@ -423,6 +425,7 @@ SYSCALL_DEFINE5(fsconfig,
> > >                       goto out_key;
> > >               }
> > >               param.size = strlen(param.string);
> > > +             value_str = param.string;
> > >               break;
> > >       case FSCONFIG_SET_BINARY:
> > >               param.type = fs_value_is_blob;
> > > @@ -432,6 +435,7 @@ SYSCALL_DEFINE5(fsconfig,
> > >                       ret = PTR_ERR(param.blob);
> > >                       goto out_key;
> > >               }
> > > +             value_str = "<binary>";
> > >               break;
> > >       case FSCONFIG_SET_PATH_EMPTY:
> > >               lookup_flags = LOOKUP_EMPTY;
> > > @@ -445,6 +449,7 @@ SYSCALL_DEFINE5(fsconfig,
> > >               }
> > >               param.dirfd = aux;
> > >               param.size = strlen(param.name->name);
> > > +             value_str = param.name->name;
> > >               break;
> > >       case FSCONFIG_SET_FD:
> > >               param.type = fs_value_is_file;
> > > @@ -458,6 +463,8 @@ SYSCALL_DEFINE5(fsconfig,
> > >               break;
> > >       }
> > >
> > > +     audit_log_fsconfig(cmd, param.key, value_str, aux);
> > > +
> > >       ret = mutex_lock_interruptible(&fc->uapi_mutex);
> > >       if (ret == 0) {
> > >               ret = vfs_fsconfig_locked(fc, cmd, &param);
> > > diff --git a/include/linux/audit.h b/include/linux/audit.h
> > > index 45abb3722d30..978eb881974c 100644
> > > --- a/include/linux/audit.h
> > > +++ b/include/linux/audit.h
> > > @@ -449,6 +449,8 @@ 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_log_fsconfig(unsigned int cmd, const char *key,
> > > +                              const char *value, int aux);
> > >
> > >  static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp)
> > >  {
> > > @@ -598,6 +600,13 @@ static inline void audit_log_nfcfg(const char *name, u8 af,
> > >               __audit_log_nfcfg(name, af, nentries, op, gfp);
> > >  }
> > >
> > > +static inline void audit_log_fsconfig(unsigned int cmd, const char *key,
> > > +                                   const char *value, int aux)
> > > +{
> > > +     if (!audit_dummy_context())
> > > +             __audit_log_fsconfig(cmd, key, value, aux);
> > > +}
> > > +
> > >  extern int audit_n_rules;
> > >  extern int audit_signals;
> > >  #else /* CONFIG_AUDITSYSCALL */
> > > @@ -730,6 +739,10 @@ static inline void audit_log_nfcfg(const char *name, u8 af,
> > >                                  enum audit_nfcfgop op, gfp_t gfp)
> > >  { }
> > >
> > > +static inline void audit_log_fsconfig(unsigned int cmd, const char *key,
> > > +                                   const char *value, int aux)
> > > +{ }
> > > +
> > >  #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 e8f5ce677df7..5cd0eb602528 100644
> > > --- a/include/uapi/linux/audit.h
> > > +++ b/include/uapi/linux/audit.h
> > > @@ -122,6 +122,7 @@
> > >  #define AUDIT_OPENAT2                1337    /* Record showing openat2 how args */
> > >  #define AUDIT_DM_CTRL                1338    /* Device Mapper target control */
> > >  #define AUDIT_DM_EVENT               1339    /* Device Mapper events */
> > > +#define AUDIT_FSCONFIG               1341    /* Record showing fsconfig args */
> > >
> > >  #define AUDIT_AVC            1400    /* SE Linux avc denial or grant */
> > >  #define AUDIT_SELINUX_ERR    1401    /* Internal SE Linux Errors */
> > > diff --git a/kernel/auditsc.c b/kernel/auditsc.c
> > > index 6610e667c728..222bf79ee9bd 100644
> > > --- a/kernel/auditsc.c
> > > +++ b/kernel/auditsc.c
> > > @@ -2882,6 +2882,33 @@ void __audit_log_nfcfg(const char *name, u8 af, unsigned int nentries,
> > >  }
> > >  EXPORT_SYMBOL_GPL(__audit_log_nfcfg);
> > >
> > > +void __audit_log_fsconfig(unsigned int cmd, const char *key,
> > > +                       const char *value, int aux)
> > > +{
> > > +     struct audit_buffer *ab;
> > > +
> > > +     ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_FSCONFIG);
> > > +     if (!ab)
> > > +             return;
> > > +
> > > +     audit_log_format(ab, "fs_cmd=%u", cmd);
> > > +     audit_log_format(ab, " fs_key=");
> > > +     if (value)
> >
> > This looks like it should be "if (key)".
> 
> Good catch!
> 
> > > +             audit_log_untrustedstring(ab, key);
> > > +     else
> > > +             audit_log_format(ab, "(null)");
> > > +
> > > +     audit_log_format(ab, " fs_val=");
> > > +     if (value)
> > > +             audit_log_untrustedstring(ab, value);
> > > +     else
> > > +             audit_log_format(ab, "(null)");
> > > +
> > > +     audit_log_format(ab, " fs_aux=%d", aux);
> > > +
> > > +     audit_log_end(ab);
> > > +}
> > > +
> > >  static void audit_log_task(struct audit_buffer *ab)
> > >  {
> > >       kuid_t auid, uid;
> > > --
> > > 2.53.0
> >
> > - RGB
> 
> -Ricardo

- RGB

--
Richard Guy Briggs <rgb@redhat.com>
Sr. S/W Engineer, Kernel Security, Base Operating Systems
Remote, Ottawa, Red Hat Canada
Upstream IRC: SunRaycer
Voice: +1.613.860 2354 SMS: +1.613.518.6570