summaryrefslogtreecommitdiff
path: root/sound/synth
diff options
context:
space:
mode:
authorOswald Buddenhagen <oswald.buddenhagen@gmx.de>2024-04-06 08:48:19 +0200
committerTakashi Iwai <tiwai@suse.de>2024-04-07 08:35:47 +0200
commitde67aab120d4d5ba7d9e94ee5b25464ae0d1bd0e (patch)
treee5be40fc7608720a0e912489ee62e401f39c8e98 /sound/synth
parent1edeac6555e9df008b1729ca445868c1177baa8b (diff)
ALSA: emux: centralize & improve patch info validation
This does several closely related things: - Move the code from the drivers into the SoundFont loader, which de-duplicates it. - Sort of explain the weird "recalculate address offset" feature. Note that I don't think it actually makes any sense - the calling user space code should do that. The background is certainly that the source data (the SoundFont format) uses pointers into a single wave block (and the API allows doing the same for on-board ROM), but the API expects the wave data from user space to be pre-chopped into individual patches anyway. - Make sure that the specified offsets actually lie within the supplied wave data. Note that we don't validate ROM offsets, so one can play back anything within the sound card's address space. - In load_guspatch(), don't call the sample_new callback anymore when the patch size is zero, as was already the case in load_data(). The callbacks would instantly return in that case anyway; these checks are now removed. Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de> Message-ID: <20240406064830.1029573-7-oswald.buddenhagen@gmx.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/synth')
-rw-r--r--sound/synth/emux/soundfont.c37
1 files changed, 36 insertions, 1 deletions
diff --git a/sound/synth/emux/soundfont.c b/sound/synth/emux/soundfont.c
index ad0231d7a39d..6d6f0102ed5b 100644
--- a/sound/synth/emux/soundfont.c
+++ b/sound/synth/emux/soundfont.c
@@ -689,6 +689,21 @@ find_sample(struct snd_soundfont *sf, int sample_id)
}
+static int
+validate_sample_info(struct soundfont_sample_info *si)
+{
+ if (si->end < 0 || si->end > si->size)
+ return -EINVAL;
+ if (si->loopstart < 0 || si->loopstart > si->end)
+ return -EINVAL;
+ if (si->loopend < 0 || si->loopend > si->end)
+ return -EINVAL;
+ /* be sure loop points start < end */
+ if (si->loopstart > si->loopend)
+ swap(si->loopstart, si->loopend);
+ return 0;
+}
+
/*
* Load sample information, this can include data to be loaded onto
* the soundcard. It can also just be a pointer into soundcard ROM.
@@ -727,6 +742,21 @@ load_data(struct snd_sf_list *sflist, const void __user *data, long count)
return -EINVAL;
}
+ if (sample_info.size > 0) {
+ if (sample_info.start < 0)
+ return -EINVAL;
+
+ // Here we "rebase out" the start address, because the
+ // real start is the start of the provided sample data.
+ sample_info.end -= sample_info.start;
+ sample_info.loopstart -= sample_info.start;
+ sample_info.loopend -= sample_info.start;
+ sample_info.start = 0;
+
+ if (validate_sample_info(&sample_info) < 0)
+ return -EINVAL;
+ }
+
/* Allocate a new sample structure */
sp = sf_sample_new(sflist, sf);
if (!sp)
@@ -974,6 +1004,11 @@ load_guspatch(struct snd_sf_list *sflist, const char __user *data, long count)
smp->v.loopend = patch.loop_end;
smp->v.size = patch.len;
+ if (validate_sample_info(&smp->v) < 0) {
+ sf_sample_delete(sflist, sf, smp);
+ return -EINVAL;
+ }
+
/* set up mode flags */
smp->v.mode_flags = 0;
if (!(patch.mode & WAVE_16_BITS))
@@ -1011,7 +1046,7 @@ load_guspatch(struct snd_sf_list *sflist, const char __user *data, long count)
/*
* load wave data
*/
- if (sflist->callback.sample_new) {
+ if (smp->v.size > 0 && sflist->callback.sample_new) {
rc = sflist->callback.sample_new
(sflist->callback.private_data, smp, sflist->memhdr,
data, count);