From ac1aff9920bd6f8b12972fc376bc41b64fa2cf4e Mon Sep 17 00:00:00 2001 From: Alexander Viro Date: Thu, 3 Jun 2004 02:47:17 -0700 Subject: [PATCH] [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. --- sound/isa/sb/sb16_csp.c | 49 +++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c index 80d576a68c0c1..27bf5109f020f 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" /* -- 2.53.0