diff --git a/sys/kern/kern_lkm.c b/sys/kern/kern_lkm.c index b2e568c1d5d8..ebcf101dadbd 100644 --- a/sys/kern/kern_lkm.c +++ b/sys/kern/kern_lkm.c @@ -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 */