diff options
author | Wei Yongjun <yjwei@cn.fujitsu.com> | 2007-12-20 17:36:44 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2007-12-20 17:36:44 -0500 |
commit | 1ac70e7ad24a88710cf9b6d7ababaefa2b575df0 (patch) | |
tree | 175202f238aca605bf916f4871bc7ce04eebddc7 /net | |
parent | c5c0f33d8e5b1219c86757e6afffd6f96823e521 (diff) |
[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 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 <yjwei@cn.fujitsu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/compat.c | 2 | ||||
-rw-r--r-- | net/core/scm.c | 2 |
2 files changed, 4 insertions, 0 deletions
diff --git a/net/compat.c b/net/compat.c index d74d82155d78..377e560ab5c9 100644 --- a/net/compat.c +++ b/net/compat.c | |||
@@ -254,6 +254,8 @@ int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *dat | |||
254 | if (copy_to_user(CMSG_COMPAT_DATA(cm), data, cmlen - sizeof(struct compat_cmsghdr))) | 254 | if (copy_to_user(CMSG_COMPAT_DATA(cm), data, cmlen - sizeof(struct compat_cmsghdr))) |
255 | return -EFAULT; | 255 | return -EFAULT; |
256 | cmlen = CMSG_COMPAT_SPACE(len); | 256 | cmlen = CMSG_COMPAT_SPACE(len); |
257 | if (kmsg->msg_controllen < cmlen) | ||
258 | cmlen = kmsg->msg_controllen; | ||
257 | kmsg->msg_control += cmlen; | 259 | kmsg->msg_control += cmlen; |
258 | kmsg->msg_controllen -= cmlen; | 260 | kmsg->msg_controllen -= cmlen; |
259 | return 0; | 261 | return 0; |
diff --git a/net/core/scm.c b/net/core/scm.c index 100ba6d9d478..10f5c65f6a47 100644 --- a/net/core/scm.c +++ b/net/core/scm.c | |||
@@ -196,6 +196,8 @@ int put_cmsg(struct msghdr * msg, int level, int type, int len, void *data) | |||
196 | if (copy_to_user(CMSG_DATA(cm), data, cmlen - sizeof(struct cmsghdr))) | 196 | if (copy_to_user(CMSG_DATA(cm), data, cmlen - sizeof(struct cmsghdr))) |
197 | goto out; | 197 | goto out; |
198 | cmlen = CMSG_SPACE(len); | 198 | cmlen = CMSG_SPACE(len); |
199 | if (msg->msg_controllen < cmlen) | ||
200 | cmlen = msg->msg_controllen; | ||
199 | msg->msg_control += cmlen; | 201 | msg->msg_control += cmlen; |
200 | msg->msg_controllen -= cmlen; | 202 | msg->msg_controllen -= cmlen; |
201 | err = 0; | 203 | err = 0; |