ALSA: emu10k1: validate parameters of snd_emu10k1_ptr_{read,write}()
authorOswald Buddenhagen <oswald.buddenhagen@gmx.de>
Sun, 14 May 2023 17:03:21 +0000 (19:03 +0200)
committerTakashi Iwai <tiwai@suse.de>
Mon, 15 May 2023 20:00:55 +0000 (22:00 +0200)
Rather than applying masks to the provided values, make assertions
about them being valid - otherwise we'd just try to paper over bugs.

Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
Link: https://lore.kernel.org/r/20230514170323.3408798-2-oswald.buddenhagen@gmx.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/emu10k1/io.c

index aee84c3..ced6916 100644 (file)
 #include <linux/export.h>
 #include "p17v.h"
 
+static inline bool check_ptr_reg(struct snd_emu10k1 *emu, unsigned int reg)
+{
+       if (snd_BUG_ON(!emu))
+               return false;
+       if (snd_BUG_ON(reg & (emu->audigy ? (0xffff0000 & ~A_PTR_ADDRESS_MASK)
+                                         : (0xffff0000 & ~PTR_ADDRESS_MASK))))
+               return false;
+       if (snd_BUG_ON(reg & 0x0000ffff & ~PTR_CHANNELNUM_MASK))
+               return false;
+       return true;
+}
+
 unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn)
 {
        unsigned long flags;
        unsigned int regptr, val;
        unsigned int mask;
 
-       mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
-       regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
+       regptr = (reg << 16) | chn;
+       if (!check_ptr_reg(emu, regptr))
+               return 0;
 
        if (reg & 0xff000000) {
                unsigned char size, offset;
@@ -57,18 +70,20 @@ void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned i
        unsigned long flags;
        unsigned int mask;
 
-       if (snd_BUG_ON(!emu))
+       regptr = (reg << 16) | chn;
+       if (!check_ptr_reg(emu, regptr))
                return;
-       mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
-       regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
 
        if (reg & 0xff000000) {
                unsigned char size, offset;
 
                size = (reg >> 24) & 0x3f;
                offset = (reg >> 16) & 0x1f;
-               mask = ((1 << size) - 1) << offset;
-               data = (data << offset) & mask;
+               mask = (1 << size) - 1;
+               if (snd_BUG_ON(data & ~mask))
+                       return;
+               mask <<= offset;
+               data <<= offset;
 
                spin_lock_irqsave(&emu->emu_lock, flags);
                outl(regptr, emu->port + PTR);