⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 socket32.c

📁 这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自测试~但就算用来做参考资料也是非常好的
💻 C
📖 第 1 页 / 共 2 页
字号:
/*  * 32bit Socket syscall emulation. Based on arch/sparc64/kernel/sys_sparc32.c. * * Copyright (C) 2000		VA Linux Co * Copyright (C) 2000		Don Dugger <n0ano@valinux.com> * Copyright (C) 1999 		Arun Sharma <arun.sharma@intel.com> * Copyright (C) 1997,1998 	Jakub Jelinek (jj@sunsite.mff.cuni.cz) * Copyright (C) 1997 		David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 2000		Hewlett-Packard Co. * Copyright (C) 2000		David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 2000,2001	Andi Kleen, SuSE Labs  */#include <linux/kernel.h>#include <linux/fs.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/file.h>#include <linux/icmpv6.h>#include <linux/socket.h>#include <linux/filter.h>#include <net/scm.h>#include <net/sock.h>#include <asm/ia32.h>#include <asm/uaccess.h>#include <asm/socket32.h>#define A(__x)		((unsigned long)(__x))#define AA(__x)		((unsigned long)(__x))static inline int iov_from_user32_to_kern(struct iovec *kiov,					  struct iovec32 *uiov32,					  int niov){	int tot_len = 0;	while(niov > 0) {		u32 len, buf;		if(get_user(len, &uiov32->iov_len) ||		   get_user(buf, &uiov32->iov_base)) {			tot_len = -EFAULT;			break;		}		tot_len += len;		kiov->iov_base = (void *)A(buf);		kiov->iov_len = (__kernel_size_t) len;		uiov32++;		kiov++;		niov--;	}	return tot_len;}static inline int msghdr_from_user32_to_kern(struct msghdr *kmsg,					     struct msghdr32 *umsg){	u32 tmp1, tmp2, tmp3;	int err;	err = get_user(tmp1, &umsg->msg_name);	err |= __get_user(tmp2, &umsg->msg_iov);	err |= __get_user(tmp3, &umsg->msg_control);	if (err)		return -EFAULT;	kmsg->msg_name = (void *)A(tmp1);	kmsg->msg_iov = (struct iovec *)A(tmp2);	kmsg->msg_control = (void *)A(tmp3);	err = get_user(kmsg->msg_namelen, &umsg->msg_namelen);	err |= get_user(kmsg->msg_iovlen, &umsg->msg_iovlen);	err |= get_user(kmsg->msg_controllen, &umsg->msg_controllen);	err |= get_user(kmsg->msg_flags, &umsg->msg_flags);		return err;}/* I've named the args so it is easy to tell whose space the pointers are in. */static int verify_iovec32(struct msghdr *kern_msg, struct iovec *kern_iov,			  char *kern_address, int mode){	int tot_len;	if(kern_msg->msg_namelen) {		if(mode==VERIFY_READ) {			int err = move_addr_to_kernel(kern_msg->msg_name,						      kern_msg->msg_namelen,						      kern_address);			if(err < 0)				return err;		}		kern_msg->msg_name = kern_address;	} else		kern_msg->msg_name = NULL;	if(kern_msg->msg_iovlen > UIO_FASTIOV) {		kern_iov = kmalloc(kern_msg->msg_iovlen * sizeof(struct iovec),				   GFP_KERNEL);		if(!kern_iov)			return -ENOMEM;	}	tot_len = iov_from_user32_to_kern(kern_iov,					  (struct iovec32 *)kern_msg->msg_iov,					  kern_msg->msg_iovlen);	if(tot_len >= 0)		kern_msg->msg_iov = kern_iov;	else if(kern_msg->msg_iovlen > UIO_FASTIOV)		kfree(kern_iov);	return tot_len;}/* 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 */static int cmsghdr_from_user32_to_kern(struct msghdr *kmsg,				       unsigned char *stackbuf, int stackbuf_size){	struct cmsghdr32 *ucmsg;	struct cmsghdr *kcmsg, *kcmsg_base;	__kernel_size_t32 ucmlen;	__kernel_size_t kcmlen, tmp;	kcmlen = 0;	kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf;	ucmsg = CMSG32_FIRSTHDR(kmsg);	while(ucmsg != NULL) {		if(get_user(ucmlen, &ucmsg->cmsg_len))			return -EFAULT;		/* Catch bogons. */		if(CMSG32_ALIGN(ucmlen) <		   CMSG32_ALIGN(sizeof(struct cmsghdr32)))			return -EINVAL;		if((unsigned long)(((char *)ucmsg - (char *)kmsg->msg_control)				   + ucmlen) > kmsg->msg_controllen)			return -EINVAL;		tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +		       CMSG_ALIGN(sizeof(struct cmsghdr)));		kcmlen += tmp;		ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen);	}	if(kcmlen == 0)		return -EINVAL;	/* 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 = kmalloc(kcmlen, GFP_KERNEL);	if(kcmsg == NULL)		return -ENOBUFS;	/* Now copy them over neatly. */	memset(kcmsg, 0, kcmlen);	ucmsg = CMSG32_FIRSTHDR(kmsg);	while(ucmsg != NULL) {		__get_user(ucmlen, &ucmsg->cmsg_len);		tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +		       CMSG_ALIGN(sizeof(struct cmsghdr)));		kcmsg->cmsg_len = tmp;		__get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level);		__get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type);		/* Copy over the data. */		if(copy_from_user(CMSG_DATA(kcmsg),				  CMSG32_DATA(ucmsg),				  (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg)))))			goto out_free_efault;		/* Advance. */		kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp));		ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen);	}	/* Ok, looks like we made it.  Hook it up and return success. */	kmsg->msg_control = kcmsg_base;	kmsg->msg_controllen = kcmlen;	return 0;out_free_efault:	if(kcmsg_base != (struct cmsghdr *)stackbuf)		kfree(kcmsg_base);	return -EFAULT;}static void put_cmsg32(struct msghdr *kmsg, int level, int type,		       int len, void *data){	struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control;	struct cmsghdr32 cmhdr;	int cmlen = CMSG32_LEN(len);	if(cm == NULL || kmsg->msg_controllen < sizeof(*cm)) {		kmsg->msg_flags |= MSG_CTRUNC;		return;	}	if(kmsg->msg_controllen < cmlen) {		kmsg->msg_flags |= MSG_CTRUNC;		cmlen = kmsg->msg_controllen;	}	cmhdr.cmsg_level = level;	cmhdr.cmsg_type = type;	cmhdr.cmsg_len = cmlen;	if(copy_to_user(cm, &cmhdr, sizeof cmhdr))		return;	if(copy_to_user(CMSG32_DATA(cm), data, cmlen - sizeof(struct cmsghdr32)))		return;	cmlen = CMSG32_SPACE(len);	kmsg->msg_control += cmlen;	kmsg->msg_controllen -= cmlen;}static void scm_detach_fds32(struct msghdr *kmsg, struct scm_cookie *scm){	struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control;	int fdmax = (kmsg->msg_controllen - sizeof(struct cmsghdr32)) / sizeof(int);	int fdnum = scm->fp->count;	struct file **fp = scm->fp->fp;	int *cmfptr;	int err = 0, i;	if (fdnum < fdmax)		fdmax = fdnum;	for (i = 0, cmfptr = (int *) CMSG32_DATA(cm); i < fdmax; i++, cmfptr++) {		int new_fd;		err = get_unused_fd();		if (err < 0)			break;		new_fd = err;		err = put_user(new_fd, cmfptr);		if (err) {			put_unused_fd(new_fd);			break;		}		/* Bump the usage count and install the file. */		get_file(fp[i]);		fd_install(new_fd, fp[i]);	}	if (i > 0) {		int cmlen = CMSG32_LEN(i * sizeof(int));		if (!err)			err = put_user(SOL_SOCKET, &cm->cmsg_level);		if (!err)			err = put_user(SCM_RIGHTS, &cm->cmsg_type);		if (!err)			err = put_user(cmlen, &cm->cmsg_len);		if (!err) {			cmlen = CMSG32_SPACE(i * sizeof(int));			kmsg->msg_control += cmlen;			kmsg->msg_controllen -= cmlen;		}	}	if (i < fdnum)		kmsg->msg_flags |= MSG_CTRUNC;	/*	 * All of the files that fit in the message have had their	 * usage counts incremented, so we just free the list.	 */	__scm_destroy(scm);}/* In these cases we (currently) can just copy to data over verbatim * because all CMSGs created by the kernel have well defined types which * have the same layout in both the 32-bit and 64-bit API.  One must add * some special cased conversions here if we start sending control messages * with incompatible types. * * SCM_RIGHTS and SCM_CREDENTIALS are done by hand in recvmsg32 right after * we do our work.  The remaining cases are: * * SOL_IP	IP_PKTINFO	struct in_pktinfo	32-bit clean *		IP_TTL		int			32-bit clean *		IP_TOS		__u8			32-bit clean *		IP_RECVOPTS	variable length		32-bit clean *		IP_RETOPTS	variable length		32-bit clean *		(these last two are clean because the types are defined *		 by the IPv4 protocol) *		IP_RECVERR	struct sock_extended_err + *				struct sockaddr_in	32-bit clean * SOL_IPV6	IPV6_RECVERR	struct sock_extended_err + *				struct sockaddr_in6	32-bit clean *		IPV6_PKTINFO	struct in6_pktinfo	32-bit clean *		IPV6_HOPLIMIT	int			32-bit clean *		IPV6_FLOWINFO	u32			32-bit clean *		IPV6_HOPOPTS	ipv6 hop exthdr		32-bit clean *		IPV6_DSTOPTS	ipv6 dst exthdr(s)	32-bit clean *		IPV6_RTHDR	ipv6 routing exthdr	32-bit clean *		IPV6_AUTHHDR	ipv6 auth exthdr	32-bit clean */static void cmsg32_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_uptr){	unsigned char *workbuf, *wp;	unsigned long bufsz, space_avail;	struct cmsghdr *ucmsg;	bufsz = ((unsigned long)kmsg->msg_control) - orig_cmsg_uptr;	space_avail = kmsg->msg_controllen + bufsz;	wp = workbuf = kmalloc(bufsz, GFP_KERNEL);	if(workbuf == NULL)		goto fail;	/* To make this more sane we assume the kernel sends back properly	 * formatted control messages.  Because of how the kernel will truncate	 * the cmsg_len for MSG_TRUNC cases, we need not check that case either.	 */	ucmsg = (struct cmsghdr *) orig_cmsg_uptr;	while(((unsigned long)ucmsg) <=	      (((unsigned long)kmsg->msg_control) - sizeof(struct cmsghdr))) {		struct cmsghdr32 *kcmsg32 = (struct cmsghdr32 *) wp;		int clen64, clen32;		/* UCMSG is the 64-bit format CMSG entry in user-space.		 * KCMSG32 is within the kernel space temporary buffer		 * we use to convert into a 32-bit style CMSG.		 */		__get_user(kcmsg32->cmsg_len, &ucmsg->cmsg_len);		__get_user(kcmsg32->cmsg_level, &ucmsg->cmsg_level);		__get_user(kcmsg32->cmsg_type, &ucmsg->cmsg_type);		clen64 = kcmsg32->cmsg_len;		copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg),			       clen64 - CMSG_ALIGN(sizeof(*ucmsg)));		clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) +			  CMSG32_ALIGN(sizeof(struct cmsghdr32)));		kcmsg32->cmsg_len = clen32;		ucmsg = (struct cmsghdr *) (((char *)ucmsg) + CMSG_ALIGN(clen64));		wp = (((char *)kcmsg32) + CMSG32_ALIGN(clen32));	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -