Fix module handling to stop oddball modules (if_ppp_mod, if_sl_mod,
if_tun_mod, etc...) from crashing the system. These modules are useful, but because they don't yet have proper load()/unload() functions, they can lead to panics: if, for example, you load the if_ppp module, any user can panic the system by running modstat. You can also hang the system outright if you try to unload the PPP module too. Changes are as follows: - Save the name passed to us during the RESERVE stage for name matching (we can't load if_ppp_mod twice: we've have two ppp0's and two ppp1's, which is beyond strange). This makes the lkmexists() cheks somewhat redundant, but there's no way around it that I can see. - If we call the module entry point and find that we have no lkm_any structure in our 'private' section, create a fake one. This keeps modstat happy. We mark such modules as LM_UNKNOWN. - Don't allow LM_UNLOAD modules to be unloaded: it just ain't possible. (Unless someone wants to write a pppunattach() function. :( ) - In lkmunreserve(), mark private.lkm_any as NULL so we don't get confused later. I think this is bogus, but I can't prove it. XXX: the name matching used to keep the user from loading two instances of the same module can easily be defeated simply by changing the module name or, in the case of the oddball modules, simply by renaming the module files. I haven't found a nice simple way to tell one module from another.
This commit is contained in:
parent
b877a2160b
commit
f13524346b
@ -71,6 +71,7 @@
|
||||
|
||||
static int lkm_v = 0;
|
||||
static int lkm_state = LKMS_IDLE;
|
||||
static char modname[MAXLKMNAME];
|
||||
|
||||
#ifndef MAXLKMS
|
||||
#define MAXLKMS 20
|
||||
@ -132,6 +133,7 @@ lkmunreserve()
|
||||
if (curp && curp->area) {
|
||||
kmem_free(kmem_map, curp->area, curp->size);/**/
|
||||
curp->area = 0;
|
||||
curp->private.lkm_any = NULL;
|
||||
}
|
||||
|
||||
lkm_state = LKMS_IDLE;
|
||||
@ -177,7 +179,7 @@ lkmcioctl(dev, cmd, data, flag)
|
||||
int flag;
|
||||
{
|
||||
int err = 0;
|
||||
int i;
|
||||
int i, j;
|
||||
struct lmc_resrv *resrvp;
|
||||
struct lmc_loadbuf *loadbufp;
|
||||
struct lmc_unload *unloadp;
|
||||
@ -210,7 +212,8 @@ lkmcioctl(dev, cmd, data, flag)
|
||||
* Get memory for module
|
||||
*/
|
||||
curp->size = resrvp->size;
|
||||
|
||||
/* XXX RIXME: Save the module name for sanity checking. */
|
||||
strcpy(modname,resrvp->name);
|
||||
curp->area = kmem_alloc(kmem_map, curp->size);/**/
|
||||
|
||||
curp->offset = 0; /* load offset */
|
||||
@ -289,7 +292,30 @@ lkmcioctl(dev, cmd, data, flag)
|
||||
#endif /* DEBUG */
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that this isn't a duplicate module (broken
|
||||
* modules are too stupid to check this for
|
||||
* themselves). We must do this *BEFORE* we call
|
||||
* the entry point of the module, since we might
|
||||
* be able to unload the module aftwewards without
|
||||
* panicking the system. This defeats the purpose of
|
||||
* the lkmexists() checking that takes place for
|
||||
* properly designed modules, but I can't find a better
|
||||
* way to do it, so...
|
||||
* XXX FIXME: Name matching can easily be defeated if
|
||||
* the user renames the module. :(
|
||||
*/
|
||||
for (j = 0; j < MAXLKMS; j++) {
|
||||
if (!lkmods[j].used || &lkmods[j] == curp)
|
||||
continue;
|
||||
if (!strcmp(modname,
|
||||
lkmods[j].private.lkm_any->lkm_name)) {
|
||||
lkm_state = LKMS_UNLOADING;
|
||||
lkmunreserve();
|
||||
curp->used = 0;
|
||||
return EBUSY;
|
||||
}
|
||||
}
|
||||
curp->entry = (int (*)()) (*((int *) (data)));
|
||||
|
||||
/* call entry(load)... (assigns "private" portion) */
|
||||
@ -304,7 +330,35 @@ lkmcioctl(dev, cmd, data, flag)
|
||||
curp->used = 0; /* free slot */
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX FIXME: Somebody has apparently decided that we can
|
||||
* load modules that don't play by the rules, which means
|
||||
* they have no proper startup and shutdown routines,
|
||||
* and consequently they have no 'private' sections.
|
||||
* This is bad ju-ju: no private section means no lkm_name,
|
||||
* and no lkm_name means modstat will panic us. To
|
||||
* protect ourselves, we have to dummy up an lkm_any
|
||||
* structure by ourselves.
|
||||
*/
|
||||
if (curp->private.lkm_any == NULL) {
|
||||
#ifdef DEBUG
|
||||
/* chastise the module programmer for being a dolt */
|
||||
printf("warning: module #%d has no 'private' data!\n",
|
||||
curp->id);
|
||||
#endif
|
||||
/* We lose some memory here, but we can't unload
|
||||
this module anyway, so what the hell. */
|
||||
curp->private.lkm_any = malloc(sizeof(struct lkm_any),
|
||||
M_IOCTLOPS, M_WAITOK);
|
||||
/* This is all thoroughly bogus,
|
||||
but it's better than a panic. */
|
||||
curp->private.lkm_any->lkm_offset = 0;
|
||||
curp->private.lkm_any->lkm_ver = LKM_VERSION;
|
||||
curp->private.lkm_any->lkm_type = LM_UNKNOWN;
|
||||
curp->private.lkm_any->lkm_name = malloc(MAXLKMNAME,
|
||||
M_IOCTLOPS, M_WAITOK);
|
||||
strcpy(curp->private.lkm_any->lkm_name, modname);
|
||||
}
|
||||
curp->used = 1;
|
||||
#ifdef DEBUG
|
||||
printf("LKM: LMREADY\n");
|
||||
@ -353,11 +407,24 @@ lkmcioctl(dev, cmd, data, flag)
|
||||
err = ENOENT;
|
||||
break;
|
||||
}
|
||||
|
||||
/* call entry(unload) */
|
||||
if ((*(curp->entry))(curp, LKM_E_UNLOAD, LKM_VERSION)) {
|
||||
/*
|
||||
* XXX FIXME: Remember those modules without the 'private'
|
||||
* sections? Don't even *think* about unloading them.
|
||||
*/
|
||||
if (curp->private.lkm_any->lkm_type == LM_UNKNOWN) {
|
||||
#ifdef DEBUG
|
||||
/* abuse the module programmer again. */
|
||||
printf ("warning: module #%d can't be unloaded!\n",
|
||||
curp->id);
|
||||
#endif
|
||||
err = EBUSY;
|
||||
break;
|
||||
} else {
|
||||
/* call entry(unload) */
|
||||
if ((*(curp->entry))(curp, LKM_E_UNLOAD, LKM_VERSION)) {
|
||||
err = EBUSY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lkm_state = LKMS_UNLOADING; /* non-idle for lkmunreserve */
|
||||
|
Loading…
x
Reference in New Issue
Block a user