summaryrefslogtreecommitdiffstats
path: root/sys/dev/sound/isa
diff options
context:
space:
mode:
authorariff <ariff@FreeBSD.org>2007-03-15 16:41:27 +0000
committerariff <ariff@FreeBSD.org>2007-03-15 16:41:27 +0000
commit2de8168c3fd8f063e61cd20eda0fdd329a5bd131 (patch)
treed884183f5f2b6415baec7ed56444b465df96b56a /sys/dev/sound/isa
parent48dd70126224a7269bc4cb5c7c3cf730ace40c7b (diff)
downloadFreeBSD-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.c3
-rw-r--r--sys/dev/sound/isa/mss.c2
-rw-r--r--sys/dev/sound/isa/sbc.c3
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
OpenPOWER on IntegriCloud