/* There is a lot of hair here because the alignment rules (and * thus placement) of cmsg headers and length are different for * 32-bit apps. -DaveM
*/ int cmsghdr_from_user_compat_to_kern(struct msghdr *kmsg, struct sock *sk, unsignedchar *stackbuf, int stackbuf_size)
{ struct compat_cmsghdr __user *ucmsg; struct cmsghdr *kcmsg, *kcmsg_base;
compat_size_t ucmlen;
__kernel_size_t kcmlen, tmp; int err = -EFAULT;
/* The kcmlen holds the 64-bit version of the control length. * It may not be modified as we do not stick it into the kmsg * until we have successfully copied over all of the data * from the user.
*/ if (kcmlen > stackbuf_size)
kcmsg_base = kcmsg = sock_kmalloc(sk, kcmlen, GFP_KERNEL); if (kcmsg == NULL) return -ENOMEM;
/* Now copy them over neatly. */
memset(kcmsg, 0, kcmlen);
ucmsg = CMSG_COMPAT_FIRSTHDR(kmsg); while (ucmsg != NULL) { struct compat_cmsghdr cmsg; if (copy_from_user(&cmsg, ucmsg, sizeof(cmsg))) goto Efault; if (!CMSG_COMPAT_OK(cmsg.cmsg_len, ucmsg, kmsg)) goto Einval;
tmp = ((cmsg.cmsg_len - sizeof(*ucmsg)) + sizeof(struct cmsghdr)); if ((char *)kcmsg_base + kcmlen - (char *)kcmsg < CMSG_ALIGN(tmp)) goto Einval;
kcmsg->cmsg_len = tmp;
kcmsg->cmsg_level = cmsg.cmsg_level;
kcmsg->cmsg_type = cmsg.cmsg_type;
tmp = CMSG_ALIGN(tmp); if (copy_from_user(CMSG_DATA(kcmsg),
CMSG_COMPAT_DATA(ucmsg),
(cmsg.cmsg_len - sizeof(*ucmsg)))) goto Efault;
/* * check the length of messages copied in is the same as the * what we get from the first loop
*/ if ((char *)kcmsg - (char *)kcmsg_base != kcmlen) goto Einval;
/* Ok, looks like we made it. Hook it up and return success. */
kmsg->msg_control_is_user = false;
kmsg->msg_control = kcmsg_base;
kmsg->msg_controllen = kcmlen; return 0;
if (call < SYS_SOCKET || call > SYS_SENDMMSG) return -EINVAL;
len = nas[call]; if (len > sizeof(a)) return -EINVAL;
if (copy_from_user(a, args, len)) return -EFAULT;
ret = audit_socketcall_compat(len / sizeof(a[0]), a); if (ret) return ret;
a0 = a[0];
a1 = a[1];
switch (call) { case SYS_SOCKET:
ret = __sys_socket(a0, a1, a[2]); break; case SYS_BIND:
ret = __sys_bind(a0, compat_ptr(a1), a[2]); break; case SYS_CONNECT:
ret = __sys_connect(a0, compat_ptr(a1), a[2]); break; case SYS_LISTEN:
ret = __sys_listen(a0, a1); break; case SYS_ACCEPT:
ret = __sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), 0); break; case SYS_GETSOCKNAME:
ret = __sys_getsockname(a0, compat_ptr(a1), compat_ptr(a[2])); break; case SYS_GETPEERNAME:
ret = __sys_getpeername(a0, compat_ptr(a1), compat_ptr(a[2])); break; case SYS_SOCKETPAIR:
ret = __sys_socketpair(a0, a1, a[2], compat_ptr(a[3])); break; case SYS_SEND:
ret = __sys_sendto(a0, compat_ptr(a1), a[2], a[3], NULL, 0); break; case SYS_SENDTO:
ret = __sys_sendto(a0, compat_ptr(a1), a[2], a[3],
compat_ptr(a[4]), a[5]); break; case SYS_RECV:
ret = __compat_sys_recvfrom(a0, compat_ptr(a1), a[2], a[3],
NULL, NULL); break; case SYS_RECVFROM:
ret = __compat_sys_recvfrom(a0, compat_ptr(a1), a[2], a[3],
compat_ptr(a[4]),
compat_ptr(a[5])); break; case SYS_SHUTDOWN:
ret = __sys_shutdown(a0, a1); break; case SYS_SETSOCKOPT:
ret = __sys_setsockopt(a0, a1, a[2], compat_ptr(a[3]), a[4]); break; case SYS_GETSOCKOPT:
ret = __sys_getsockopt(a0, a1, a[2], compat_ptr(a[3]),
compat_ptr(a[4])); break; case SYS_SENDMSG:
ret = __compat_sys_sendmsg(a0, compat_ptr(a1), a[2]); break; case SYS_SENDMMSG:
ret = __compat_sys_sendmmsg(a0, compat_ptr(a1), a[2], a[3]); break; case SYS_RECVMSG:
ret = __compat_sys_recvmsg(a0, compat_ptr(a1), a[2]); break; case SYS_RECVMMSG:
ret = __sys_recvmmsg(a0, compat_ptr(a1), a[2],
a[3] | MSG_CMSG_COMPAT, NULL,
compat_ptr(a[4])); break; case SYS_ACCEPT4:
ret = __sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), a[3]); break; default:
ret = -EINVAL; break;
} return ret;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.