diff options
| author | Chas Williams <chas@nrl.navy.mil> | 2003-09-03 10:34:02 -0700 |
|---|---|---|
| committer | Stephen Hemminger <shemminger@osdl.org> | 2003-09-03 10:34:02 -0700 |
| commit | 076a2e8fc200963e5ce13881895bbb6da2ae0b0c (patch) | |
| tree | 069c43f25ad057244ddc3d94ee694405cc9190a8 /net | |
| parent | 70150e541ffe53806bbe30954a6d1d14716243da (diff) | |
[ATM]: In atm_getaddr() do not copy_to_user() with locks held.
Diffstat (limited to 'net')
| -rw-r--r-- | net/atm/addr.c | 29 |
1 files changed, 15 insertions, 14 deletions
diff --git a/net/atm/addr.c b/net/atm/addr.c index 5974a1876116..459bdeed05f9 100644 --- a/net/atm/addr.c +++ b/net/atm/addr.c @@ -118,23 +118,24 @@ int atm_get_addr(struct atm_dev *dev,struct sockaddr_atmsvc *u_buf,int size) { unsigned long flags; struct atm_dev_addr *walk; - int total; + int total = 0, error; + struct sockaddr_atmsvc *tmp_buf, *tmp_bufp; + spin_lock_irqsave(&dev->lock, flags); - total = 0; - for (walk = dev->local; walk; walk = walk->next) { + for (walk = dev->local; walk; walk = walk->next) total += sizeof(struct sockaddr_atmsvc); - if (total > size) { - spin_unlock_irqrestore(&dev->lock, flags); - return -E2BIG; - } - if (copy_to_user(u_buf,&walk->addr, - sizeof(struct sockaddr_atmsvc))) { - spin_unlock_irqrestore(&dev->lock, flags); - return -EFAULT; - } - u_buf++; + tmp_buf = tmp_bufp = kmalloc(total, GFP_ATOMIC); + if (!tmp_buf) { + spin_unlock_irqrestore(&dev->lock, flags); + return -ENOMEM; } + for (walk = dev->local; walk; walk = walk->next) + memcpy(tmp_bufp++, &walk->addr, sizeof(struct sockaddr_atmsvc)); spin_unlock_irqrestore(&dev->lock, flags); - return total; + error = total > size ? -E2BIG : total; + if (copy_to_user(u_buf, tmp_buf, total < size ? total : size)) + error = -EFAULT; + kfree(tmp_buf); + return error; } |
