linux-modules.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1] audit,module: restore audit logging in load failure case
@ 2024-10-23 21:13 Richard Guy Briggs
  2024-10-24 17:58 ` kernel test robot
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Richard Guy Briggs @ 2024-10-23 21:13 UTC (permalink / raw)
  To: Linux-Audit Mailing List, LKML, linux-modules,
	Linux Kernel Audit Mailing List
  Cc: Paul Moore, Eric Paris, Steve Grubb, Richard Guy Briggs

The move of the module sanity check to earlier skipped the audit logging
call in the case of failure and to a place where the previously used
context is unavailable.

Add an audit logging call for the module loading failure case and get
the module name when possible.

Link: https://issues.redhat.com/browse/RHEL-52839
Fixes: 02da2cbab452 ("module: move check_modinfo() early to early_mod_check()")
Signed-off-by: Richard Guy Briggs <rgb@redhat.com>
---
 kernel/module/main.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/kernel/module/main.c b/kernel/module/main.c
index 49b9bca9de12..1f482532ef66 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -3057,8 +3057,10 @@ static int load_module(struct load_info *info, const char __user *uargs,
 	 * failures once the proper module was allocated and
 	 * before that.
 	 */
-	if (!module_allocated)
+	if (!module_allocated) {
+		audit_log_kern_module(info->name ? info->name : "(unavailable)");
 		mod_stat_bump_becoming(info, flags);
+	}
 	free_copy(info, flags);
 	return err;
 }
-- 
2.43.5


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v1] audit,module: restore audit logging in load failure case
  2024-10-23 21:13 [PATCH v1] audit,module: restore audit logging in load failure case Richard Guy Briggs
@ 2024-10-24 17:58 ` kernel test robot
  2024-10-24 20:41 ` Paul Moore
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 9+ messages in thread
From: kernel test robot @ 2024-10-24 17:58 UTC (permalink / raw)
  To: Richard Guy Briggs, Linux-Audit Mailing List, LKML, linux-modules,
	Linux Kernel Audit Mailing List
  Cc: llvm, oe-kbuild-all, Paul Moore, Eric Paris, Steve Grubb,
	Richard Guy Briggs

Hi Richard,

kernel test robot noticed the following build errors:

[auto build test ERROR on mcgrof/modules-next]
[also build test ERROR on linus/master v6.12-rc4 next-20241024]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Richard-Guy-Briggs/audit-module-restore-audit-logging-in-load-failure-case/20241024-051515
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/linux.git modules-next
patch link:    https://lore.kernel.org/r/999cdd694f951acd2f4ad665fe7ab97d0834e162.1729717542.git.rgb%40redhat.com
patch subject: [PATCH v1] audit,module: restore audit logging in load failure case
config: x86_64-kexec (https://download.01.org/0day-ci/archive/20241025/202410250152.vcJ5tyVZ-lkp@intel.com/config)
compiler: clang version 19.1.2 (https://github.com/llvm/llvm-project 7ba7d8e2f7b6445b60679da826210cdde29eaf8b)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241025/202410250152.vcJ5tyVZ-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202410250152.vcJ5tyVZ-lkp@intel.com/

All errors (new ones prefixed by >>):

   In file included from kernel/module/main.c:14:
   In file included from include/linux/trace_events.h:6:
   In file included from include/linux/ring_buffer.h:5:
   In file included from include/linux/mm.h:2213:
   include/linux/vmstat.h:504:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
     504 |         return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~ ^
     505 |                            item];
         |                            ~~~~
   include/linux/vmstat.h:511:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
     511 |         return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~ ^
     512 |                            NR_VM_NUMA_EVENT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~~
   include/linux/vmstat.h:518:36: warning: arithmetic between different enumeration types ('enum node_stat_item' and 'enum lru_list') [-Wenum-enum-conversion]
     518 |         return node_stat_name(NR_LRU_BASE + lru) + 3; // skip "nr_"
         |                               ~~~~~~~~~~~ ^ ~~~
   include/linux/vmstat.h:524:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
     524 |         return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~ ^
     525 |                            NR_VM_NUMA_EVENT_ITEMS +
         |                            ~~~~~~~~~~~~~~~~~~~~~~
>> kernel/module/main.c:3336:25: error: passing 'const char *' to parameter of type 'char *' discards qualifiers [-Werror,-Wincompatible-pointer-types-discards-qualifiers]
    3336 |                 audit_log_kern_module(info->name ? info->name : "(unavailable)");
         |                                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/audit.h:522:48: note: passing argument to parameter 'name' here
     522 | static inline void audit_log_kern_module(char *name)
         |                                                ^
   4 warnings and 1 error generated.


vim +3336 kernel/module/main.c

  3124	
  3125	/*
  3126	 * Allocate and load the module: note that size of section 0 is always
  3127	 * zero, and we rely on this for optional sections.
  3128	 */
  3129	static int load_module(struct load_info *info, const char __user *uargs,
  3130			       int flags)
  3131	{
  3132		struct module *mod;
  3133		bool module_allocated = false;
  3134		long err = 0;
  3135		char *after_dashes;
  3136	
  3137		/*
  3138		 * Do the signature check (if any) first. All that
  3139		 * the signature check needs is info->len, it does
  3140		 * not need any of the section info. That can be
  3141		 * set up later. This will minimize the chances
  3142		 * of a corrupt module causing problems before
  3143		 * we even get to the signature check.
  3144		 *
  3145		 * The check will also adjust info->len by stripping
  3146		 * off the sig length at the end of the module, making
  3147		 * checks against info->len more correct.
  3148		 */
  3149		err = module_sig_check(info, flags);
  3150		if (err)
  3151			goto free_copy;
  3152	
  3153		/*
  3154		 * Do basic sanity checks against the ELF header and
  3155		 * sections. Cache useful sections and set the
  3156		 * info->mod to the userspace passed struct module.
  3157		 */
  3158		err = elf_validity_cache_copy(info, flags);
  3159		if (err)
  3160			goto free_copy;
  3161	
  3162		err = early_mod_check(info, flags);
  3163		if (err)
  3164			goto free_copy;
  3165	
  3166		/* Figure out module layout, and allocate all the memory. */
  3167		mod = layout_and_allocate(info, flags);
  3168		if (IS_ERR(mod)) {
  3169			err = PTR_ERR(mod);
  3170			goto free_copy;
  3171		}
  3172	
  3173		module_allocated = true;
  3174	
  3175		audit_log_kern_module(mod->name);
  3176	
  3177		/* Reserve our place in the list. */
  3178		err = add_unformed_module(mod);
  3179		if (err)
  3180			goto free_module;
  3181	
  3182		/*
  3183		 * We are tainting your kernel if your module gets into
  3184		 * the modules linked list somehow.
  3185		 */
  3186		module_augment_kernel_taints(mod, info);
  3187	
  3188		/* To avoid stressing percpu allocator, do this once we're unique. */
  3189		err = percpu_modalloc(mod, info);
  3190		if (err)
  3191			goto unlink_mod;
  3192	
  3193		/* Now module is in final location, initialize linked lists, etc. */
  3194		err = module_unload_init(mod);
  3195		if (err)
  3196			goto unlink_mod;
  3197	
  3198		init_param_lock(mod);
  3199	
  3200		/*
  3201		 * Now we've got everything in the final locations, we can
  3202		 * find optional sections.
  3203		 */
  3204		err = find_module_sections(mod, info);
  3205		if (err)
  3206			goto free_unload;
  3207	
  3208		err = check_export_symbol_versions(mod);
  3209		if (err)
  3210			goto free_unload;
  3211	
  3212		/* Set up MODINFO_ATTR fields */
  3213		setup_modinfo(mod, info);
  3214	
  3215		/* Fix up syms, so that st_value is a pointer to location. */
  3216		err = simplify_symbols(mod, info);
  3217		if (err < 0)
  3218			goto free_modinfo;
  3219	
  3220		err = apply_relocations(mod, info);
  3221		if (err < 0)
  3222			goto free_modinfo;
  3223	
  3224		err = post_relocation(mod, info);
  3225		if (err < 0)
  3226			goto free_modinfo;
  3227	
  3228		flush_module_icache(mod);
  3229	
  3230		/* Now copy in args */
  3231		mod->args = strndup_user(uargs, ~0UL >> 1);
  3232		if (IS_ERR(mod->args)) {
  3233			err = PTR_ERR(mod->args);
  3234			goto free_arch_cleanup;
  3235		}
  3236	
  3237		init_build_id(mod, info);
  3238	
  3239		/* Ftrace init must be called in the MODULE_STATE_UNFORMED state */
  3240		ftrace_module_init(mod);
  3241	
  3242		/* Finally it's fully formed, ready to start executing. */
  3243		err = complete_formation(mod, info);
  3244		if (err)
  3245			goto ddebug_cleanup;
  3246	
  3247		err = prepare_coming_module(mod);
  3248		if (err)
  3249			goto bug_cleanup;
  3250	
  3251		mod->async_probe_requested = async_probe;
  3252	
  3253		/* Module is ready to execute: parsing args may do that. */
  3254		after_dashes = parse_args(mod->name, mod->args, mod->kp, mod->num_kp,
  3255					  -32768, 32767, mod,
  3256					  unknown_module_param_cb);
  3257		if (IS_ERR(after_dashes)) {
  3258			err = PTR_ERR(after_dashes);
  3259			goto coming_cleanup;
  3260		} else if (after_dashes) {
  3261			pr_warn("%s: parameters '%s' after `--' ignored\n",
  3262			       mod->name, after_dashes);
  3263		}
  3264	
  3265		/* Link in to sysfs. */
  3266		err = mod_sysfs_setup(mod, info, mod->kp, mod->num_kp);
  3267		if (err < 0)
  3268			goto coming_cleanup;
  3269	
  3270		if (is_livepatch_module(mod)) {
  3271			err = copy_module_elf(mod, info);
  3272			if (err < 0)
  3273				goto sysfs_cleanup;
  3274		}
  3275	
  3276		/* Get rid of temporary copy. */
  3277		free_copy(info, flags);
  3278	
  3279		codetag_load_module(mod);
  3280	
  3281		/* Done! */
  3282		trace_module_load(mod);
  3283	
  3284		return do_init_module(mod);
  3285	
  3286	 sysfs_cleanup:
  3287		mod_sysfs_teardown(mod);
  3288	 coming_cleanup:
  3289		mod->state = MODULE_STATE_GOING;
  3290		destroy_params(mod->kp, mod->num_kp);
  3291		blocking_notifier_call_chain(&module_notify_list,
  3292					     MODULE_STATE_GOING, mod);
  3293		klp_module_going(mod);
  3294	 bug_cleanup:
  3295		mod->state = MODULE_STATE_GOING;
  3296		/* module_bug_cleanup needs module_mutex protection */
  3297		mutex_lock(&module_mutex);
  3298		module_bug_cleanup(mod);
  3299		mutex_unlock(&module_mutex);
  3300	
  3301	 ddebug_cleanup:
  3302		ftrace_release_mod(mod);
  3303		synchronize_rcu();
  3304		kfree(mod->args);
  3305	 free_arch_cleanup:
  3306		module_arch_cleanup(mod);
  3307	 free_modinfo:
  3308		free_modinfo(mod);
  3309	 free_unload:
  3310		module_unload_free(mod);
  3311	 unlink_mod:
  3312		mutex_lock(&module_mutex);
  3313		/* Unlink carefully: kallsyms could be walking list. */
  3314		list_del_rcu(&mod->list);
  3315		mod_tree_remove(mod);
  3316		wake_up_all(&module_wq);
  3317		/* Wait for RCU-sched synchronizing before releasing mod->list. */
  3318		synchronize_rcu();
  3319		mutex_unlock(&module_mutex);
  3320	 free_module:
  3321		mod_stat_bump_invalid(info, flags);
  3322		/* Free lock-classes; relies on the preceding sync_rcu() */
  3323		for_class_mod_mem_type(type, core_data) {
  3324			lockdep_free_key_range(mod->mem[type].base,
  3325					       mod->mem[type].size);
  3326		}
  3327	
  3328		module_deallocate(mod, info);
  3329	 free_copy:
  3330		/*
  3331		 * The info->len is always set. We distinguish between
  3332		 * failures once the proper module was allocated and
  3333		 * before that.
  3334		 */
  3335		if (!module_allocated) {
> 3336			audit_log_kern_module(info->name ? info->name : "(unavailable)");
  3337			mod_stat_bump_becoming(info, flags);
  3338		}
  3339		free_copy(info, flags);
  3340		return err;
  3341	}
  3342	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v1] audit,module: restore audit logging in load failure  case
  2024-10-23 21:13 [PATCH v1] audit,module: restore audit logging in load failure case Richard Guy Briggs
  2024-10-24 17:58 ` kernel test robot
@ 2024-10-24 20:41 ` Paul Moore
  2025-03-06 21:41   ` Richard Guy Briggs
  2024-10-25  7:38 ` kernel test robot
  2024-10-28  5:55 ` kernel test robot
  3 siblings, 1 reply; 9+ messages in thread
From: Paul Moore @ 2024-10-24 20:41 UTC (permalink / raw)
  To: Richard Guy Briggs, Linux-Audit Mailing List, LKML, linux-modules,
	Linux Kernel Audit Mailing List
  Cc: Eric Paris, Steve Grubb, Richard Guy Briggs

On Oct 23, 2024 Richard Guy Briggs <rgb@redhat.com> wrote:
> 
> The move of the module sanity check to earlier skipped the audit logging
> call in the case of failure and to a place where the previously used
> context is unavailable.
> 
> Add an audit logging call for the module loading failure case and get
> the module name when possible.
> 
> Link: https://issues.redhat.com/browse/RHEL-52839
> Fixes: 02da2cbab452 ("module: move check_modinfo() early to early_mod_check()")
> Signed-off-by: Richard Guy Briggs <rgb@redhat.com>
> ---
>  kernel/module/main.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/kernel/module/main.c b/kernel/module/main.c
> index 49b9bca9de12..1f482532ef66 100644
> --- a/kernel/module/main.c
> +++ b/kernel/module/main.c
> @@ -3057,8 +3057,10 @@ static int load_module(struct load_info *info, const char __user *uargs,
>  	 * failures once the proper module was allocated and
>  	 * before that.
>  	 */
> -	if (!module_allocated)
> +	if (!module_allocated) {
> +		audit_log_kern_module(info->name ? info->name : "(unavailable)");
>  		mod_stat_bump_becoming(info, flags);
> +	}

We probably should move the existing audit_log_kern_module() to just
after the elf_validity_cache_copy() call as both info->name and
info->mod->name should be as valid as they are going to get at that
point.  If we do that then we only have two cases we need to worry about,
a failed module_sig_check() or a failed elf_validity_cache_copy(), and
in both cases we can use "(unavailable)" without having to check
info->name first.

However, assuming we move the audit_log_kern_module() call up a bit as
described above, I'm not sure there is much value in calling
audit_log_kern_module() with an "(unavailable)" module name in those
early two cases.  We know it's an attempted module load based on the
SYSCALL record, seeing an associated "(unavailable)" KERN_MODULE record
doesn't provide us with any more information than if we had simply
skipped the KERN_MODULE record.

Untested, but this is what I'm talking about:

diff --git a/include/linux/audit.h b/include/linux/audit.h
index 0050ef288ab3..eaa10e3c7eca 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -417,7 +417,7 @@ extern int __audit_log_bprm_fcaps(struct linux_binprm *bprm,
 extern void __audit_log_capset(const struct cred *new, const struct cred *old);
 extern void __audit_mmap_fd(int fd, int flags);
 extern void __audit_openat2_how(struct open_how *how);
-extern void __audit_log_kern_module(char *name);
+extern void __audit_log_kern_module(const char *name);
 extern void __audit_fanotify(u32 response, struct fanotify_response_info_audit_rule *friar);
 extern void __audit_tk_injoffset(struct timespec64 offset);
 extern void __audit_ntp_log(const struct audit_ntp_data *ad);
@@ -519,7 +519,7 @@ static inline void audit_openat2_how(struct open_how *how)
                __audit_openat2_how(how);
 }
 
-static inline void audit_log_kern_module(char *name)
+static inline void audit_log_kern_module(const char *name)
 {
        if (!audit_dummy_context())
                __audit_log_kern_module(name);
@@ -677,7 +677,7 @@ static inline void audit_mmap_fd(int fd, int flags)
 static inline void audit_openat2_how(struct open_how *how)
 { }
 
-static inline void audit_log_kern_module(char *name)
+static inline void audit_log_kern_module(const char *name)
 {
 }
 
diff --git a/kernel/audit.h b/kernel/audit.h
index a60d2840559e..5156ecd35457 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -199,7 +199,7 @@ struct audit_context {
                        int                     argc;
                } execve;
                struct {
-                       char                    *name;
+                       const char              *name;
                } module;
                struct {
                        struct audit_ntp_data   ntp_data;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 0627e74585ce..f79eb3a5a789 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2870,7 +2870,7 @@ void __audit_openat2_how(struct open_how *how)
        context->type = AUDIT_OPENAT2;
 }
 
-void __audit_log_kern_module(char *name)
+void __audit_log_kern_module(const char *name)
 {
        struct audit_context *context = audit_context();
 
diff --git a/kernel/module/main.c b/kernel/module/main.c
index 49b9bca9de12..3acb65073c53 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -2884,6 +2884,8 @@ static int load_module(struct load_info *info, const char __user *uargs,
        if (err)
                goto free_copy;
 
+       audit_log_kern_module(info->name);
+
        err = early_mod_check(info, flags);
        if (err)
                goto free_copy;
@@ -2897,8 +2899,6 @@ static int load_module(struct load_info *info, const char __user *uargs,
 
        module_allocated = true;
 
-       audit_log_kern_module(mod->name);
-
        /* Reserve our place in the list. */
        err = add_unformed_module(mod);
        if (err)

--
paul-moore.com

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v1] audit,module: restore audit logging in load failure case
  2024-10-23 21:13 [PATCH v1] audit,module: restore audit logging in load failure case Richard Guy Briggs
  2024-10-24 17:58 ` kernel test robot
  2024-10-24 20:41 ` Paul Moore
@ 2024-10-25  7:38 ` kernel test robot
  2024-10-28  5:55 ` kernel test robot
  3 siblings, 0 replies; 9+ messages in thread
From: kernel test robot @ 2024-10-25  7:38 UTC (permalink / raw)
  To: Richard Guy Briggs, Linux-Audit Mailing List, LKML, linux-modules,
	Linux Kernel Audit Mailing List
  Cc: oe-kbuild-all, Paul Moore, Eric Paris, Steve Grubb,
	Richard Guy Briggs

Hi Richard,

kernel test robot noticed the following build warnings:

[auto build test WARNING on mcgrof/modules-next]
[also build test WARNING on linus/master v6.12-rc4 next-20241024]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Richard-Guy-Briggs/audit-module-restore-audit-logging-in-load-failure-case/20241024-051515
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/linux.git modules-next
patch link:    https://lore.kernel.org/r/999cdd694f951acd2f4ad665fe7ab97d0834e162.1729717542.git.rgb%40redhat.com
patch subject: [PATCH v1] audit,module: restore audit logging in load failure case
config: x86_64-randconfig-121-20241025 (https://download.01.org/0day-ci/archive/20241025/202410251446.xzMTe7Yk-lkp@intel.com/config)
compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241025/202410251446.xzMTe7Yk-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202410251446.xzMTe7Yk-lkp@intel.com/

sparse warnings: (new ones prefixed by >>)
>> kernel/module/main.c:3336:50: sparse: sparse: incorrect type in argument 1 (different modifiers) @@     expected char *name @@     got char const * @@
   kernel/module/main.c:3336:50: sparse:     expected char *name
   kernel/module/main.c:3336:50: sparse:     got char const *

vim +3336 kernel/module/main.c

  3124	
  3125	/*
  3126	 * Allocate and load the module: note that size of section 0 is always
  3127	 * zero, and we rely on this for optional sections.
  3128	 */
  3129	static int load_module(struct load_info *info, const char __user *uargs,
  3130			       int flags)
  3131	{
  3132		struct module *mod;
  3133		bool module_allocated = false;
  3134		long err = 0;
  3135		char *after_dashes;
  3136	
  3137		/*
  3138		 * Do the signature check (if any) first. All that
  3139		 * the signature check needs is info->len, it does
  3140		 * not need any of the section info. That can be
  3141		 * set up later. This will minimize the chances
  3142		 * of a corrupt module causing problems before
  3143		 * we even get to the signature check.
  3144		 *
  3145		 * The check will also adjust info->len by stripping
  3146		 * off the sig length at the end of the module, making
  3147		 * checks against info->len more correct.
  3148		 */
  3149		err = module_sig_check(info, flags);
  3150		if (err)
  3151			goto free_copy;
  3152	
  3153		/*
  3154		 * Do basic sanity checks against the ELF header and
  3155		 * sections. Cache useful sections and set the
  3156		 * info->mod to the userspace passed struct module.
  3157		 */
  3158		err = elf_validity_cache_copy(info, flags);
  3159		if (err)
  3160			goto free_copy;
  3161	
  3162		err = early_mod_check(info, flags);
  3163		if (err)
  3164			goto free_copy;
  3165	
  3166		/* Figure out module layout, and allocate all the memory. */
  3167		mod = layout_and_allocate(info, flags);
  3168		if (IS_ERR(mod)) {
  3169			err = PTR_ERR(mod);
  3170			goto free_copy;
  3171		}
  3172	
  3173		module_allocated = true;
  3174	
  3175		audit_log_kern_module(mod->name);
  3176	
  3177		/* Reserve our place in the list. */
  3178		err = add_unformed_module(mod);
  3179		if (err)
  3180			goto free_module;
  3181	
  3182		/*
  3183		 * We are tainting your kernel if your module gets into
  3184		 * the modules linked list somehow.
  3185		 */
  3186		module_augment_kernel_taints(mod, info);
  3187	
  3188		/* To avoid stressing percpu allocator, do this once we're unique. */
  3189		err = percpu_modalloc(mod, info);
  3190		if (err)
  3191			goto unlink_mod;
  3192	
  3193		/* Now module is in final location, initialize linked lists, etc. */
  3194		err = module_unload_init(mod);
  3195		if (err)
  3196			goto unlink_mod;
  3197	
  3198		init_param_lock(mod);
  3199	
  3200		/*
  3201		 * Now we've got everything in the final locations, we can
  3202		 * find optional sections.
  3203		 */
  3204		err = find_module_sections(mod, info);
  3205		if (err)
  3206			goto free_unload;
  3207	
  3208		err = check_export_symbol_versions(mod);
  3209		if (err)
  3210			goto free_unload;
  3211	
  3212		/* Set up MODINFO_ATTR fields */
  3213		setup_modinfo(mod, info);
  3214	
  3215		/* Fix up syms, so that st_value is a pointer to location. */
  3216		err = simplify_symbols(mod, info);
  3217		if (err < 0)
  3218			goto free_modinfo;
  3219	
  3220		err = apply_relocations(mod, info);
  3221		if (err < 0)
  3222			goto free_modinfo;
  3223	
  3224		err = post_relocation(mod, info);
  3225		if (err < 0)
  3226			goto free_modinfo;
  3227	
  3228		flush_module_icache(mod);
  3229	
  3230		/* Now copy in args */
  3231		mod->args = strndup_user(uargs, ~0UL >> 1);
  3232		if (IS_ERR(mod->args)) {
  3233			err = PTR_ERR(mod->args);
  3234			goto free_arch_cleanup;
  3235		}
  3236	
  3237		init_build_id(mod, info);
  3238	
  3239		/* Ftrace init must be called in the MODULE_STATE_UNFORMED state */
  3240		ftrace_module_init(mod);
  3241	
  3242		/* Finally it's fully formed, ready to start executing. */
  3243		err = complete_formation(mod, info);
  3244		if (err)
  3245			goto ddebug_cleanup;
  3246	
  3247		err = prepare_coming_module(mod);
  3248		if (err)
  3249			goto bug_cleanup;
  3250	
  3251		mod->async_probe_requested = async_probe;
  3252	
  3253		/* Module is ready to execute: parsing args may do that. */
  3254		after_dashes = parse_args(mod->name, mod->args, mod->kp, mod->num_kp,
  3255					  -32768, 32767, mod,
  3256					  unknown_module_param_cb);
  3257		if (IS_ERR(after_dashes)) {
  3258			err = PTR_ERR(after_dashes);
  3259			goto coming_cleanup;
  3260		} else if (after_dashes) {
  3261			pr_warn("%s: parameters '%s' after `--' ignored\n",
  3262			       mod->name, after_dashes);
  3263		}
  3264	
  3265		/* Link in to sysfs. */
  3266		err = mod_sysfs_setup(mod, info, mod->kp, mod->num_kp);
  3267		if (err < 0)
  3268			goto coming_cleanup;
  3269	
  3270		if (is_livepatch_module(mod)) {
  3271			err = copy_module_elf(mod, info);
  3272			if (err < 0)
  3273				goto sysfs_cleanup;
  3274		}
  3275	
  3276		/* Get rid of temporary copy. */
  3277		free_copy(info, flags);
  3278	
  3279		codetag_load_module(mod);
  3280	
  3281		/* Done! */
  3282		trace_module_load(mod);
  3283	
  3284		return do_init_module(mod);
  3285	
  3286	 sysfs_cleanup:
  3287		mod_sysfs_teardown(mod);
  3288	 coming_cleanup:
  3289		mod->state = MODULE_STATE_GOING;
  3290		destroy_params(mod->kp, mod->num_kp);
  3291		blocking_notifier_call_chain(&module_notify_list,
  3292					     MODULE_STATE_GOING, mod);
  3293		klp_module_going(mod);
  3294	 bug_cleanup:
  3295		mod->state = MODULE_STATE_GOING;
  3296		/* module_bug_cleanup needs module_mutex protection */
  3297		mutex_lock(&module_mutex);
  3298		module_bug_cleanup(mod);
  3299		mutex_unlock(&module_mutex);
  3300	
  3301	 ddebug_cleanup:
  3302		ftrace_release_mod(mod);
  3303		synchronize_rcu();
  3304		kfree(mod->args);
  3305	 free_arch_cleanup:
  3306		module_arch_cleanup(mod);
  3307	 free_modinfo:
  3308		free_modinfo(mod);
  3309	 free_unload:
  3310		module_unload_free(mod);
  3311	 unlink_mod:
  3312		mutex_lock(&module_mutex);
  3313		/* Unlink carefully: kallsyms could be walking list. */
  3314		list_del_rcu(&mod->list);
  3315		mod_tree_remove(mod);
  3316		wake_up_all(&module_wq);
  3317		/* Wait for RCU-sched synchronizing before releasing mod->list. */
  3318		synchronize_rcu();
  3319		mutex_unlock(&module_mutex);
  3320	 free_module:
  3321		mod_stat_bump_invalid(info, flags);
  3322		/* Free lock-classes; relies on the preceding sync_rcu() */
  3323		for_class_mod_mem_type(type, core_data) {
  3324			lockdep_free_key_range(mod->mem[type].base,
  3325					       mod->mem[type].size);
  3326		}
  3327	
  3328		module_deallocate(mod, info);
  3329	 free_copy:
  3330		/*
  3331		 * The info->len is always set. We distinguish between
  3332		 * failures once the proper module was allocated and
  3333		 * before that.
  3334		 */
  3335		if (!module_allocated) {
> 3336			audit_log_kern_module(info->name ? info->name : "(unavailable)");
  3337			mod_stat_bump_becoming(info, flags);
  3338		}
  3339		free_copy(info, flags);
  3340		return err;
  3341	}
  3342	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v1] audit,module: restore audit logging in load failure case
  2024-10-23 21:13 [PATCH v1] audit,module: restore audit logging in load failure case Richard Guy Briggs
                   ` (2 preceding siblings ...)
  2024-10-25  7:38 ` kernel test robot
@ 2024-10-28  5:55 ` kernel test robot
  3 siblings, 0 replies; 9+ messages in thread
From: kernel test robot @ 2024-10-28  5:55 UTC (permalink / raw)
  To: Richard Guy Briggs, Linux-Audit Mailing List, LKML, linux-modules,
	Linux Kernel Audit Mailing List
  Cc: oe-kbuild-all, Paul Moore, Eric Paris, Steve Grubb,
	Richard Guy Briggs

Hi Richard,

kernel test robot noticed the following build warnings:

[auto build test WARNING on mcgrof/modules-next]
[also build test WARNING on linus/master v6.12-rc5 next-20241025]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Richard-Guy-Briggs/audit-module-restore-audit-logging-in-load-failure-case/20241024-051515
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/linux.git modules-next
patch link:    https://lore.kernel.org/r/999cdd694f951acd2f4ad665fe7ab97d0834e162.1729717542.git.rgb%40redhat.com
patch subject: [PATCH v1] audit,module: restore audit logging in load failure case
config: x86_64-defconfig (https://download.01.org/0day-ci/archive/20241028/202410281314.56S1Nfqd-lkp@intel.com/config)
compiler: gcc-11 (Debian 11.3.0-12) 11.3.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241028/202410281314.56S1Nfqd-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202410281314.56S1Nfqd-lkp@intel.com/

All warnings (new ones prefixed by >>):

   kernel/module/main.c: In function 'load_module':
>> kernel/module/main.c:3336:63: warning: passing argument 1 of 'audit_log_kern_module' discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
    3336 |                 audit_log_kern_module(info->name ? info->name : "(unavailable)");
         |                                       ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~
   In file included from kernel/module/main.c:57:
   include/linux/audit.h:522:48: note: expected 'char *' but argument is of type 'const char *'
     522 | static inline void audit_log_kern_module(char *name)
         |                                          ~~~~~~^~~~


vim +3336 kernel/module/main.c

  3124	
  3125	/*
  3126	 * Allocate and load the module: note that size of section 0 is always
  3127	 * zero, and we rely on this for optional sections.
  3128	 */
  3129	static int load_module(struct load_info *info, const char __user *uargs,
  3130			       int flags)
  3131	{
  3132		struct module *mod;
  3133		bool module_allocated = false;
  3134		long err = 0;
  3135		char *after_dashes;
  3136	
  3137		/*
  3138		 * Do the signature check (if any) first. All that
  3139		 * the signature check needs is info->len, it does
  3140		 * not need any of the section info. That can be
  3141		 * set up later. This will minimize the chances
  3142		 * of a corrupt module causing problems before
  3143		 * we even get to the signature check.
  3144		 *
  3145		 * The check will also adjust info->len by stripping
  3146		 * off the sig length at the end of the module, making
  3147		 * checks against info->len more correct.
  3148		 */
  3149		err = module_sig_check(info, flags);
  3150		if (err)
  3151			goto free_copy;
  3152	
  3153		/*
  3154		 * Do basic sanity checks against the ELF header and
  3155		 * sections. Cache useful sections and set the
  3156		 * info->mod to the userspace passed struct module.
  3157		 */
  3158		err = elf_validity_cache_copy(info, flags);
  3159		if (err)
  3160			goto free_copy;
  3161	
  3162		err = early_mod_check(info, flags);
  3163		if (err)
  3164			goto free_copy;
  3165	
  3166		/* Figure out module layout, and allocate all the memory. */
  3167		mod = layout_and_allocate(info, flags);
  3168		if (IS_ERR(mod)) {
  3169			err = PTR_ERR(mod);
  3170			goto free_copy;
  3171		}
  3172	
  3173		module_allocated = true;
  3174	
  3175		audit_log_kern_module(mod->name);
  3176	
  3177		/* Reserve our place in the list. */
  3178		err = add_unformed_module(mod);
  3179		if (err)
  3180			goto free_module;
  3181	
  3182		/*
  3183		 * We are tainting your kernel if your module gets into
  3184		 * the modules linked list somehow.
  3185		 */
  3186		module_augment_kernel_taints(mod, info);
  3187	
  3188		/* To avoid stressing percpu allocator, do this once we're unique. */
  3189		err = percpu_modalloc(mod, info);
  3190		if (err)
  3191			goto unlink_mod;
  3192	
  3193		/* Now module is in final location, initialize linked lists, etc. */
  3194		err = module_unload_init(mod);
  3195		if (err)
  3196			goto unlink_mod;
  3197	
  3198		init_param_lock(mod);
  3199	
  3200		/*
  3201		 * Now we've got everything in the final locations, we can
  3202		 * find optional sections.
  3203		 */
  3204		err = find_module_sections(mod, info);
  3205		if (err)
  3206			goto free_unload;
  3207	
  3208		err = check_export_symbol_versions(mod);
  3209		if (err)
  3210			goto free_unload;
  3211	
  3212		/* Set up MODINFO_ATTR fields */
  3213		setup_modinfo(mod, info);
  3214	
  3215		/* Fix up syms, so that st_value is a pointer to location. */
  3216		err = simplify_symbols(mod, info);
  3217		if (err < 0)
  3218			goto free_modinfo;
  3219	
  3220		err = apply_relocations(mod, info);
  3221		if (err < 0)
  3222			goto free_modinfo;
  3223	
  3224		err = post_relocation(mod, info);
  3225		if (err < 0)
  3226			goto free_modinfo;
  3227	
  3228		flush_module_icache(mod);
  3229	
  3230		/* Now copy in args */
  3231		mod->args = strndup_user(uargs, ~0UL >> 1);
  3232		if (IS_ERR(mod->args)) {
  3233			err = PTR_ERR(mod->args);
  3234			goto free_arch_cleanup;
  3235		}
  3236	
  3237		init_build_id(mod, info);
  3238	
  3239		/* Ftrace init must be called in the MODULE_STATE_UNFORMED state */
  3240		ftrace_module_init(mod);
  3241	
  3242		/* Finally it's fully formed, ready to start executing. */
  3243		err = complete_formation(mod, info);
  3244		if (err)
  3245			goto ddebug_cleanup;
  3246	
  3247		err = prepare_coming_module(mod);
  3248		if (err)
  3249			goto bug_cleanup;
  3250	
  3251		mod->async_probe_requested = async_probe;
  3252	
  3253		/* Module is ready to execute: parsing args may do that. */
  3254		after_dashes = parse_args(mod->name, mod->args, mod->kp, mod->num_kp,
  3255					  -32768, 32767, mod,
  3256					  unknown_module_param_cb);
  3257		if (IS_ERR(after_dashes)) {
  3258			err = PTR_ERR(after_dashes);
  3259			goto coming_cleanup;
  3260		} else if (after_dashes) {
  3261			pr_warn("%s: parameters '%s' after `--' ignored\n",
  3262			       mod->name, after_dashes);
  3263		}
  3264	
  3265		/* Link in to sysfs. */
  3266		err = mod_sysfs_setup(mod, info, mod->kp, mod->num_kp);
  3267		if (err < 0)
  3268			goto coming_cleanup;
  3269	
  3270		if (is_livepatch_module(mod)) {
  3271			err = copy_module_elf(mod, info);
  3272			if (err < 0)
  3273				goto sysfs_cleanup;
  3274		}
  3275	
  3276		/* Get rid of temporary copy. */
  3277		free_copy(info, flags);
  3278	
  3279		codetag_load_module(mod);
  3280	
  3281		/* Done! */
  3282		trace_module_load(mod);
  3283	
  3284		return do_init_module(mod);
  3285	
  3286	 sysfs_cleanup:
  3287		mod_sysfs_teardown(mod);
  3288	 coming_cleanup:
  3289		mod->state = MODULE_STATE_GOING;
  3290		destroy_params(mod->kp, mod->num_kp);
  3291		blocking_notifier_call_chain(&module_notify_list,
  3292					     MODULE_STATE_GOING, mod);
  3293		klp_module_going(mod);
  3294	 bug_cleanup:
  3295		mod->state = MODULE_STATE_GOING;
  3296		/* module_bug_cleanup needs module_mutex protection */
  3297		mutex_lock(&module_mutex);
  3298		module_bug_cleanup(mod);
  3299		mutex_unlock(&module_mutex);
  3300	
  3301	 ddebug_cleanup:
  3302		ftrace_release_mod(mod);
  3303		synchronize_rcu();
  3304		kfree(mod->args);
  3305	 free_arch_cleanup:
  3306		module_arch_cleanup(mod);
  3307	 free_modinfo:
  3308		free_modinfo(mod);
  3309	 free_unload:
  3310		module_unload_free(mod);
  3311	 unlink_mod:
  3312		mutex_lock(&module_mutex);
  3313		/* Unlink carefully: kallsyms could be walking list. */
  3314		list_del_rcu(&mod->list);
  3315		mod_tree_remove(mod);
  3316		wake_up_all(&module_wq);
  3317		/* Wait for RCU-sched synchronizing before releasing mod->list. */
  3318		synchronize_rcu();
  3319		mutex_unlock(&module_mutex);
  3320	 free_module:
  3321		mod_stat_bump_invalid(info, flags);
  3322		/* Free lock-classes; relies on the preceding sync_rcu() */
  3323		for_class_mod_mem_type(type, core_data) {
  3324			lockdep_free_key_range(mod->mem[type].base,
  3325					       mod->mem[type].size);
  3326		}
  3327	
  3328		module_deallocate(mod, info);
  3329	 free_copy:
  3330		/*
  3331		 * The info->len is always set. We distinguish between
  3332		 * failures once the proper module was allocated and
  3333		 * before that.
  3334		 */
  3335		if (!module_allocated) {
> 3336			audit_log_kern_module(info->name ? info->name : "(unavailable)");
  3337			mod_stat_bump_becoming(info, flags);
  3338		}
  3339		free_copy(info, flags);
  3340		return err;
  3341	}
  3342	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v1] audit,module: restore audit logging in load failure case
  2024-10-24 20:41 ` Paul Moore
@ 2025-03-06 21:41   ` Richard Guy Briggs
  2025-03-07  0:11     ` Richard Guy Briggs
  2025-03-07 19:41     ` Steve Grubb
  0 siblings, 2 replies; 9+ messages in thread
From: Richard Guy Briggs @ 2025-03-06 21:41 UTC (permalink / raw)
  To: Paul Moore
  Cc: Linux-Audit Mailing List, LKML, linux-modules,
	Linux Kernel Audit Mailing List, Eric Paris, Steve Grubb

On 2024-10-24 16:41, Paul Moore wrote:
> On Oct 23, 2024 Richard Guy Briggs <rgb@redhat.com> wrote:
> > The move of the module sanity check to earlier skipped the audit logging
> > call in the case of failure and to a place where the previously used
> > context is unavailable.
> > 
> > Add an audit logging call for the module loading failure case and get
> > the module name when possible.
> > 
> > Link: https://issues.redhat.com/browse/RHEL-52839
> > Fixes: 02da2cbab452 ("module: move check_modinfo() early to early_mod_check()")
> > Signed-off-by: Richard Guy Briggs <rgb@redhat.com>
> > ---
> >  kernel/module/main.c | 4 +++-
> >  1 file changed, 3 insertions(+), 1 deletion(-)
> > 
> > diff --git a/kernel/module/main.c b/kernel/module/main.c
> > index 49b9bca9de12..1f482532ef66 100644
> > --- a/kernel/module/main.c
> > +++ b/kernel/module/main.c
> > @@ -3057,8 +3057,10 @@ static int load_module(struct load_info *info, const char __user *uargs,
> >  	 * failures once the proper module was allocated and
> >  	 * before that.
> >  	 */
> > -	if (!module_allocated)
> > +	if (!module_allocated) {
> > +		audit_log_kern_module(info->name ? info->name : "(unavailable)");
> >  		mod_stat_bump_becoming(info, flags);
> > +	}
> 
> We probably should move the existing audit_log_kern_module() to just
> after the elf_validity_cache_copy() call as both info->name and
> info->mod->name should be as valid as they are going to get at that
> point.  If we do that then we only have two cases we need to worry about,
> a failed module_sig_check() or a failed elf_validity_cache_copy(), and
> in both cases we can use "(unavailable)" without having to check
> info->name first.

Fair enough.

> However, assuming we move the audit_log_kern_module() call up a bit as
> described above, I'm not sure there is much value in calling
> audit_log_kern_module() with an "(unavailable)" module name in those
> early two cases.  We know it's an attempted module load based on the
> SYSCALL record, seeing an associated "(unavailable)" KERN_MODULE record
> doesn't provide us with any more information than if we had simply
> skipped the KERN_MODULE record.

Understood.  I wonder if the absence of the record in the error case
will leave us guessing if we lost a record from the event?  We will have
the error code from the SYSCALL record but not much more than that, and
some of those error codes could just as well be generated after that
point too.  This would be a similar situation to the vanishing fields in
an existing record, but is likely easier to mitigate than a
non-last-field vanishing or shifting around in an existing record.

Steve?  Atilla?  Any comments?

> Untested, but this is what I'm talking about:
> 
> diff --git a/include/linux/audit.h b/include/linux/audit.h
> index 0050ef288ab3..eaa10e3c7eca 100644
> --- a/include/linux/audit.h
> +++ b/include/linux/audit.h
> @@ -417,7 +417,7 @@ extern int __audit_log_bprm_fcaps(struct linux_binprm *bprm,
>  extern void __audit_log_capset(const struct cred *new, const struct cred *old);
>  extern void __audit_mmap_fd(int fd, int flags);
>  extern void __audit_openat2_how(struct open_how *how);
> -extern void __audit_log_kern_module(char *name);
> +extern void __audit_log_kern_module(const char *name);
>  extern void __audit_fanotify(u32 response, struct fanotify_response_info_audit_rule *friar);
>  extern void __audit_tk_injoffset(struct timespec64 offset);
>  extern void __audit_ntp_log(const struct audit_ntp_data *ad);
> @@ -519,7 +519,7 @@ static inline void audit_openat2_how(struct open_how *how)
>                 __audit_openat2_how(how);
>  }
>  
> -static inline void audit_log_kern_module(char *name)
> +static inline void audit_log_kern_module(const char *name)
>  {
>         if (!audit_dummy_context())
>                 __audit_log_kern_module(name);
> @@ -677,7 +677,7 @@ static inline void audit_mmap_fd(int fd, int flags)
>  static inline void audit_openat2_how(struct open_how *how)
>  { }
>  
> -static inline void audit_log_kern_module(char *name)
> +static inline void audit_log_kern_module(const char *name)
>  {
>  }
>  
> diff --git a/kernel/audit.h b/kernel/audit.h
> index a60d2840559e..5156ecd35457 100644
> --- a/kernel/audit.h
> +++ b/kernel/audit.h
> @@ -199,7 +199,7 @@ struct audit_context {
>                         int                     argc;
>                 } execve;
>                 struct {
> -                       char                    *name;
> +                       const char              *name;
>                 } module;
>                 struct {
>                         struct audit_ntp_data   ntp_data;
> diff --git a/kernel/auditsc.c b/kernel/auditsc.c
> index 0627e74585ce..f79eb3a5a789 100644
> --- a/kernel/auditsc.c
> +++ b/kernel/auditsc.c
> @@ -2870,7 +2870,7 @@ void __audit_openat2_how(struct open_how *how)
>         context->type = AUDIT_OPENAT2;
>  }
>  
> -void __audit_log_kern_module(char *name)
> +void __audit_log_kern_module(const char *name)
>  {
>         struct audit_context *context = audit_context();
>  
> diff --git a/kernel/module/main.c b/kernel/module/main.c
> index 49b9bca9de12..3acb65073c53 100644
> --- a/kernel/module/main.c
> +++ b/kernel/module/main.c
> @@ -2884,6 +2884,8 @@ static int load_module(struct load_info *info, const char __user *uargs,
>         if (err)
>                 goto free_copy;
>  
> +       audit_log_kern_module(info->name);
> +
>         err = early_mod_check(info, flags);
>         if (err)
>                 goto free_copy;
> @@ -2897,8 +2899,6 @@ static int load_module(struct load_info *info, const char __user *uargs,
>  
>         module_allocated = true;
>  
> -       audit_log_kern_module(mod->name);
> -
>         /* Reserve our place in the list. */
>         err = add_unformed_module(mod);
>         if (err)
> 
> --
> paul-moore.com

- 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


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v1] audit,module: restore audit logging in load failure case
  2025-03-06 21:41   ` Richard Guy Briggs
@ 2025-03-07  0:11     ` Richard Guy Briggs
  2025-03-07 19:41     ` Steve Grubb
  1 sibling, 0 replies; 9+ messages in thread
From: Richard Guy Briggs @ 2025-03-07  0:11 UTC (permalink / raw)
  To: Paul Moore
  Cc: Linux-Audit Mailing List, LKML, linux-modules,
	Linux Kernel Audit Mailing List, Eric Paris, Steve Grubb

On 2025-03-06 16:41, Richard Guy Briggs wrote:
> On 2024-10-24 16:41, Paul Moore wrote:
> > On Oct 23, 2024 Richard Guy Briggs <rgb@redhat.com> wrote:
> > > The move of the module sanity check to earlier skipped the audit logging
> > > call in the case of failure and to a place where the previously used
> > > context is unavailable.
> > > 
> > > Add an audit logging call for the module loading failure case and get
> > > the module name when possible.
> > > 
> > > Link: https://issues.redhat.com/browse/RHEL-52839
> > > Fixes: 02da2cbab452 ("module: move check_modinfo() early to early_mod_check()")
> > > Signed-off-by: Richard Guy Briggs <rgb@redhat.com>
> > > ---
> > >  kernel/module/main.c | 4 +++-
> > >  1 file changed, 3 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/kernel/module/main.c b/kernel/module/main.c
> > > index 49b9bca9de12..1f482532ef66 100644
> > > --- a/kernel/module/main.c
> > > +++ b/kernel/module/main.c
> > > @@ -3057,8 +3057,10 @@ static int load_module(struct load_info *info, const char __user *uargs,
> > >  	 * failures once the proper module was allocated and
> > >  	 * before that.
> > >  	 */
> > > -	if (!module_allocated)
> > > +	if (!module_allocated) {
> > > +		audit_log_kern_module(info->name ? info->name : "(unavailable)");
> > >  		mod_stat_bump_becoming(info, flags);
> > > +	}
> > 
> > We probably should move the existing audit_log_kern_module() to just
> > after the elf_validity_cache_copy() call as both info->name and
> > info->mod->name should be as valid as they are going to get at that
> > point.  If we do that then we only have two cases we need to worry about,
> > a failed module_sig_check() or a failed elf_validity_cache_copy(), and
> > in both cases we can use "(unavailable)" without having to check
> > info->name first.
> 
> Fair enough.
> 
> > However, assuming we move the audit_log_kern_module() call up a bit as
> > described above, I'm not sure there is much value in calling
> > audit_log_kern_module() with an "(unavailable)" module name in those
> > early two cases.  We know it's an attempted module load based on the
> > SYSCALL record, seeing an associated "(unavailable)" KERN_MODULE record
> > doesn't provide us with any more information than if we had simply
> > skipped the KERN_MODULE record.
> 
> Understood.  I wonder if the absence of the record in the error case
> will leave us guessing if we lost a record from the event?  We will have
> the error code from the SYSCALL record but not much more than that, and
> some of those error codes could just as well be generated after that
> point too.  This would be a similar situation to the vanishing fields in
> an existing record, but is likely easier to mitigate than a
> non-last-field vanishing or shifting around in an existing record.

In fact, the reason the original issue was filed was due to the
unexpected missing record, so it seems that it would be best to include
it regardless so that event can be found more consistently by
KERN_MODULE record type rather than searching for SYSCALL sub-field.

> Steve?  Atilla?  Any comments?
> 
> > Untested, but this is what I'm talking about:
> > 
> > diff --git a/include/linux/audit.h b/include/linux/audit.h
> > index 0050ef288ab3..eaa10e3c7eca 100644
> > --- a/include/linux/audit.h
> > +++ b/include/linux/audit.h
> > @@ -417,7 +417,7 @@ extern int __audit_log_bprm_fcaps(struct linux_binprm *bprm,
> >  extern void __audit_log_capset(const struct cred *new, const struct cred *old);
> >  extern void __audit_mmap_fd(int fd, int flags);
> >  extern void __audit_openat2_how(struct open_how *how);
> > -extern void __audit_log_kern_module(char *name);
> > +extern void __audit_log_kern_module(const char *name);
> >  extern void __audit_fanotify(u32 response, struct fanotify_response_info_audit_rule *friar);
> >  extern void __audit_tk_injoffset(struct timespec64 offset);
> >  extern void __audit_ntp_log(const struct audit_ntp_data *ad);
> > @@ -519,7 +519,7 @@ static inline void audit_openat2_how(struct open_how *how)
> >                 __audit_openat2_how(how);
> >  }
> >  
> > -static inline void audit_log_kern_module(char *name)
> > +static inline void audit_log_kern_module(const char *name)
> >  {
> >         if (!audit_dummy_context())
> >                 __audit_log_kern_module(name);
> > @@ -677,7 +677,7 @@ static inline void audit_mmap_fd(int fd, int flags)
> >  static inline void audit_openat2_how(struct open_how *how)
> >  { }
> >  
> > -static inline void audit_log_kern_module(char *name)
> > +static inline void audit_log_kern_module(const char *name)
> >  {
> >  }
> >  
> > diff --git a/kernel/audit.h b/kernel/audit.h
> > index a60d2840559e..5156ecd35457 100644
> > --- a/kernel/audit.h
> > +++ b/kernel/audit.h
> > @@ -199,7 +199,7 @@ struct audit_context {
> >                         int                     argc;
> >                 } execve;
> >                 struct {
> > -                       char                    *name;
> > +                       const char              *name;
> >                 } module;
> >                 struct {
> >                         struct audit_ntp_data   ntp_data;
> > diff --git a/kernel/auditsc.c b/kernel/auditsc.c
> > index 0627e74585ce..f79eb3a5a789 100644
> > --- a/kernel/auditsc.c
> > +++ b/kernel/auditsc.c
> > @@ -2870,7 +2870,7 @@ void __audit_openat2_how(struct open_how *how)
> >         context->type = AUDIT_OPENAT2;
> >  }
> >  
> > -void __audit_log_kern_module(char *name)
> > +void __audit_log_kern_module(const char *name)
> >  {
> >         struct audit_context *context = audit_context();
> >  
> > diff --git a/kernel/module/main.c b/kernel/module/main.c
> > index 49b9bca9de12..3acb65073c53 100644
> > --- a/kernel/module/main.c
> > +++ b/kernel/module/main.c
> > @@ -2884,6 +2884,8 @@ static int load_module(struct load_info *info, const char __user *uargs,
> >         if (err)
> >                 goto free_copy;
> >  
> > +       audit_log_kern_module(info->name);
> > +
> >         err = early_mod_check(info, flags);
> >         if (err)
> >                 goto free_copy;
> > @@ -2897,8 +2899,6 @@ static int load_module(struct load_info *info, const char __user *uargs,
> >  
> >         module_allocated = true;
> >  
> > -       audit_log_kern_module(mod->name);
> > -
> >         /* Reserve our place in the list. */
> >         err = add_unformed_module(mod);
> >         if (err)
> > 
> > --
> > paul-moore.com
> 
> - RGB

- 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


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v1] audit,module: restore audit logging in load failure case
  2025-03-06 21:41   ` Richard Guy Briggs
  2025-03-07  0:11     ` Richard Guy Briggs
@ 2025-03-07 19:41     ` Steve Grubb
  2025-03-13 15:18       ` Richard Guy Briggs
  1 sibling, 1 reply; 9+ messages in thread
From: Steve Grubb @ 2025-03-07 19:41 UTC (permalink / raw)
  To: Paul Moore, Richard Guy Briggs
  Cc: Linux-Audit Mailing List, LKML, linux-modules,
	Linux Kernel Audit Mailing List, Eric Paris

On Thursday, March 6, 2025 4:41:40 PM Eastern Standard Time Richard Guy 
Briggs wrote:
> On 2024-10-24 16:41, Paul Moore wrote:
> > On Oct 23, 2024 Richard Guy Briggs <rgb@redhat.com> wrote:
> > > The move of the module sanity check to earlier skipped the audit
> > > logging
> > > call in the case of failure and to a place where the previously used
> > > context is unavailable.
> > > 
> > > Add an audit logging call for the module loading failure case and get
> > > the module name when possible.
> > > 
> > > Link: https://issues.redhat.com/browse/RHEL-52839
> > > Fixes: 02da2cbab452 ("module: move check_modinfo() early to
> > > early_mod_check()") Signed-off-by: Richard Guy Briggs <rgb@redhat.com>
> > > ---
> > > 
> > >  kernel/module/main.c | 4 +++-
> > >  1 file changed, 3 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/kernel/module/main.c b/kernel/module/main.c
> > > index 49b9bca9de12..1f482532ef66 100644
> > > --- a/kernel/module/main.c
> > > +++ b/kernel/module/main.c
> > > @@ -3057,8 +3057,10 @@ static int load_module(struct load_info *info,
> > > const char __user *uargs,> > 
> > >  	 * failures once the proper module was allocated and
> > >  	 * before that.
> > >  	 */
> > > 
> > > -	if (!module_allocated)
> > > +	if (!module_allocated) {
> > > +		audit_log_kern_module(info->name ? info->name : 
"(unavailable)");
> > > 
> > >  		mod_stat_bump_becoming(info, flags);
> > > 
> > > +	}
> > 
> > We probably should move the existing audit_log_kern_module() to just
> > after the elf_validity_cache_copy() call as both info->name and
> > info->mod->name should be as valid as they are going to get at that
> > point.  If we do that then we only have two cases we need to worry about,
> > a failed module_sig_check() or a failed elf_validity_cache_copy(), and
> > in both cases we can use "(unavailable)" without having to check
> > info->name first.
> 
> Fair enough.
> 
> > However, assuming we move the audit_log_kern_module() call up a bit as
> > described above, I'm not sure there is much value in calling
> > audit_log_kern_module() with an "(unavailable)" module name in those
> > early two cases.  We know it's an attempted module load based on the
> > SYSCALL record, seeing an associated "(unavailable)" KERN_MODULE record
> > doesn't provide us with any more information than if we had simply
> > skipped the KERN_MODULE record.
> 
> Understood.  I wonder if the absence of the record in the error case
> will leave us guessing if we lost a record from the event?  We will have
> the error code from the SYSCALL record but not much more than that, and
> some of those error codes could just as well be generated after that
> point too.  This would be a similar situation to the vanishing fields in
> an existing record, but is likely easier to mitigate than a
> non-last-field vanishing or shifting around in an existing record.
> 
> Steve?  Atilla?  Any comments?

We should only get the events if we have syscall rules that would result in 
kernel module loading/unloading events. I suppose that by the time audit 
loads it's rules, many modules have already loaded. So, I don't think we need 
to worry about early cases. But when we do get a kernel module load/unload 
event based on the rules, we need it's name - even in failures. We need to be 
able to determine what was attempted since this could affect system 
integrity.

-Steve

> > Untested, but this is what I'm talking about:
> > 
> > diff --git a/include/linux/audit.h b/include/linux/audit.h
> > index 0050ef288ab3..eaa10e3c7eca 100644
> > --- a/include/linux/audit.h
> > +++ b/include/linux/audit.h
> > @@ -417,7 +417,7 @@ extern int __audit_log_bprm_fcaps(struct linux_binprm
> > *bprm,> 
> >  extern void __audit_log_capset(const struct cred *new, const struct cred
> >  *old); extern void __audit_mmap_fd(int fd, int flags);
> >  extern void __audit_openat2_how(struct open_how *how);
> > 
> > -extern void __audit_log_kern_module(char *name);
> > +extern void __audit_log_kern_module(const char *name);
> > 
> >  extern void __audit_fanotify(u32 response, struct
> >  fanotify_response_info_audit_rule *friar); extern void
> >  __audit_tk_injoffset(struct timespec64 offset);
> >  extern void __audit_ntp_log(const struct audit_ntp_data *ad);
> > 
> > @@ -519,7 +519,7 @@ static inline void audit_openat2_how(struct open_how
> > *how)> 
> >                 __audit_openat2_how(how);
> >  
> >  }
> > 
> > -static inline void audit_log_kern_module(char *name)
> > +static inline void audit_log_kern_module(const char *name)
> > 
> >  {
> >  
> >         if (!audit_dummy_context())
> >         
> >                 __audit_log_kern_module(name);
> > 
> > @@ -677,7 +677,7 @@ static inline void audit_mmap_fd(int fd, int flags)
> > 
> >  static inline void audit_openat2_how(struct open_how *how)
> >  { }
> > 
> > -static inline void audit_log_kern_module(char *name)
> > +static inline void audit_log_kern_module(const char *name)
> > 
> >  {
> >  }
> > 
> > diff --git a/kernel/audit.h b/kernel/audit.h
> > index a60d2840559e..5156ecd35457 100644
> > --- a/kernel/audit.h
> > +++ b/kernel/audit.h
> > @@ -199,7 +199,7 @@ struct audit_context {
> > 
> >                         int                     argc;
> >                 
> >                 } execve;
> >                 struct {
> > 
> > -                       char                    *name;
> > +                       const char              *name;
> > 
> >                 } module;
> >                 struct {
> >                 
> >                         struct audit_ntp_data   ntp_data;
> > 
> > diff --git a/kernel/auditsc.c b/kernel/auditsc.c
> > index 0627e74585ce..f79eb3a5a789 100644
> > --- a/kernel/auditsc.c
> > +++ b/kernel/auditsc.c
> > @@ -2870,7 +2870,7 @@ void __audit_openat2_how(struct open_how *how)
> > 
> >         context->type = AUDIT_OPENAT2;
> >  
> >  }
> > 
> > -void __audit_log_kern_module(char *name)
> > +void __audit_log_kern_module(const char *name)
> > 
> >  {
> >  
> >         struct audit_context *context = audit_context();
> > 
> > diff --git a/kernel/module/main.c b/kernel/module/main.c
> > index 49b9bca9de12..3acb65073c53 100644
> > --- a/kernel/module/main.c
> > +++ b/kernel/module/main.c
> > @@ -2884,6 +2884,8 @@ static int load_module(struct load_info *info,
> > const char __user *uargs,> 
> >         if (err)
> >         
> >                 goto free_copy;
> > 
> > +       audit_log_kern_module(info->name);
> > +
> > 
> >         err = early_mod_check(info, flags);
> >         if (err)
> >         
> >                 goto free_copy;
> > 
> > @@ -2897,8 +2899,6 @@ static int load_module(struct load_info *info,
> > const char __user *uargs,> 
> >         module_allocated = true;
> > 
> > -       audit_log_kern_module(mod->name);
> > -
> > 
> >         /* Reserve our place in the list. */
> >         err = add_unformed_module(mod);
> >         if (err)
> > 
> > --
> > paul-moore.com
> 
> - 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





^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v1] audit,module: restore audit logging in load failure case
  2025-03-07 19:41     ` Steve Grubb
@ 2025-03-13 15:18       ` Richard Guy Briggs
  0 siblings, 0 replies; 9+ messages in thread
From: Richard Guy Briggs @ 2025-03-13 15:18 UTC (permalink / raw)
  To: Steve Grubb
  Cc: Paul Moore, Linux-Audit Mailing List, LKML, linux-modules,
	Linux Kernel Audit Mailing List, Eric Paris

On 2025-03-07 14:41, Steve Grubb wrote:
> On Thursday, March 6, 2025 4:41:40 PM Eastern Standard Time Richard Guy 
> Briggs wrote:
> > On 2024-10-24 16:41, Paul Moore wrote:
> > > On Oct 23, 2024 Richard Guy Briggs <rgb@redhat.com> wrote:
> > > > The move of the module sanity check to earlier skipped the audit
> > > > logging
> > > > call in the case of failure and to a place where the previously used
> > > > context is unavailable.
> > > > 
> > > > Add an audit logging call for the module loading failure case and get
> > > > the module name when possible.
> > > > 
> > > > Link: https://issues.redhat.com/browse/RHEL-52839
> > > > Fixes: 02da2cbab452 ("module: move check_modinfo() early to
> > > > early_mod_check()") Signed-off-by: Richard Guy Briggs <rgb@redhat.com>
> > > > ---
> > > > 
> > > >  kernel/module/main.c | 4 +++-
> > > >  1 file changed, 3 insertions(+), 1 deletion(-)
> > > > 
> > > > diff --git a/kernel/module/main.c b/kernel/module/main.c
> > > > index 49b9bca9de12..1f482532ef66 100644
> > > > --- a/kernel/module/main.c
> > > > +++ b/kernel/module/main.c
> > > > @@ -3057,8 +3057,10 @@ static int load_module(struct load_info *info,
> > > > const char __user *uargs,> > 
> > > >  	 * failures once the proper module was allocated and
> > > >  	 * before that.
> > > >  	 */
> > > > 
> > > > -	if (!module_allocated)
> > > > +	if (!module_allocated) {
> > > > +		audit_log_kern_module(info->name ? info->name : 
> "(unavailable)");
> > > > 
> > > >  		mod_stat_bump_becoming(info, flags);
> > > > 
> > > > +	}
> > > 
> > > We probably should move the existing audit_log_kern_module() to just
> > > after the elf_validity_cache_copy() call as both info->name and
> > > info->mod->name should be as valid as they are going to get at that
> > > point.  If we do that then we only have two cases we need to worry about,
> > > a failed module_sig_check() or a failed elf_validity_cache_copy(), and
> > > in both cases we can use "(unavailable)" without having to check
> > > info->name first.
> > 
> > Fair enough.
> > 
> > > However, assuming we move the audit_log_kern_module() call up a bit as
> > > described above, I'm not sure there is much value in calling
> > > audit_log_kern_module() with an "(unavailable)" module name in those
> > > early two cases.  We know it's an attempted module load based on the
> > > SYSCALL record, seeing an associated "(unavailable)" KERN_MODULE record
> > > doesn't provide us with any more information than if we had simply
> > > skipped the KERN_MODULE record.
> > 
> > Understood.  I wonder if the absence of the record in the error case
> > will leave us guessing if we lost a record from the event?  We will have
> > the error code from the SYSCALL record but not much more than that, and
> > some of those error codes could just as well be generated after that
> > point too.  This would be a similar situation to the vanishing fields in
> > an existing record, but is likely easier to mitigate than a
> > non-last-field vanishing or shifting around in an existing record.
> > 
> > Steve?  Atilla?  Any comments?
> 
> We should only get the events if we have syscall rules that would result in 
> kernel module loading/unloading events. I suppose that by the time audit 
> loads it's rules, many modules have already loaded. So, I don't think we need 
> to worry about early cases. But when we do get a kernel module load/unload 
> event based on the rules, we need it's name - even in failures. We need to be 
> able to determine what was attempted since this could affect system 
> integrity.

Ok, yes, agreed.  But that information isn't available yet for a number
of error cases.  It hasn't even been looked for yet after
module_sig_check() and can't be reliably found until halfway through
elf_validity_cache_copy().

So, we should provide the record and make a best effort to fill in that
information if we can.  We could try more aggressively to extract it
from the info blob, but I don't know if that is worth the effort because
a number of the steps leading up to it are necessary to check the
validity and set up structures to extract it.

> -Steve
> 
> > > Untested, but this is what I'm talking about:
> > > 
> > > diff --git a/include/linux/audit.h b/include/linux/audit.h
> > > index 0050ef288ab3..eaa10e3c7eca 100644
> > > --- a/include/linux/audit.h
> > > +++ b/include/linux/audit.h
> > > @@ -417,7 +417,7 @@ extern int __audit_log_bprm_fcaps(struct linux_binprm
> > > *bprm,> 
> > >  extern void __audit_log_capset(const struct cred *new, const struct cred
> > >  *old); extern void __audit_mmap_fd(int fd, int flags);
> > >  extern void __audit_openat2_how(struct open_how *how);
> > > 
> > > -extern void __audit_log_kern_module(char *name);
> > > +extern void __audit_log_kern_module(const char *name);
> > > 
> > >  extern void __audit_fanotify(u32 response, struct
> > >  fanotify_response_info_audit_rule *friar); extern void
> > >  __audit_tk_injoffset(struct timespec64 offset);
> > >  extern void __audit_ntp_log(const struct audit_ntp_data *ad);
> > > 
> > > @@ -519,7 +519,7 @@ static inline void audit_openat2_how(struct open_how
> > > *how)> 
> > >                 __audit_openat2_how(how);
> > >  
> > >  }
> > > 
> > > -static inline void audit_log_kern_module(char *name)
> > > +static inline void audit_log_kern_module(const char *name)
> > > 
> > >  {
> > >  
> > >         if (!audit_dummy_context())
> > >         
> > >                 __audit_log_kern_module(name);
> > > 
> > > @@ -677,7 +677,7 @@ static inline void audit_mmap_fd(int fd, int flags)
> > > 
> > >  static inline void audit_openat2_how(struct open_how *how)
> > >  { }
> > > 
> > > -static inline void audit_log_kern_module(char *name)
> > > +static inline void audit_log_kern_module(const char *name)
> > > 
> > >  {
> > >  }
> > > 
> > > diff --git a/kernel/audit.h b/kernel/audit.h
> > > index a60d2840559e..5156ecd35457 100644
> > > --- a/kernel/audit.h
> > > +++ b/kernel/audit.h
> > > @@ -199,7 +199,7 @@ struct audit_context {
> > > 
> > >                         int                     argc;
> > >                 
> > >                 } execve;
> > >                 struct {
> > > 
> > > -                       char                    *name;
> > > +                       const char              *name;
> > > 
> > >                 } module;
> > >                 struct {
> > >                 
> > >                         struct audit_ntp_data   ntp_data;
> > > 
> > > diff --git a/kernel/auditsc.c b/kernel/auditsc.c
> > > index 0627e74585ce..f79eb3a5a789 100644
> > > --- a/kernel/auditsc.c
> > > +++ b/kernel/auditsc.c
> > > @@ -2870,7 +2870,7 @@ void __audit_openat2_how(struct open_how *how)
> > > 
> > >         context->type = AUDIT_OPENAT2;
> > >  
> > >  }
> > > 
> > > -void __audit_log_kern_module(char *name)
> > > +void __audit_log_kern_module(const char *name)
> > > 
> > >  {
> > >  
> > >         struct audit_context *context = audit_context();
> > > 
> > > diff --git a/kernel/module/main.c b/kernel/module/main.c
> > > index 49b9bca9de12..3acb65073c53 100644
> > > --- a/kernel/module/main.c
> > > +++ b/kernel/module/main.c
> > > @@ -2884,6 +2884,8 @@ static int load_module(struct load_info *info,
> > > const char __user *uargs,> 
> > >         if (err)
> > >         
> > >                 goto free_copy;
> > > 
> > > +       audit_log_kern_module(info->name);
> > > +
> > > 
> > >         err = early_mod_check(info, flags);
> > >         if (err)
> > >         
> > >                 goto free_copy;
> > > 
> > > @@ -2897,8 +2899,6 @@ static int load_module(struct load_info *info,
> > > const char __user *uargs,> 
> > >         module_allocated = true;
> > > 
> > > -       audit_log_kern_module(mod->name);
> > > -
> > > 
> > >         /* Reserve our place in the list. */
> > >         err = add_unformed_module(mod);
> > >         if (err)
> > > 
> > > --
> > > paul-moore.com
> > 
> > - RGB

- 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


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2025-03-13 15:19 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-10-23 21:13 [PATCH v1] audit,module: restore audit logging in load failure case Richard Guy Briggs
2024-10-24 17:58 ` kernel test robot
2024-10-24 20:41 ` Paul Moore
2025-03-06 21:41   ` Richard Guy Briggs
2025-03-07  0:11     ` Richard Guy Briggs
2025-03-07 19:41     ` Steve Grubb
2025-03-13 15:18       ` Richard Guy Briggs
2024-10-25  7:38 ` kernel test robot
2024-10-28  5:55 ` kernel test robot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).