netdev
[Top] [All Lists]

[PATCH][ATM] atm_getaddr() isn't safe

To: davem@xxxxxxxxxx
Subject: [PATCH][ATM] atm_getaddr() isn't safe
From: chas williams <chas@xxxxxxxxxxxxxxxx>
Date: Wed, 03 Sep 2003 12:25:16 -0400
Cc: netdev@xxxxxxxxxxx
Reply-to: chas3@xxxxxxxxxxxxxxxxxxxxx
Sender: netdev-bounce@xxxxxxxxxxx
this patch also preserves the old behavior of atm_getaddr() in
that it does partially fill in the passed buffer.  please apply
to 2.6 and 2.4.

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#                  ChangeSet    1.1414  -> 1.1415 
#             net/atm/addr.c    1.3     -> 1.4    
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 03/09/03      chas@xxxxxxxxxxxxxxxxxxxxxx     1.1415
# addr.c:
#   copy_to_user() shouldn't be called while blocking interrupts
# --------------------------------------------
#
diff -Nru a/net/atm/addr.c b/net/atm/addr.c
--- a/net/atm/addr.c    Wed Sep  3 05:33:30 2003
+++ b/net/atm/addr.c    Wed Sep  3 05:33:30 2003
@@ -118,23 +118,24 @@
 {
        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;
 }

<Prev in Thread] Current Thread [Next in Thread>