aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorAlexander Viro <viro@parcelfarce.linux.theplanet.co.uk>2004-06-03 02:47:17 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-06-03 02:47:17 -0700
commitac1aff9920bd6f8b12972fc376bc41b64fa2cf4e (patch)
tree230cfe0b88ff39669c6e51311d99512d0bdeef1e /sound
parenta6b0d9d233286121de038470f91034679a73123f (diff)
downloadhistory-ac1aff9920bd6f8b12972fc376bc41b64fa2cf4e.tar.gz
[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.
Diffstat (limited to 'sound')
-rw-r--r--sound/isa/sb/sb16_csp.c49
1 files changed, 23 insertions, 26 deletions
diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c
index 80d576a68c0c16..27bf5109f020fc 100644
--- a/sound/isa/sb/sb16_csp.c
+++ b/sound/isa/sb/sb16_csp.c
@@ -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,28 +627,11 @@ 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);
+ if (load_flags & SNDRV_SB_CSP_LOAD_FROMUSER)
+ /* load from kernel space */
+ while (size--) {
+ if (!snd_sbdsp_command(p->chip, *buf++))
goto __fail;
- }
- while (size--) {
- if (!snd_sbdsp_command(p->chip, *kbuf++)) {
- kfree (_kbuf);
- goto __fail;
- }
- }
- kfree (_kbuf);
- } else {
- /* 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"
/*