mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-09 23:00:21 +00:00
Merge branch 'topic/core-vuln-fixes' into for-linus
This commit is contained in:
commit
8d42fda9ea
@ -116,6 +116,8 @@ struct snd_card {
|
|||||||
int user_ctl_count; /* count of all user controls */
|
int user_ctl_count; /* count of all user controls */
|
||||||
struct list_head controls; /* all controls for this card */
|
struct list_head controls; /* all controls for this card */
|
||||||
struct list_head ctl_files; /* active control files */
|
struct list_head ctl_files; /* active control files */
|
||||||
|
struct mutex user_ctl_lock; /* protects user controls against
|
||||||
|
concurrent access */
|
||||||
|
|
||||||
struct snd_info_entry *proc_root; /* root for soundcard specific files */
|
struct snd_info_entry *proc_root; /* root for soundcard specific files */
|
||||||
struct snd_info_entry *proc_id; /* the card id */
|
struct snd_info_entry *proc_id; /* the card id */
|
||||||
|
@ -288,6 +288,10 @@ static bool snd_ctl_remove_numid_conflict(struct snd_card *card,
|
|||||||
{
|
{
|
||||||
struct snd_kcontrol *kctl;
|
struct snd_kcontrol *kctl;
|
||||||
|
|
||||||
|
/* Make sure that the ids assigned to the control do not wrap around */
|
||||||
|
if (card->last_numid >= UINT_MAX - count)
|
||||||
|
card->last_numid = 0;
|
||||||
|
|
||||||
list_for_each_entry(kctl, &card->controls, list) {
|
list_for_each_entry(kctl, &card->controls, list) {
|
||||||
if (kctl->id.numid < card->last_numid + 1 + count &&
|
if (kctl->id.numid < card->last_numid + 1 + count &&
|
||||||
kctl->id.numid + kctl->count > card->last_numid + 1) {
|
kctl->id.numid + kctl->count > card->last_numid + 1) {
|
||||||
@ -330,6 +334,7 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
|
|||||||
{
|
{
|
||||||
struct snd_ctl_elem_id id;
|
struct snd_ctl_elem_id id;
|
||||||
unsigned int idx;
|
unsigned int idx;
|
||||||
|
unsigned int count;
|
||||||
int err = -EINVAL;
|
int err = -EINVAL;
|
||||||
|
|
||||||
if (! kcontrol)
|
if (! kcontrol)
|
||||||
@ -337,6 +342,9 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
|
|||||||
if (snd_BUG_ON(!card || !kcontrol->info))
|
if (snd_BUG_ON(!card || !kcontrol->info))
|
||||||
goto error;
|
goto error;
|
||||||
id = kcontrol->id;
|
id = kcontrol->id;
|
||||||
|
if (id.index > UINT_MAX - kcontrol->count)
|
||||||
|
goto error;
|
||||||
|
|
||||||
down_write(&card->controls_rwsem);
|
down_write(&card->controls_rwsem);
|
||||||
if (snd_ctl_find_id(card, &id)) {
|
if (snd_ctl_find_id(card, &id)) {
|
||||||
up_write(&card->controls_rwsem);
|
up_write(&card->controls_rwsem);
|
||||||
@ -358,8 +366,9 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
|
|||||||
card->controls_count += kcontrol->count;
|
card->controls_count += kcontrol->count;
|
||||||
kcontrol->id.numid = card->last_numid + 1;
|
kcontrol->id.numid = card->last_numid + 1;
|
||||||
card->last_numid += kcontrol->count;
|
card->last_numid += kcontrol->count;
|
||||||
|
count = kcontrol->count;
|
||||||
up_write(&card->controls_rwsem);
|
up_write(&card->controls_rwsem);
|
||||||
for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++)
|
for (idx = 0; idx < count; idx++, id.index++, id.numid++)
|
||||||
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
|
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -388,6 +397,7 @@ int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol,
|
|||||||
bool add_on_replace)
|
bool add_on_replace)
|
||||||
{
|
{
|
||||||
struct snd_ctl_elem_id id;
|
struct snd_ctl_elem_id id;
|
||||||
|
unsigned int count;
|
||||||
unsigned int idx;
|
unsigned int idx;
|
||||||
struct snd_kcontrol *old;
|
struct snd_kcontrol *old;
|
||||||
int ret;
|
int ret;
|
||||||
@ -423,8 +433,9 @@ add:
|
|||||||
card->controls_count += kcontrol->count;
|
card->controls_count += kcontrol->count;
|
||||||
kcontrol->id.numid = card->last_numid + 1;
|
kcontrol->id.numid = card->last_numid + 1;
|
||||||
card->last_numid += kcontrol->count;
|
card->last_numid += kcontrol->count;
|
||||||
|
count = kcontrol->count;
|
||||||
up_write(&card->controls_rwsem);
|
up_write(&card->controls_rwsem);
|
||||||
for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++)
|
for (idx = 0; idx < count; idx++, id.index++, id.numid++)
|
||||||
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
|
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -897,9 +908,9 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
|
|||||||
result = kctl->put(kctl, control);
|
result = kctl->put(kctl, control);
|
||||||
}
|
}
|
||||||
if (result > 0) {
|
if (result > 0) {
|
||||||
|
struct snd_ctl_elem_id id = control->id;
|
||||||
up_read(&card->controls_rwsem);
|
up_read(&card->controls_rwsem);
|
||||||
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
|
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &id);
|
||||||
&control->id);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -991,6 +1002,7 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file,
|
|||||||
|
|
||||||
struct user_element {
|
struct user_element {
|
||||||
struct snd_ctl_elem_info info;
|
struct snd_ctl_elem_info info;
|
||||||
|
struct snd_card *card;
|
||||||
void *elem_data; /* element data */
|
void *elem_data; /* element data */
|
||||||
unsigned long elem_data_size; /* size of element data in bytes */
|
unsigned long elem_data_size; /* size of element data in bytes */
|
||||||
void *tlv_data; /* TLV data */
|
void *tlv_data; /* TLV data */
|
||||||
@ -1034,7 +1046,9 @@ static int snd_ctl_elem_user_get(struct snd_kcontrol *kcontrol,
|
|||||||
{
|
{
|
||||||
struct user_element *ue = kcontrol->private_data;
|
struct user_element *ue = kcontrol->private_data;
|
||||||
|
|
||||||
|
mutex_lock(&ue->card->user_ctl_lock);
|
||||||
memcpy(&ucontrol->value, ue->elem_data, ue->elem_data_size);
|
memcpy(&ucontrol->value, ue->elem_data, ue->elem_data_size);
|
||||||
|
mutex_unlock(&ue->card->user_ctl_lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1043,10 +1057,12 @@ static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol,
|
|||||||
{
|
{
|
||||||
int change;
|
int change;
|
||||||
struct user_element *ue = kcontrol->private_data;
|
struct user_element *ue = kcontrol->private_data;
|
||||||
|
|
||||||
|
mutex_lock(&ue->card->user_ctl_lock);
|
||||||
change = memcmp(&ucontrol->value, ue->elem_data, ue->elem_data_size) != 0;
|
change = memcmp(&ucontrol->value, ue->elem_data, ue->elem_data_size) != 0;
|
||||||
if (change)
|
if (change)
|
||||||
memcpy(ue->elem_data, &ucontrol->value, ue->elem_data_size);
|
memcpy(ue->elem_data, &ucontrol->value, ue->elem_data_size);
|
||||||
|
mutex_unlock(&ue->card->user_ctl_lock);
|
||||||
return change;
|
return change;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1066,19 +1082,32 @@ static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol,
|
|||||||
new_data = memdup_user(tlv, size);
|
new_data = memdup_user(tlv, size);
|
||||||
if (IS_ERR(new_data))
|
if (IS_ERR(new_data))
|
||||||
return PTR_ERR(new_data);
|
return PTR_ERR(new_data);
|
||||||
|
mutex_lock(&ue->card->user_ctl_lock);
|
||||||
change = ue->tlv_data_size != size;
|
change = ue->tlv_data_size != size;
|
||||||
if (!change)
|
if (!change)
|
||||||
change = memcmp(ue->tlv_data, new_data, size);
|
change = memcmp(ue->tlv_data, new_data, size);
|
||||||
kfree(ue->tlv_data);
|
kfree(ue->tlv_data);
|
||||||
ue->tlv_data = new_data;
|
ue->tlv_data = new_data;
|
||||||
ue->tlv_data_size = size;
|
ue->tlv_data_size = size;
|
||||||
|
mutex_unlock(&ue->card->user_ctl_lock);
|
||||||
} else {
|
} else {
|
||||||
if (! ue->tlv_data_size || ! ue->tlv_data)
|
int ret = 0;
|
||||||
return -ENXIO;
|
|
||||||
if (size < ue->tlv_data_size)
|
mutex_lock(&ue->card->user_ctl_lock);
|
||||||
return -ENOSPC;
|
if (!ue->tlv_data_size || !ue->tlv_data) {
|
||||||
|
ret = -ENXIO;
|
||||||
|
goto err_unlock;
|
||||||
|
}
|
||||||
|
if (size < ue->tlv_data_size) {
|
||||||
|
ret = -ENOSPC;
|
||||||
|
goto err_unlock;
|
||||||
|
}
|
||||||
if (copy_to_user(tlv, ue->tlv_data, ue->tlv_data_size))
|
if (copy_to_user(tlv, ue->tlv_data, ue->tlv_data_size))
|
||||||
return -EFAULT;
|
ret = -EFAULT;
|
||||||
|
err_unlock:
|
||||||
|
mutex_unlock(&ue->card->user_ctl_lock);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
return change;
|
return change;
|
||||||
}
|
}
|
||||||
@ -1136,8 +1165,6 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
|
|||||||
struct user_element *ue;
|
struct user_element *ue;
|
||||||
int idx, err;
|
int idx, err;
|
||||||
|
|
||||||
if (!replace && card->user_ctl_count >= MAX_USER_CONTROLS)
|
|
||||||
return -ENOMEM;
|
|
||||||
if (info->count < 1)
|
if (info->count < 1)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
|
access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
|
||||||
@ -1146,21 +1173,16 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
|
|||||||
SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE));
|
SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE));
|
||||||
info->id.numid = 0;
|
info->id.numid = 0;
|
||||||
memset(&kctl, 0, sizeof(kctl));
|
memset(&kctl, 0, sizeof(kctl));
|
||||||
down_write(&card->controls_rwsem);
|
|
||||||
_kctl = snd_ctl_find_id(card, &info->id);
|
if (replace) {
|
||||||
err = 0;
|
err = snd_ctl_remove_user_ctl(file, &info->id);
|
||||||
if (_kctl) {
|
if (err)
|
||||||
if (replace)
|
return err;
|
||||||
err = snd_ctl_remove(card, _kctl);
|
|
||||||
else
|
|
||||||
err = -EBUSY;
|
|
||||||
} else {
|
|
||||||
if (replace)
|
|
||||||
err = -ENOENT;
|
|
||||||
}
|
}
|
||||||
up_write(&card->controls_rwsem);
|
|
||||||
if (err < 0)
|
if (card->user_ctl_count >= MAX_USER_CONTROLS)
|
||||||
return err;
|
return -ENOMEM;
|
||||||
|
|
||||||
memcpy(&kctl.id, &info->id, sizeof(info->id));
|
memcpy(&kctl.id, &info->id, sizeof(info->id));
|
||||||
kctl.count = info->owner ? info->owner : 1;
|
kctl.count = info->owner ? info->owner : 1;
|
||||||
access |= SNDRV_CTL_ELEM_ACCESS_USER;
|
access |= SNDRV_CTL_ELEM_ACCESS_USER;
|
||||||
@ -1210,6 +1232,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
|
|||||||
ue = kzalloc(sizeof(struct user_element) + private_size, GFP_KERNEL);
|
ue = kzalloc(sizeof(struct user_element) + private_size, GFP_KERNEL);
|
||||||
if (ue == NULL)
|
if (ue == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
ue->card = card;
|
||||||
ue->info = *info;
|
ue->info = *info;
|
||||||
ue->info.access = 0;
|
ue->info.access = 0;
|
||||||
ue->elem_data = (char *)ue + sizeof(*ue);
|
ue->elem_data = (char *)ue + sizeof(*ue);
|
||||||
@ -1321,8 +1344,9 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file,
|
|||||||
}
|
}
|
||||||
err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv);
|
err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv);
|
||||||
if (err > 0) {
|
if (err > 0) {
|
||||||
|
struct snd_ctl_elem_id id = kctl->id;
|
||||||
up_read(&card->controls_rwsem);
|
up_read(&card->controls_rwsem);
|
||||||
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &kctl->id);
|
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &id);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -232,6 +232,7 @@ int snd_card_new(struct device *parent, int idx, const char *xid,
|
|||||||
INIT_LIST_HEAD(&card->devices);
|
INIT_LIST_HEAD(&card->devices);
|
||||||
init_rwsem(&card->controls_rwsem);
|
init_rwsem(&card->controls_rwsem);
|
||||||
rwlock_init(&card->ctl_files_rwlock);
|
rwlock_init(&card->ctl_files_rwlock);
|
||||||
|
mutex_init(&card->user_ctl_lock);
|
||||||
INIT_LIST_HEAD(&card->controls);
|
INIT_LIST_HEAD(&card->controls);
|
||||||
INIT_LIST_HEAD(&card->ctl_files);
|
INIT_LIST_HEAD(&card->ctl_files);
|
||||||
spin_lock_init(&card->files_lock);
|
spin_lock_init(&card->files_lock);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user