Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 23 Aug 2010 18:00:56 +0200
From:      Attilio Rao <attilio@freebsd.org>
To:        Andriy Gapon <avg@icyb.net.ua>
Cc:        freebsd-hackers@freebsd.org, Ryan Stone <rysto32@gmail.com>
Subject:   Re: kld modules remain loaded if MOD_LOAD handler returns an error
Message-ID:  <AANLkTinxWAbZsunvQBTVWP5FqMYj=CTdrqYSRSoMBzA4@mail.gmail.com>
In-Reply-To: <4C728DF4.2060203@icyb.net.ua>
References:  <AANLkTi=qJ3WZChWg5axnuH8OBMxzd6JrnmfsmXHqPY2Q@mail.gmail.com> <201008230810.04710.jhb@freebsd.org> <4C728DF4.2060203@icyb.net.ua>

next in thread | previous in thread | raw e-mail | index | archive | help
2010/8/23 Andriy Gapon <avg@icyb.net.ua>:
> 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)
>>> {
>>> =C2=A0 =C2=A0 return *test;
>>> }
>>>
>>> static int
>>> first_modevent(struct module *m, int what, void *arg)
>>> {
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 int err =3D 0;
>>>
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 switch (what) {
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 case MOD_LOAD: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0/* kldload */
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 test =3D malloc=
(sizeof(int), M_TEMP, M_NOWAIT | M_ZERO);
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (!test)
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 err =3D ENOMEM;
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 break;
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 case MOD_UNLOAD: =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0/* kldunload */
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 break;
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 default:
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 err =3D EINVAL;
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 break;
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 }
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 return(err);
>>> }
>>>
>>> static moduledata_t first_mod =3D {
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 "first",
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 first_modevent,
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 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)
>>> {
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 int err =3D 0;
>>>
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 switch (what) {
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 case MOD_LOAD: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0/* kldload */
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 test_function()=
;
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 break;
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 case MOD_UNLOAD: =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0/* kldunload */
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 break;
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 default:
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 err =3D EINVAL;
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 break;
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 }
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 return(err);
>>> }
>>>
>>> static moduledata_t second_mod =3D {
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 "second",
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 second_modevent,
>>> =C2=A0 =C2=A0 =C2=A0 =C2=A0 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. =C2=A0However, 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. =C2=A0Anybody have any thoughts on this?
>>
>> Yeah, it's not easy to fix. =C2=A0Probably we could patch the kernel lin=
ker to
>> notice if any of the modules for a given linker file had errors during
>> initialization and trigger an unload if that occurs. =C2=A0I 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.

I replied in private, but I really agree with Andriy here.

Thanks,
Attilio


--=20
Peace can only be achieved by understanding - A. Einstein



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?AANLkTinxWAbZsunvQBTVWP5FqMYj=CTdrqYSRSoMBzA4>