kld modules remain loaded if MOD_LOAD handler returns an error
John Baldwin
jhb at freebsd.org
Mon Aug 23 15:10:35 UTC 2010
On Monday, August 23, 2010 11:04:20 am Andriy Gapon wrote:
> on 23/08/2010 15:10 John Baldwin said the following:
> > On Friday, August 20, 2010 1:13:53 pm Ryan Stone wrote:
> >> Consider the following modules:
> >>
> >> /* first.c */
> >> static int *test;
> >>
> >> int
> >> test_function(void)
> >> {
> >> return *test;
> >> }
> >>
> >> static int
> >> first_modevent(struct module *m, int what, void *arg)
> >> {
> >> int err = 0;
> >>
> >> switch (what) {
> >> case MOD_LOAD: /* kldload */
> >> test = malloc(sizeof(int), M_TEMP, M_NOWAIT | M_ZERO);
> >> if (!test)
> >> err = ENOMEM;
> >> break;
> >> case MOD_UNLOAD: /* kldunload */
> >> break;
> >> default:
> >> err = EINVAL;
> >> break;
> >> }
> >> return(err);
> >> }
> >>
> >> static moduledata_t first_mod = {
> >> "first",
> >> first_modevent,
> >> NULL
> >> };
> >>
> >> DECLARE_MODULE(first, first_mod, SI_SUB_KLD, SI_ORDER_ANY);
> >> MODULE_VERSION(first, 1);
> >>
> >>
> >> /* second.c */
> >> static int
> >> second_modevent(struct module *m, int what, void *arg)
> >> {
> >> int err = 0;
> >>
> >> switch (what) {
> >> case MOD_LOAD: /* kldload */
> >> test_function();
> >> break;
> >> case MOD_UNLOAD: /* kldunload */
> >> break;
> >> default:
> >> err = EINVAL;
> >> break;
> >> }
> >> return(err);
> >> }
> >>
> >> static moduledata_t second_mod = {
> >> "second",
> >> second_modevent,
> >> NULL
> >> };
> >>
> >> DECLARE_MODULE(second, second_mod, SI_SUB_KLD, SI_ORDER_ANY);
> >> MODULE_DEPEND(second, first, 1, 1, 1);
> >>
> >>
> >> Consider the case where malloc fails in first_modevent.
> >> first_modevent will return ENOMEM, but the module will remain loaded.
> >> Now when the second module goes and loads, it calls into the first
> >> module, which is not initialized properly, and promptly crashes when
> >> test_function() dereferences a null pointer.
> >>
> >> It seems to me that a module should be unloaded if it returns an error
> >> from its MOD_LOAD handler. However, that's easier said than done.
> >> The MOD_LOAD handler is called from a SYSINIT, and there's no
> >> immediately obvious way to pass information about the failure from the
> >> SYSINIT to the kernel linker. Anybody have any thoughts on this?
> >
> > Yeah, it's not easy to fix. Probably we could patch the kernel linker to
> > notice if any of the modules for a given linker file had errors during
> > initialization and trigger an unload if that occurs. I don't think this would
> > be too hard to do.
>
> John,
>
> please note that for this testcase we would need to prevent second module's
> modevent from being executed at all.
> Perhaps a module shouldn't be considered as loaded until modevent caller marks it
> as successfully initialized, but I haven't looked at the actual code.
Well, if these two event handlers are in the same module, I think that is a
bug in the module really. I tend to collapse such things down to a single
event handler per kld just so I can really get the ordering correct anyway. :)
If they are in two separate .ko files then the other solution would work.
We could also hack the module code to mark a linker_file as 'broken' and have
the module_helper sysinit not call mod_load if the containing file is 'broken',
etc.
--
John Baldwin
More information about the freebsd-hackers
mailing list