diff options
author | ariff <ariff@FreeBSD.org> | 2007-03-15 16:41:27 +0000 |
---|---|---|
committer | ariff <ariff@FreeBSD.org> | 2007-03-15 16:41:27 +0000 |
commit | 2de8168c3fd8f063e61cd20eda0fdd329a5bd131 (patch) | |
tree | d884183f5f2b6415baec7ed56444b465df96b56a /sys/dev/sound/isa | |
parent | 48dd70126224a7269bc4cb5c7c3cf730ace40c7b (diff) | |
download | FreeBSD-src-2de8168c3fd8f063e61cd20eda0fdd329a5bd131.zip FreeBSD-src-2de8168c3fd8f063e61cd20eda0fdd329a5bd131.tar.gz |
Fix severe out-of-bound mtx "type" pointer, causing WITNESS refcount
confusions and panic provided that the following conditions are met:
1) WITNESS is enabled (watch/trace).
2) Using modules, instead of statically linked (Not a strict
requirement, but easier to reproduce this way).
3) 2 or more modules share the same mtx type ("sound softc").
- They might share the same name (strcmp() == 0), but it always
point to different address.
4) Repetitive kldunload/load on any module that shares the same mtx
type (Not a strict requirement, but easier to reproduce this way).
Consider module A and module B:
- From enroll() - subr_witness.c:
* Load module A. Everything seems fine right now.
wA-w_refcount == 1 ; wA-w_name = "sound softc"
* Load module B.
* w->w_name == description will always fail.
("sound softc" from A and B point to different address).
* wA->w_refcount > 0 && strcmp(description, wA->w_name) == 0
* enroll() will return wA instead of returning (possibly unique)
wB.
wA->w_refcount++ , == 2.
* Unload module A, mtx_destroy(), wA->w_name become invalid,
but wA->w_refcount-- become 1 instead of 0. wA will not be
removed from witness list.
* Some other places call mtx_init(), iterating witness list,
found wA, failed on wA->w_name == description
* wA->w_refcount > 0 && strcmp(description, wA->w_name)
* Panic on strcmp() since wA->w_name no longer point to valid
address.
Note that this could happened in other places as well, not just sound
(eg. consider lots of drivers that share simmilar MTX_NETWORK_LOCK).
Solutions (for sound case):
1) Provide unique mtx type string for each mutex creation (chosen)
or
2) Put "sound softc" global variable somewhere and use it.
Diffstat (limited to 'sys/dev/sound/isa')
-rw-r--r-- | sys/dev/sound/isa/ad1816.c | 3 | ||||
-rw-r--r-- | sys/dev/sound/isa/mss.c | 2 | ||||
-rw-r--r-- | sys/dev/sound/isa/sbc.c | 3 |
3 files changed, 5 insertions, 3 deletions
diff --git a/sys/dev/sound/isa/ad1816.c b/sys/dev/sound/isa/ad1816.c index 283f66f..eb05e5e 100644 --- a/sys/dev/sound/isa/ad1816.c +++ b/sys/dev/sound/isa/ad1816.c @@ -601,7 +601,8 @@ ad1816_attach(device_t dev) ad1816 = (struct ad1816_info *)malloc(sizeof *ad1816, M_DEVBUF, M_NOWAIT | M_ZERO); if (!ad1816) return ENXIO; - ad1816->lock = snd_mtxcreate(device_get_nameunit(dev), "sound softc"); + ad1816->lock = snd_mtxcreate(device_get_nameunit(dev), + "snd_ad1816 softc"); ad1816->io_rid = 2; ad1816->irq_rid = 0; ad1816->drq1_rid = 0; diff --git a/sys/dev/sound/isa/mss.c b/sys/dev/sound/isa/mss.c index 22af6e7..4820eed 100644 --- a/sys/dev/sound/isa/mss.c +++ b/sys/dev/sound/isa/mss.c @@ -1696,7 +1696,7 @@ mss_doattach(device_t dev, struct mss_info *mss) int pdma, rdma, flags = device_get_flags(dev); char status[SND_STATUSLEN], status2[SND_STATUSLEN]; - mss->lock = snd_mtxcreate(device_get_nameunit(dev), "sound softc"); + mss->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_mss softc"); mss->bufsize = pcm_getbuffersize(dev, 4096, MSS_DEFAULT_BUFSZ, 65536); if (!mss_alloc_resources(mss, dev)) goto no; mss_init(mss, dev); diff --git a/sys/dev/sound/isa/sbc.c b/sys/dev/sound/isa/sbc.c index ef4b119..9cbe523 100644 --- a/sys/dev/sound/isa/sbc.c +++ b/sys/dev/sound/isa/sbc.c @@ -120,7 +120,8 @@ static void sb_setmixer(struct resource *io, u_int port, u_int value); static void sbc_lockinit(struct sbc_softc *scp) { - scp->lock = snd_mtxcreate(device_get_nameunit(scp->dev), "sound softc"); + scp->lock = snd_mtxcreate(device_get_nameunit(scp->dev), + "snd_sbc softc"); } static void |