Don't crash when a connection list has invalid NIDs.

PR#32485 by Samuel Tran
This commit is contained in:
kent 2006-01-16 14:15:26 +00:00
parent 8b18b188e0
commit dd89fc8bd6
2 changed files with 54 additions and 22 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: azalia.c,v 1.18 2006/01/08 16:52:42 kent Exp $ */
/* $NetBSD: azalia.c,v 1.19 2006/01/16 14:15:26 kent Exp $ */
/*-
* Copyright (c) 2005 The NetBSD Foundation, Inc.
@ -49,7 +49,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: azalia.c,v 1.18 2006/01/08 16:52:42 kent Exp $");
__KERNEL_RCSID(0, "$NetBSD: azalia.c,v 1.19 2006/01/16 14:15:26 kent Exp $");
#include <sys/param.h>
#include <sys/device.h>
@ -1004,6 +1004,10 @@ azalia_codec_init(codec_t *this)
COP_AMPCAP_NUMSTEPS(result), COP_AMPCAP_OFFSET(result)));
#endif
strlcpy(this->w[CORB_NID_ROOT].name, "root",
sizeof(this->w[CORB_NID_ROOT].name));
strlcpy(this->w[this->audiofunc].name, "hdaudio",
sizeof(this->w[this->audiofunc].name));
FOR_EACH_WIDGET(this, i) {
err = azalia_widget_init(&this->w[i], this, i);
if (err)
@ -1303,7 +1307,7 @@ azalia_mixer_init(codec_t *this)
*/
mixer_item_t *m;
int nadcs;
int err, i, j;
int err, i, j, k;
nadcs = 0;
this->maxmixers = 10;
@ -1366,7 +1370,6 @@ azalia_mixer_init(codec_t *this)
FOR_EACH_WIDGET(this, i) {
const widget_t *w;
DPRINTF(("%s: process w[%d]\n", __func__, i));
w = &this->w[i];
if (w->type == COP_AWTYPE_AUDIO_INPUT)
@ -1388,15 +1391,18 @@ azalia_mixer_init(codec_t *this)
d->next = AUDIO_MIXER_LAST;
d->prev = AUDIO_MIXER_LAST;
m->target = MI_TARGET_CONNLIST;
for (j = 0; j < w->nconnections && j < 32; j++) {
d->un.e.member[j].ord = j;
for (j = 0, k = 0; j < w->nconnections && k < 32; j++) {
if (!VALID_WIDGET_NID(w->connections[j], this))
continue;
d->un.e.member[k].ord = k;
DPRINTF(("%s: selector %d=%s\n", __func__, j,
this->w[w->connections[j]].name));
strlcpy(d->un.e.member[j].label.name,
strlcpy(d->un.e.member[k].label.name,
this->w[w->connections[j]].name,
MAX_AUDIO_DEV_LEN);
k++;
}
d->un.e.num_mem = j;
d->un.e.num_mem = k;
this->nmixers++;
}
@ -1467,6 +1473,8 @@ azalia_mixer_init(codec_t *this)
DPRINTF(("%s: input mute %s\n", __func__, w->name));
for (j = 0; j < w->nconnections; j++) {
MIXER_REG_PROLOG;
if (!VALID_WIDGET_NID(w->connections[j], this))
continue;
DPRINTF(("%s: input mute %s.%s\n", __func__,
w->name, this->w[w->connections[j]].name));
snprintf(d->label.name, sizeof(d->label.name),
@ -1499,6 +1507,8 @@ azalia_mixer_init(codec_t *this)
DPRINTF(("%s: input gain %s\n", __func__, w->name));
for (j = 0; j < w->nconnections; j++) {
MIXER_REG_PROLOG;
if (!VALID_WIDGET_NID(w->connections[j], this))
continue;
DPRINTF(("%s: input gain %s.%s\n", __func__,
w->name, this->w[w->connections[j]].name));
snprintf(d->label.name, sizeof(d->label.name),
@ -1795,11 +1805,18 @@ azalia_mixer_get(const codec_t *this, mixer_ctrl_t *mc)
/* selection */
else if (m->target == MI_TARGET_CONNLIST) {
int i;
err = this->comresp(this, m->nid,
CORB_GET_CONNECTION_SELECT_CONTROL, 0, &result);
if (err)
return err;
mc->un.ord = CORB_CSC_INDEX(result);
result = CORB_CSC_INDEX(result);
mc->un.ord = -1;
for (i = 0; i <= result; i++) {
if (!VALID_WIDGET_NID(this->w[m->nid].connections[i], this))
continue;
mc->un.ord++;
}
}
/* pin I/O */
@ -2018,10 +2035,18 @@ azalia_mixer_set(codec_t *this, const mixer_ctrl_t *mc)
/* selection */
else if (m->target == MI_TARGET_CONNLIST) {
if (mc->un.ord >= this->w[m->nid].nconnections)
int i;
for (i = 0, value = 0; i < this->w[m->nid].nconnections; i++) {
if (!VALID_WIDGET_NID(this->w[m->nid].connections[i], this))
continue;
if (value == mc->un.ord)
break;
value++;
}
if (i >= this->w[m->nid].nconnections)
return EINVAL;
err = this->comresp(this, m->nid,
CORB_SET_CONNECTION_SELECT_CONTROL, mc->un.ord, &result);
CORB_SET_CONNECTION_SELECT_CONTROL, i, &result);
if (err)
return err;
}
@ -2417,31 +2442,35 @@ azalia_widget_init_connection(widget_t *this, const codec_t *codec)
length = COP_CLL_LENGTH(result);
if (length == 0)
return 0;
DPRINTF(("%s: CLE=0x%x\n", __func__, result));
this->nconnections = length;
this->connections = malloc(sizeof(nid_t) * length, M_DEVBUF, M_NOWAIT);
this->connections = malloc(sizeof(nid_t) * (length + 3),
M_DEVBUF, M_NOWAIT);
if (this->connections == NULL) {
aprint_error("%s: out of memory\n", XNAME(codec->az));
return ENOMEM;
}
if (longform) {
for (i = 0; i < length; i += 2) {
for (i = 0; i < length;) {
err = codec->comresp(codec, this->nid,
CORB_GET_CONNECTION_LIST_ENTRY, i, &result);
if (err)
return err;
this->connections[i] = CORB_CLE_LONG_0(result);
this->connections[i+1] = CORB_CLE_LONG_1(result);
DPRINTF(("%s: long[%d]=0x%x\n", __func__, i, result));
this->connections[i++] = CORB_CLE_LONG_0(result);
this->connections[i++] = CORB_CLE_LONG_1(result);
}
} else {
for (i = 0; i < length; i += 4) {
for (i = 0; i < length;) {
err = codec->comresp(codec, this->nid,
CORB_GET_CONNECTION_LIST_ENTRY, i, &result);
if (err)
return err;
this->connections[i] = CORB_CLE_SHORT_0(result);
this->connections[i+1] = CORB_CLE_SHORT_1(result);
this->connections[i+2] = CORB_CLE_SHORT_2(result);
this->connections[i+3] = CORB_CLE_SHORT_3(result);
DPRINTF(("%s: short[%d]=0x%x\n", __func__, i, result));
this->connections[i++] = CORB_CLE_SHORT_0(result);
this->connections[i++] = CORB_CLE_SHORT_1(result);
this->connections[i++] = CORB_CLE_SHORT_2(result);
this->connections[i++] = CORB_CLE_SHORT_3(result);
}
}
if (length > 0) {
@ -2456,7 +2485,6 @@ azalia_widget_init_connection(widget_t *this, const codec_t *codec)
return err;
this->selected = CORB_CSC_INDEX(result);
DPRINTF(("; selected=0x%x\n", this->connections[result]));
}
return 0;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: azalia.h,v 1.5 2006/01/03 14:16:29 kent Exp $ */
/* $NetBSD: azalia.h,v 1.6 2006/01/16 14:15:26 kent Exp $ */
/*-
* Copyright (c) 2005 The NetBSD Foundation, Inc.
@ -507,6 +507,10 @@ typedef struct {
#define MI_TARGET_VOLUME 0x106
} mixer_item_t;
#define VALID_WIDGET_NID(nid, codec) (nid == (codec)->audiofunc || \
(nid >= (codec)->wstart && \
nid < (codec)->wend))
typedef struct {
int nconv;
nid_t conv[HDA_MAX_CHANNELS];