From: yuan linyu <linyu.y...@alcatel-sbell.com.cn> 1. put_cmsg{_compat}() may copy data to user when buffer free space less than control message header alignment size. 2. scm_detach_fds{_compat}() may calc wrong fdmax if control message header have greater alignment size.
Signed-off-by: yuan linyu <linyu.y...@alcatel-sbell.com.cn> --- net/compat.c | 10 ++++++++-- net/core/scm.c | 8 +++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/net/compat.c b/net/compat.c index 96c544b..fe1f41c 100644 --- a/net/compat.c +++ b/net/compat.c @@ -245,7 +245,9 @@ int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *dat if (copy_to_user(cm, &cmhdr, sizeof cmhdr)) return -EFAULT; - if (copy_to_user(CMSG_COMPAT_DATA(cm), data, cmlen - sizeof(struct compat_cmsghdr))) + if (cmlen > CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr)) && + copy_to_user(CMSG_COMPAT_DATA(cm), data, + cmlen - CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr)))) return -EFAULT; cmlen = CMSG_COMPAT_SPACE(len); if (kmsg->msg_controllen < cmlen) @@ -258,12 +260,16 @@ int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *dat void scm_detach_fds_compat(struct msghdr *kmsg, struct scm_cookie *scm) { struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control; - int fdmax = (kmsg->msg_controllen - sizeof(struct compat_cmsghdr)) / sizeof(int); + int fdmax = 0; int fdnum = scm->fp->count; struct file **fp = scm->fp->fp; int __user *cmfptr; int err = 0, i; + if (kmsg->msg_controllen > CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr))) + fdmax = (kmsg->msg_controllen - + CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr))) / sizeof(int); + if (fdnum < fdmax) fdmax = fdnum; diff --git a/net/core/scm.c b/net/core/scm.c index d882043..5d8ef4f 100644 --- a/net/core/scm.c +++ b/net/core/scm.c @@ -238,7 +238,9 @@ int put_cmsg(struct msghdr * msg, int level, int type, int len, void *data) err = -EFAULT; if (copy_to_user(cm, &cmhdr, sizeof cmhdr)) goto out; - if (copy_to_user(CMSG_DATA(cm), data, cmlen - sizeof(struct cmsghdr))) + if (cmlen > CMSG_ALIGN(sizeof(struct cmsghdr)) && + copy_to_user(CMSG_DATA(cm), data, + cmlen - CMSG_ALIGN(sizeof(struct cmsghdr)))) goto out; cmlen = CMSG_SPACE(len); if (msg->msg_controllen < cmlen) @@ -267,8 +269,8 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm) return; } - if (msg->msg_controllen > sizeof(struct cmsghdr)) - fdmax = ((msg->msg_controllen - sizeof(struct cmsghdr)) + if (msg->msg_controllen > CMSG_ALIGN(sizeof(struct cmsghdr))) + fdmax = ((msg->msg_controllen - CMSG_ALIGN(sizeof(struct cmsghdr))) / sizeof(int)); if (fdnum < fdmax) -- 2.7.4