1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
/* { dg-do compile } */
/* { dg-options "-fanalyzer" } */
/* { dg-require-effective-target analyzer } */
/* Reduced from a -Wanalyzer-tainted-array-index false +ve
seen in the Linux kernel's sound/drivers/opl3/opl3_synth.c. */
extern unsigned long
copy_from_user(void* to, const void* from, unsigned long n);
struct sbi_patch
{
unsigned char prog;
unsigned char bank;
};
struct fm_patch
{
unsigned char prog;
unsigned char bank;
struct fm_patch* next;
};
struct snd_opl3
{
struct fm_patch* patch_table[32];
};
int
snd_opl3_load_patch(struct snd_opl3* opl3,
int prog,
int bank);
struct fm_patch*
snd_opl3_find_patch(struct snd_opl3* opl3,
int prog,
int bank,
int create_patch);
long
snd_opl3_write(struct snd_opl3* opl3,
const char* buf,
long count)
{
long result = 0;
int err = 0;
struct sbi_patch inst;
while (count >= sizeof(inst)) {
if (copy_from_user(&inst, buf, sizeof(inst)))
return -14;
err = snd_opl3_load_patch(opl3, inst.prog, inst.bank);
if (err < 0)
break;
result += sizeof(inst);
count -= sizeof(inst);
}
return result > 0 ? result : err;
}
int
snd_opl3_load_patch(struct snd_opl3* opl3,
int prog,
int bank)
{
struct fm_patch* patch;
patch = snd_opl3_find_patch(opl3, prog, bank, 1);
if (!patch)
return -12;
return 0;
}
struct fm_patch*
snd_opl3_find_patch(struct snd_opl3* opl3, int prog, int bank, int create_patch)
{
unsigned int key = (prog + bank) % 32;
struct fm_patch* patch;
for (patch = opl3->patch_table[key]; patch; patch = patch->next) { /* { dg-bogus "use of attacker-controlled value in array lookup" } */
if (patch->prog == prog && patch->bank == bank)
return patch;
}
return ((void*)0);
}
|