Commit ac1aff99 authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] sparse: sound sb fix

	In some cases snd_sb_csp_load() did kmalloc() and copy_from_user()
under a spinlock.  Split into snd_sb_csp_load() and snd_sb_csp_load_user() -
ther former always from kernel pointer, the latter - from userland.
	snd_sb_csp_load_user() doesn't take any locks itself, it just
does kmalloc, copy_from_user and calls snd_sb_csp_load() to do the rest.
parent a6b0d9d2
......@@ -91,7 +91,7 @@ static int get_version(sb_t *chip);
static int snd_sb_csp_riff_load(snd_sb_csp_t * p, snd_sb_csp_microcode_t * code);
static int snd_sb_csp_unload(snd_sb_csp_t * p);
static int snd_sb_csp_load(snd_sb_csp_t * p, const unsigned char *buf, int size, int load_flags);
static int snd_sb_csp_load_user(snd_sb_csp_t * p, const unsigned char *buf, int size, int load_flags);
static int snd_sb_csp_autoload(snd_sb_csp_t * p, int pcm_sfmt, int play_rec_mode);
static int snd_sb_csp_check_version(snd_sb_csp_t * p);
......@@ -372,8 +372,8 @@ static int snd_sb_csp_riff_load(snd_sb_csp_t * p, snd_sb_csp_microcode_t * mcode
if (code_h.name != INIT_HEADER)
break;
data_ptr += sizeof(code_h);
err = snd_sb_csp_load(p, data_ptr, LE_INT(code_h.len),
SNDRV_SB_CSP_LOAD_INITBLOCK | SNDRV_SB_CSP_LOAD_FROMUSER);
err = snd_sb_csp_load_user(p, data_ptr, LE_INT(code_h.len),
SNDRV_SB_CSP_LOAD_INITBLOCK);
if (err)
return err;
data_ptr += LE_INT(code_h.len);
......@@ -387,8 +387,8 @@ static int snd_sb_csp_riff_load(snd_sb_csp_t * p, snd_sb_csp_microcode_t * mcode
return -EINVAL;
}
data_ptr += sizeof(code_h);
err = snd_sb_csp_load(p, data_ptr, LE_INT(code_h.len),
SNDRV_SB_CSP_LOAD_FROMUSER);
err = snd_sb_csp_load_user(p, data_ptr,
LE_INT(code_h.len), 0);
if (err)
return err;
......@@ -627,29 +627,12 @@ static int snd_sb_csp_load(snd_sb_csp_t * p, const unsigned char *buf, int size,
/* Send high byte */
snd_sbdsp_command(p->chip, (unsigned char)((size - 1) >> 8));
/* send microcode sequence */
if (load_flags & SNDRV_SB_CSP_LOAD_FROMUSER) {
/* copy microcode from user space */
unsigned char *kbuf, *_kbuf;
_kbuf = kbuf = kmalloc (size, GFP_KERNEL);
if (copy_from_user(kbuf, buf, size)) {
result = -EFAULT;
kfree (_kbuf);
goto __fail;
}
while (size--) {
if (!snd_sbdsp_command(p->chip, *kbuf++)) {
kfree (_kbuf);
goto __fail;
}
}
kfree (_kbuf);
} else {
if (load_flags & SNDRV_SB_CSP_LOAD_FROMUSER)
/* load from kernel space */
while (size--) {
if (!snd_sbdsp_command(p->chip, *buf++))
goto __fail;
}
}
if (snd_sbdsp_get_byte(p->chip))
goto __fail;
......@@ -693,6 +676,20 @@ static int snd_sb_csp_load(snd_sb_csp_t * p, const unsigned char *buf, int size,
return result;
}
static int snd_sb_csp_load_user(snd_sb_csp_t * p, const unsigned char *buf, int size, int load_flags)
{
int err = -ENOMEM;
unsigned char *kbuf = kmalloc(size, GFP_KERNEL);
if (kbuf) {
if (copy_from_user(kbuf, buf, size))
err = -EFAULT;
else
err = snd_sb_csp_load(p, kbuf, size, load_flags);
kfree(kbuf);
}
return err;
}
#include "sb16_csp_codecs.h"
/*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment