summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorChas Williams <chas@nrl.navy.mil>2003-09-03 10:34:02 -0700
committerStephen Hemminger <shemminger@osdl.org>2003-09-03 10:34:02 -0700
commit076a2e8fc200963e5ce13881895bbb6da2ae0b0c (patch)
tree069c43f25ad057244ddc3d94ee694405cc9190a8 /net
parent70150e541ffe53806bbe30954a6d1d14716243da (diff)
[ATM]: In atm_getaddr() do not copy_to_user() with locks held.
Diffstat (limited to 'net')
-rw-r--r--net/atm/addr.c29
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;
}