When used function put_cmsg() to copy kernel information to user application memory, if the memory length given by user application is not enough, by the bad length calculate of msg.msg_controllen, put_cmsg() function may cause the msg.msg_controllen to be a large value, such as 0xFFFFFFF0, so the following put_cmsg() can also write data to usr application memory even usr has no valid memory to store this. This may cause usr application memory overflow.

int put_cmsg(struct msghdr * msg, int level, int type, int len, void *data)
{
   struct cmsghdr __user *cm
       = (__force struct cmsghdr __user *)msg->msg_control;
   struct cmsghdr cmhdr;
   int cmlen = CMSG_LEN(len);
   ~~~~~~~~~~~~~~~~~~~~~
   int err;

   if (MSG_CMSG_COMPAT & msg->msg_flags)
       return put_cmsg_compat(msg, level, type, len, data);

   if (cm==NULL || msg->msg_controllen < sizeof(*cm)) {
       msg->msg_flags |= MSG_CTRUNC;
       return 0; /* XXX: return error? check spec. */
   }
   if (msg->msg_controllen < cmlen) {
   ~~~~~~~~~~~~~~~~~~~~~~~~
       msg->msg_flags |= MSG_CTRUNC;
       cmlen = msg->msg_controllen;
   }
   cmhdr.cmsg_level = level;
   cmhdr.cmsg_type = type;
   cmhdr.cmsg_len = cmlen;

   err = -EFAULT;
   if (copy_to_user(cm, &cmhdr, sizeof cmhdr))
       goto out;
   if (copy_to_user(CMSG_DATA(cm), data, cmlen - sizeof(struct cmsghdr)))
       goto out;
   cmlen = CMSG_SPACE(len);
~~~~~~~~~~~~~~~~~~~~~~~~~~~
If MSG_CTRUNC flags is set, msg->msg_controllen is less than CMSG_SPACE(len), "msg->msg_controllen -= cmlen" will cause unsinged int type msg->msg_controllen to be a large value.
~~~~~~~~~~~~~~~~~~~~~~~~~~~
   msg->msg_control += cmlen;
   msg->msg_controllen -= cmlen;
   ~~~~~~~~~~~~~~~~~~~~~
   err = 0;
out:
   return err;
}

The same promble exists in put_cmsg_compat(). This patch can fix this problem.

Signed-off-by: Wei Yongjun <[EMAIL PROTECTED]>

--- a/net/core/scm.c    2007-12-11 08:41:57.000000000 -0500
+++ b/net/core/scm.c    2007-12-11 12:10:25.000000000 -0500
@@ -196,6 +196,8 @@ int put_cmsg(struct msghdr * msg, int le
        if (copy_to_user(CMSG_DATA(cm), data, cmlen - sizeof(struct cmsghdr)))
                goto out;
        cmlen = CMSG_SPACE(len);
+       if (msg->msg_controllen < cmlen)
+               cmlen = msg->msg_controllen;
        msg->msg_control += cmlen;
        msg->msg_controllen -= cmlen;
        err = 0;
--- a/net/compat.c      2007-12-11 12:10:32.000000000 -0500
+++ b/net/compat.c      2007-12-11 12:11:08.000000000 -0500
@@ -254,6 +254,8 @@ int put_cmsg_compat(struct msghdr *kmsg,
        if (copy_to_user(CMSG_COMPAT_DATA(cm), data, cmlen - sizeof(struct 
compat_cmsghdr)))
                return -EFAULT;
        cmlen = CMSG_COMPAT_SPACE(len);
+       if (kmsg->msg_controllen < cmlen)
+               cmlen = kmsg->msg_controllen;
        kmsg->msg_control += cmlen;
        kmsg->msg_controllen -= cmlen;
        return 0;





--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to