diff options
author | Alexander Viro <viro@parcelfarce.linux.theplanet.co.uk> | 2004-06-03 02:47:17 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-06-03 02:47:17 -0700 |
commit | ac1aff9920bd6f8b12972fc376bc41b64fa2cf4e (patch) | |
tree | 230cfe0b88ff39669c6e51311d99512d0bdeef1e /sound | |
parent | a6b0d9d233286121de038470f91034679a73123f (diff) | |
download | history-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.c | 49 |
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" /* |