NET: Fix function put_cmsg() which may cause usr application memory overflow
Subsystems (3)
PATCH 1/1 NET: Fix function put_cmsg() which may cause usr application memory overflow
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 thanCMSG_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.
net/core/scm.c +0 -0
@@ -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;
net/compat.c +0 -0
@@ -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;
David Miller
maintainerFrom: Wei Yongjun <[email protected]>
Date: Tue, 18 Dec 2007 15:19:09 +0900
Quoted 7 lines
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 as0xFFFFFFF0, so the followingput_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.
...
Quoted 4 lines
The same promble exists in
put_cmsg_compat(). This patch can fix this problem.Signed-off-by Wei Yongjun <[email protected]>
Thank you for fixing this bug, patch applied.
put_cmsg() is a confusing function, it takes a while to understand what it is trying to accomplish. And this explains why this bug lived for so long.
Each CMSG entry has to be aligned, but put_cmsg() will allow to put the full final message into the CMSG area if there is enough room to fit the message without the added alignment.
So, with Wei's fix, we now have:
int cmlen = CMSG_LEN(len);
...
if (msg->msg_controllen < cmlen) {
msg->msg_flags |= MSG_CTRUNC;
cmlen = msg->msg_controllen;
}
...
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->msg_controllen < cmlen)
cmlen = msg->msg_controllen;
msg->msg_control += cmlen;
msg->msg_controllen -= cmlen;...
which I think finally implements the intended behavior accurately.