alsa-utils
alsa-utils copied to clipboard
A potential Integer Overflow bug found in aplay/aplay.c
Hi, I'm currently trying to use the static analysis tool Infer to find uncatched API-misuse bugs in OpenWrt packages, and I find a potential Integer Overflow in your project, version 1.2.9.
The bug located in aplay/aplay.c. Firstly, the program tries to write the remains bytes in audiobuf with the length of loaded in line 2865, and loaded is later used as the parameter for safe_read in the loop, then loaded is used as the 2nd argument of pct_write() and finally after a multiply operation, it is used as the size of Malloc in remap_data(), as shown in the following code:
static void playback_go(int fd, size_t loaded, off_t count, int rtype, char *name)
{
int l, r;
off_t written = 0;
off_t c;
header(rtype, name);
set_params();
while (loaded > chunk_bytes && written < count && !in_aborting) {
if (pcm_write(audiobuf + written, chunk_size) <= 0)
return;
written += chunk_bytes;
loaded -= chunk_bytes;
}
if (written > 0 && loaded > 0)
memmove(audiobuf, audiobuf + written, loaded);
l = loaded;
while (written < count && !in_aborting) {
do {
c = count - written;
if (c > chunk_bytes)
c = chunk_bytes;
/* c < l, there is more data loaded
* then we actually need to write
*/
if (c < l)
l = c;
c -= l;
if (c == 0)
break;
r = safe_read(fd, audiobuf + l, c);
if (r < 0) {
perror(name);
prg_exit(EXIT_FAILURE);
}
fdcount += r;
if (r == 0)
break;
l += r;
} while ((size_t)l < chunk_bytes);
l = l * 8 / bits_per_frame;
r = pcm_write(audiobuf, l);
if (r != l)
break;
r = r * bits_per_frame / 8;
written += r;
l = 0;
}
if (!in_aborting) {
snd_pcm_nonblock(handle, 0);
snd_pcm_drain(handle);
snd_pcm_nonblock(handle, nonblock);
}
}
# in remap_data()
chunk_bytes = count * bits_per_frame / 8;
if (tmp_size < chunk_bytes) {
free(tmp);
tmp = malloc(chunk_bytes);
if (!tmp) {
error(_("not enough memory"));
exit(1);
}
tmp_size = count;
}
The parameter passed to Malloc may be overflowed so that the actual allocated memory is small.
I also attached the analysis trace given by Infer FYI:
"trace": [
{
"file": "aplay/aplay.c",
"line": 940,
"col": 14,
"feature": [ "Input", "read" ]
},
{
"file": "aplay/aplay.c",
"line": 940,
"col": 14,
"feature": [ "Input", "read" ]
},
{
"file": "aplay/aplay.c",
"line": 2865,
"col": 21,
"feature": [
"Prune",
[
"UnOp",
"!",
[
"BinOp",
">",
[ "Var" ],
[ "Cast", [ "Unsupported" ], [ "Const", [ "Cint", 0 ] ] ]
]
]
]
},
{
"file": "aplay/aplay.c",
"line": 2868,
"col": 2,
"feature": [ "Store", [ "Var" ], [ "Var" ] ]
},
{
"file": "aplay/aplay.c",
"line": 2878,
"col": 8,
"feature": [
"Prune",
[ "UnOp", "!", [ "BinOp", "<", [ "Var" ], [ "Var" ] ] ]
]
},
{
"file": "aplay/aplay.c",
"line": 2871,
"col": 4,
"feature": [
"Store",
[ "Var" ],
[ "BinOp", "-", [ "Var" ], [ "Var" ] ]
]
},
{
"file": "aplay/aplay.c",
"line": 2872,
"col": 8,
"feature": [
"Prune",
[
"UnOp",
"!",
[
"BinOp",
">",
[ "Cast", [ "Unsupported" ], [ "Var" ] ],
[ "Var" ]
]
]
]
},
{
"file": "aplay/aplay.c",
"line": 2878,
"col": 8,
"feature": [ "Prune", [ "BinOp", "<", [ "Var" ], [ "Var" ] ] ]
},
{
"file": "aplay/aplay.c",
"line": 2879,
"col": 5,
"feature": [ "Store", [ "Var" ], [ "Var" ] ]
},
{
"file": "aplay/aplay.c",
"line": 2899,
"col": 3,
"feature": [
"Store",
[ "Var" ],
[
"BinOp",
"/",
[
"BinOp",
"*",
[ "Cast", [ "Unsupported" ], [ "Var" ] ],
[ "Var" ]
],
[ "Cast", [ "Unsupported" ], [ "Const", [ "Cint", 8 ] ] ]
]
]
},
{
"file": "aplay/aplay.c",
"line": 2900,
"col": 3,
"feature": [
"Store",
[ "Var" ],
[ "BinOp", "+", [ "Var" ], [ "Var" ] ]
]
},
{
"file": "aplay/aplay.c",
"line": 2871,
"col": 4,
"feature": [
"Store",
[ "Var" ],
[ "BinOp", "-", [ "Var" ], [ "Var" ] ]
]
},
{
"file": "aplay/aplay.c",
"line": 2872,
"col": 8,
"feature": [
"Prune",
[
"UnOp",
"!",
[
"BinOp",
">",
[ "Cast", [ "Unsupported" ], [ "Var" ] ],
[ "Var" ]
]
]
]
},
{
"file": "aplay/aplay.c",
"line": 2878,
"col": 8,
"feature": [ "Prune", [ "BinOp", "<", [ "Var" ], [ "Var" ] ] ]
},
{
"file": "aplay/aplay.c",
"line": 2879,
"col": 5,
"feature": [ "Store", [ "Var" ], [ "Var" ] ]
},
{
"file": "aplay/aplay.c",
"line": 2895,
"col": 3,
"feature": [
"Store",
[ "Var" ],
[
"BinOp",
"/",
[
"Cast",
[ "Unsupported" ],
[ "BinOp", "*", [ "Var" ], [ "Const", [ "Cint", 8 ] ] ]
],
[ "Var" ]
]
]
},
{
"file": "aplay/aplay.c",
"line": 2896,
"col": 7,
"feature": [ "Call", "pcm_write" ]
},
{
"file": "aplay/aplay.c",
"line": 2126,
"col": 6,
"feature": [
"Prune",
[ "UnOp", "!", [ "BinOp", "<", [ "Var" ], [ "Var" ] ] ]
]
},
{
"file": "aplay/aplay.c",
"line": 2130,
"col": 9,
"feature": [ "Call", "remap_data" ]
},
{
"file": "aplay/aplay.c",
"line": 2069,
"col": 2,
"feature": [
"Store",
[ "Var" ],
[
"BinOp",
"/",
[ "BinOp", "*", [ "Var" ], [ "Var" ] ],
[ "Cast", [ "Unsupported" ], [ "Const", [ "Cint", 8 ] ] ]
]
]
},
{
"file": "aplay/aplay.c",
"line": 2070,
"col": 6,
"feature": [ "Prune", [ "BinOp", "<", [ "Var" ], [ "Var" ] ] ]
},
{
"file": "aplay/aplay.c",
"line": 2072,
"col": 9,
"feature": [ "IntOverflow", "malloc", [ "Var" ] ]
}
],