diff options
author | Takashi Iwai <tiwai@suse.de> | 2014-06-18 10:38:45 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2014-06-18 10:38:45 -0400 |
commit | 8d42fda9ea9820d271a40f0bf7ed436647f2ddb9 (patch) | |
tree | 146fda0a84f4fa931a5f47528fd41a9eb133597e /sound | |
parent | 6c0c9a3db486508801cb2ced923c188e828f51d3 (diff) | |
parent | 883a1d49f0d77d30012f114b2e19fc141beb3e8e (diff) |
Merge branch 'topic/core-vuln-fixes' into for-linus
Diffstat (limited to 'sound')
-rw-r--r-- | sound/core/control.c | 78 | ||||
-rw-r--r-- | sound/core/init.c | 1 |
2 files changed, 52 insertions, 27 deletions
diff --git a/sound/core/control.c b/sound/core/control.c index f038f5afafe2..f0b0e14497a5 100644 --- a/sound/core/control.c +++ b/sound/core/control.c | |||
@@ -288,6 +288,10 @@ static bool snd_ctl_remove_numid_conflict(struct snd_card *card, | |||
288 | { | 288 | { |
289 | struct snd_kcontrol *kctl; | 289 | struct snd_kcontrol *kctl; |
290 | 290 | ||
291 | /* Make sure that the ids assigned to the control do not wrap around */ | ||
292 | if (card->last_numid >= UINT_MAX - count) | ||
293 | card->last_numid = 0; | ||
294 | |||
291 | list_for_each_entry(kctl, &card->controls, list) { | 295 | list_for_each_entry(kctl, &card->controls, list) { |
292 | if (kctl->id.numid < card->last_numid + 1 + count && | 296 | if (kctl->id.numid < card->last_numid + 1 + count && |
293 | kctl->id.numid + kctl->count > card->last_numid + 1) { | 297 | 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) | |||
330 | { | 334 | { |
331 | struct snd_ctl_elem_id id; | 335 | struct snd_ctl_elem_id id; |
332 | unsigned int idx; | 336 | unsigned int idx; |
337 | unsigned int count; | ||
333 | int err = -EINVAL; | 338 | int err = -EINVAL; |
334 | 339 | ||
335 | if (! kcontrol) | 340 | if (! kcontrol) |
@@ -337,6 +342,9 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) | |||
337 | if (snd_BUG_ON(!card || !kcontrol->info)) | 342 | if (snd_BUG_ON(!card || !kcontrol->info)) |
338 | goto error; | 343 | goto error; |
339 | id = kcontrol->id; | 344 | id = kcontrol->id; |
345 | if (id.index > UINT_MAX - kcontrol->count) | ||
346 | goto error; | ||
347 | |||
340 | down_write(&card->controls_rwsem); | 348 | down_write(&card->controls_rwsem); |
341 | if (snd_ctl_find_id(card, &id)) { | 349 | if (snd_ctl_find_id(card, &id)) { |
342 | up_write(&card->controls_rwsem); | 350 | up_write(&card->controls_rwsem); |
@@ -358,8 +366,9 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) | |||
358 | card->controls_count += kcontrol->count; | 366 | card->controls_count += kcontrol->count; |
359 | kcontrol->id.numid = card->last_numid + 1; | 367 | kcontrol->id.numid = card->last_numid + 1; |
360 | card->last_numid += kcontrol->count; | 368 | card->last_numid += kcontrol->count; |
369 | count = kcontrol->count; | ||
361 | up_write(&card->controls_rwsem); | 370 | up_write(&card->controls_rwsem); |
362 | for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++) | 371 | for (idx = 0; idx < count; idx++, id.index++, id.numid++) |
363 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id); | 372 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id); |
364 | return 0; | 373 | return 0; |
365 | 374 | ||
@@ -388,6 +397,7 @@ int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol, | |||
388 | bool add_on_replace) | 397 | bool add_on_replace) |
389 | { | 398 | { |
390 | struct snd_ctl_elem_id id; | 399 | struct snd_ctl_elem_id id; |
400 | unsigned int count; | ||
391 | unsigned int idx; | 401 | unsigned int idx; |
392 | struct snd_kcontrol *old; | 402 | struct snd_kcontrol *old; |
393 | int ret; | 403 | int ret; |
@@ -423,8 +433,9 @@ add: | |||
423 | card->controls_count += kcontrol->count; | 433 | card->controls_count += kcontrol->count; |
424 | kcontrol->id.numid = card->last_numid + 1; | 434 | kcontrol->id.numid = card->last_numid + 1; |
425 | card->last_numid += kcontrol->count; | 435 | card->last_numid += kcontrol->count; |
436 | count = kcontrol->count; | ||
426 | up_write(&card->controls_rwsem); | 437 | up_write(&card->controls_rwsem); |
427 | for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++) | 438 | for (idx = 0; idx < count; idx++, id.index++, id.numid++) |
428 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id); | 439 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id); |
429 | return 0; | 440 | return 0; |
430 | 441 | ||
@@ -897,9 +908,9 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, | |||
897 | result = kctl->put(kctl, control); | 908 | result = kctl->put(kctl, control); |
898 | } | 909 | } |
899 | if (result > 0) { | 910 | if (result > 0) { |
911 | struct snd_ctl_elem_id id = control->id; | ||
900 | up_read(&card->controls_rwsem); | 912 | up_read(&card->controls_rwsem); |
901 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, | 913 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &id); |
902 | &control->id); | ||
903 | return 0; | 914 | return 0; |
904 | } | 915 | } |
905 | } | 916 | } |
@@ -991,6 +1002,7 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file, | |||
991 | 1002 | ||
992 | struct user_element { | 1003 | struct user_element { |
993 | struct snd_ctl_elem_info info; | 1004 | struct snd_ctl_elem_info info; |
1005 | struct snd_card *card; | ||
994 | void *elem_data; /* element data */ | 1006 | void *elem_data; /* element data */ |
995 | unsigned long elem_data_size; /* size of element data in bytes */ | 1007 | unsigned long elem_data_size; /* size of element data in bytes */ |
996 | void *tlv_data; /* TLV data */ | 1008 | void *tlv_data; /* TLV data */ |
@@ -1034,7 +1046,9 @@ static int snd_ctl_elem_user_get(struct snd_kcontrol *kcontrol, | |||
1034 | { | 1046 | { |
1035 | struct user_element *ue = kcontrol->private_data; | 1047 | struct user_element *ue = kcontrol->private_data; |
1036 | 1048 | ||
1049 | mutex_lock(&ue->card->user_ctl_lock); | ||
1037 | memcpy(&ucontrol->value, ue->elem_data, ue->elem_data_size); | 1050 | memcpy(&ucontrol->value, ue->elem_data, ue->elem_data_size); |
1051 | mutex_unlock(&ue->card->user_ctl_lock); | ||
1038 | return 0; | 1052 | return 0; |
1039 | } | 1053 | } |
1040 | 1054 | ||
@@ -1043,10 +1057,12 @@ static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol, | |||
1043 | { | 1057 | { |
1044 | int change; | 1058 | int change; |
1045 | struct user_element *ue = kcontrol->private_data; | 1059 | struct user_element *ue = kcontrol->private_data; |
1046 | 1060 | ||
1061 | mutex_lock(&ue->card->user_ctl_lock); | ||
1047 | change = memcmp(&ucontrol->value, ue->elem_data, ue->elem_data_size) != 0; | 1062 | change = memcmp(&ucontrol->value, ue->elem_data, ue->elem_data_size) != 0; |
1048 | if (change) | 1063 | if (change) |
1049 | memcpy(ue->elem_data, &ucontrol->value, ue->elem_data_size); | 1064 | memcpy(ue->elem_data, &ucontrol->value, ue->elem_data_size); |
1065 | mutex_unlock(&ue->card->user_ctl_lock); | ||
1050 | return change; | 1066 | return change; |
1051 | } | 1067 | } |
1052 | 1068 | ||
@@ -1066,19 +1082,32 @@ static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol, | |||
1066 | new_data = memdup_user(tlv, size); | 1082 | new_data = memdup_user(tlv, size); |
1067 | if (IS_ERR(new_data)) | 1083 | if (IS_ERR(new_data)) |
1068 | return PTR_ERR(new_data); | 1084 | return PTR_ERR(new_data); |
1085 | mutex_lock(&ue->card->user_ctl_lock); | ||
1069 | change = ue->tlv_data_size != size; | 1086 | change = ue->tlv_data_size != size; |
1070 | if (!change) | 1087 | if (!change) |
1071 | change = memcmp(ue->tlv_data, new_data, size); | 1088 | change = memcmp(ue->tlv_data, new_data, size); |
1072 | kfree(ue->tlv_data); | 1089 | kfree(ue->tlv_data); |
1073 | ue->tlv_data = new_data; | 1090 | ue->tlv_data = new_data; |
1074 | ue->tlv_data_size = size; | 1091 | ue->tlv_data_size = size; |
1092 | mutex_unlock(&ue->card->user_ctl_lock); | ||
1075 | } else { | 1093 | } else { |
1076 | if (! ue->tlv_data_size || ! ue->tlv_data) | 1094 | int ret = 0; |
1077 | return -ENXIO; | 1095 | |
1078 | if (size < ue->tlv_data_size) | 1096 | mutex_lock(&ue->card->user_ctl_lock); |
1079 | return -ENOSPC; | 1097 | if (!ue->tlv_data_size || !ue->tlv_data) { |
1098 | ret = -ENXIO; | ||
1099 | goto err_unlock; | ||
1100 | } | ||
1101 | if (size < ue->tlv_data_size) { | ||
1102 | ret = -ENOSPC; | ||
1103 | goto err_unlock; | ||
1104 | } | ||
1080 | if (copy_to_user(tlv, ue->tlv_data, ue->tlv_data_size)) | 1105 | if (copy_to_user(tlv, ue->tlv_data, ue->tlv_data_size)) |
1081 | return -EFAULT; | 1106 | ret = -EFAULT; |
1107 | err_unlock: | ||
1108 | mutex_unlock(&ue->card->user_ctl_lock); | ||
1109 | if (ret) | ||
1110 | return ret; | ||
1082 | } | 1111 | } |
1083 | return change; | 1112 | return change; |
1084 | } | 1113 | } |
@@ -1136,8 +1165,6 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, | |||
1136 | struct user_element *ue; | 1165 | struct user_element *ue; |
1137 | int idx, err; | 1166 | int idx, err; |
1138 | 1167 | ||
1139 | if (!replace && card->user_ctl_count >= MAX_USER_CONTROLS) | ||
1140 | return -ENOMEM; | ||
1141 | if (info->count < 1) | 1168 | if (info->count < 1) |
1142 | return -EINVAL; | 1169 | return -EINVAL; |
1143 | access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : | 1170 | access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : |
@@ -1146,21 +1173,16 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, | |||
1146 | SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)); | 1173 | SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)); |
1147 | info->id.numid = 0; | 1174 | info->id.numid = 0; |
1148 | memset(&kctl, 0, sizeof(kctl)); | 1175 | memset(&kctl, 0, sizeof(kctl)); |
1149 | down_write(&card->controls_rwsem); | 1176 | |
1150 | _kctl = snd_ctl_find_id(card, &info->id); | 1177 | if (replace) { |
1151 | err = 0; | 1178 | err = snd_ctl_remove_user_ctl(file, &info->id); |
1152 | if (_kctl) { | 1179 | if (err) |
1153 | if (replace) | 1180 | return err; |
1154 | err = snd_ctl_remove(card, _kctl); | ||
1155 | else | ||
1156 | err = -EBUSY; | ||
1157 | } else { | ||
1158 | if (replace) | ||
1159 | err = -ENOENT; | ||
1160 | } | 1181 | } |
1161 | up_write(&card->controls_rwsem); | 1182 | |
1162 | if (err < 0) | 1183 | if (card->user_ctl_count >= MAX_USER_CONTROLS) |
1163 | return err; | 1184 | return -ENOMEM; |
1185 | |||
1164 | memcpy(&kctl.id, &info->id, sizeof(info->id)); | 1186 | memcpy(&kctl.id, &info->id, sizeof(info->id)); |
1165 | kctl.count = info->owner ? info->owner : 1; | 1187 | kctl.count = info->owner ? info->owner : 1; |
1166 | access |= SNDRV_CTL_ELEM_ACCESS_USER; | 1188 | access |= SNDRV_CTL_ELEM_ACCESS_USER; |
@@ -1210,6 +1232,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, | |||
1210 | ue = kzalloc(sizeof(struct user_element) + private_size, GFP_KERNEL); | 1232 | ue = kzalloc(sizeof(struct user_element) + private_size, GFP_KERNEL); |
1211 | if (ue == NULL) | 1233 | if (ue == NULL) |
1212 | return -ENOMEM; | 1234 | return -ENOMEM; |
1235 | ue->card = card; | ||
1213 | ue->info = *info; | 1236 | ue->info = *info; |
1214 | ue->info.access = 0; | 1237 | ue->info.access = 0; |
1215 | ue->elem_data = (char *)ue + sizeof(*ue); | 1238 | ue->elem_data = (char *)ue + sizeof(*ue); |
@@ -1321,8 +1344,9 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, | |||
1321 | } | 1344 | } |
1322 | err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv); | 1345 | err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv); |
1323 | if (err > 0) { | 1346 | if (err > 0) { |
1347 | struct snd_ctl_elem_id id = kctl->id; | ||
1324 | up_read(&card->controls_rwsem); | 1348 | up_read(&card->controls_rwsem); |
1325 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &kctl->id); | 1349 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &id); |
1326 | return 0; | 1350 | return 0; |
1327 | } | 1351 | } |
1328 | } else { | 1352 | } else { |
diff --git a/sound/core/init.c b/sound/core/init.c index 5ee83845c5de..7bdfd19e24a8 100644 --- a/sound/core/init.c +++ b/sound/core/init.c | |||
@@ -232,6 +232,7 @@ int snd_card_new(struct device *parent, int idx, const char *xid, | |||
232 | INIT_LIST_HEAD(&card->devices); | 232 | INIT_LIST_HEAD(&card->devices); |
233 | init_rwsem(&card->controls_rwsem); | 233 | init_rwsem(&card->controls_rwsem); |
234 | rwlock_init(&card->ctl_files_rwlock); | 234 | rwlock_init(&card->ctl_files_rwlock); |
235 | mutex_init(&card->user_ctl_lock); | ||
235 | INIT_LIST_HEAD(&card->controls); | 236 | INIT_LIST_HEAD(&card->controls); |
236 | INIT_LIST_HEAD(&card->ctl_files); | 237 | INIT_LIST_HEAD(&card->ctl_files); |
237 | spin_lock_init(&card->files_lock); | 238 | spin_lock_init(&card->files_lock); |