📄 sys_ia32.c
字号:
#define ROUND_UP_TIME(x,y) (((x)+(y)-1)/(y))asmlinkage longsys32_select (int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval32 *tvp32){ fd_set_bits fds; char *bits; long timeout; int ret, size; timeout = MAX_SCHEDULE_TIMEOUT; if (tvp32) { time_t sec, usec; ret = -EFAULT; if (get_user(sec, &tvp32->tv_sec) || get_user(usec, &tvp32->tv_usec)) goto out_nofds; ret = -EINVAL; if (sec < 0 || usec < 0) goto out_nofds; if ((unsigned long) sec < MAX_SELECT_SECONDS) { timeout = ROUND_UP_TIME(usec, 1000000/HZ); timeout += sec * (unsigned long) HZ; } } ret = -EINVAL; if (n < 0) goto out_nofds; if (n > current->files->max_fdset) n = current->files->max_fdset; /* * We need 6 bitmaps (in/out/ex for both incoming and outgoing), * since we used fdset we need to allocate memory in units of * long-words. */ ret = -ENOMEM; size = FDS_BYTES(n); bits = kmalloc(6 * size, GFP_KERNEL); if (!bits) goto out_nofds; fds.in = (unsigned long *) bits; fds.out = (unsigned long *) (bits + size); fds.ex = (unsigned long *) (bits + 2*size); fds.res_in = (unsigned long *) (bits + 3*size); fds.res_out = (unsigned long *) (bits + 4*size); fds.res_ex = (unsigned long *) (bits + 5*size); if ((ret = get_fd_set(n, inp, fds.in)) || (ret = get_fd_set(n, outp, fds.out)) || (ret = get_fd_set(n, exp, fds.ex))) goto out; zero_fd_set(n, fds.res_in); zero_fd_set(n, fds.res_out); zero_fd_set(n, fds.res_ex); ret = do_select(n, &fds, &timeout); if (tvp32 && !(current->personality & STICKY_TIMEOUTS)) { time_t sec = 0, usec = 0; if (timeout) { sec = timeout / HZ; usec = timeout % HZ; usec *= (1000000/HZ); } if (put_user(sec, &tvp32->tv_sec) || put_user(usec, &tvp32->tv_usec)) { ret = -EFAULT; goto out; } } if (ret < 0) goto out; if (!ret) { ret = -ERESTARTNOHAND; if (signal_pending(current)) goto out; ret = 0; } set_fd_set(n, inp, fds.res_in); set_fd_set(n, outp, fds.res_out); set_fd_set(n, exp, fds.res_ex);out: kfree(bits);out_nofds: return ret;}struct sel_arg_struct { unsigned int n; unsigned int inp; unsigned int outp; unsigned int exp; unsigned int tvp;};asmlinkage longsys32_old_select (struct sel_arg_struct *arg){ struct sel_arg_struct a; if (copy_from_user(&a, arg, sizeof(a))) return -EFAULT; return sys32_select(a.n, (fd_set *) A(a.inp), (fd_set *) A(a.outp), (fd_set *) A(a.exp), (struct timeval32 *) A(a.tvp));}extern asmlinkage long sys_nanosleep (struct timespec *rqtp, struct timespec *rmtp);asmlinkage longsys32_nanosleep (struct timespec32 *rqtp, struct timespec32 *rmtp){ struct timespec t; int ret; mm_segment_t old_fs = get_fs(); if (get_user (t.tv_sec, &rqtp->tv_sec) || get_user (t.tv_nsec, &rqtp->tv_nsec)) return -EFAULT; set_fs(KERNEL_DS); ret = sys_nanosleep(&t, rmtp ? &t : NULL); set_fs(old_fs); if (rmtp && ret == -EINTR) { if (put_user(t.tv_sec, &rmtp->tv_sec) || put_user(t.tv_nsec, &rmtp->tv_nsec)) return -EFAULT; } return ret;}struct iovec32 { unsigned int iov_base; int iov_len; };asmlinkage ssize_t sys_readv (unsigned long,const struct iovec *,unsigned long);asmlinkage ssize_t sys_writev (unsigned long,const struct iovec *,unsigned long);static struct iovec *get_iovec32 (struct iovec32 *iov32, struct iovec *iov_buf, u32 count, int type){ int i; u32 buf, len; struct iovec *ivp, *iov; /* Get the "struct iovec" from user memory */ if (!count) return 0; if (verify_area(VERIFY_READ, iov32, sizeof(struct iovec32)*count)) return NULL; if (count > UIO_MAXIOV) return NULL; if (count > UIO_FASTIOV) { iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL); if (!iov) return NULL; } else iov = iov_buf; ivp = iov; for (i = 0; i < count; i++) { if (__get_user(len, &iov32->iov_len) || __get_user(buf, &iov32->iov_base)) { if (iov != iov_buf) kfree(iov); return NULL; } if (verify_area(type, (void *)A(buf), len)) { if (iov != iov_buf) kfree(iov); return((struct iovec *)0); } ivp->iov_base = (void *)A(buf); ivp->iov_len = (__kernel_size_t) len; iov32++; ivp++; } return iov;}asmlinkage longsys32_readv (int fd, struct iovec32 *vector, u32 count){ struct iovec iovstack[UIO_FASTIOV]; struct iovec *iov; long ret; mm_segment_t old_fs = get_fs(); iov = get_iovec32(vector, iovstack, count, VERIFY_WRITE); if (!iov) return -EFAULT; set_fs(KERNEL_DS); ret = sys_readv(fd, iov, count); set_fs(old_fs); if (iov != iovstack) kfree(iov); return ret;}asmlinkage longsys32_writev (int fd, struct iovec32 *vector, u32 count){ struct iovec iovstack[UIO_FASTIOV]; struct iovec *iov; long ret; mm_segment_t old_fs = get_fs(); iov = get_iovec32(vector, iovstack, count, VERIFY_READ); if (!iov) return -EFAULT; set_fs(KERNEL_DS); ret = sys_writev(fd, iov, count); set_fs(old_fs); if (iov != iovstack) kfree(iov); return ret;}#define RLIM_INFINITY32 0x7fffffff#define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x)struct rlimit32 { int rlim_cur; int rlim_max;};extern asmlinkage long sys_getrlimit (unsigned int resource, struct rlimit *rlim);asmlinkage longsys32_old_getrlimit (unsigned int resource, struct rlimit32 *rlim){ mm_segment_t old_fs = get_fs(); struct rlimit r; int ret; set_fs(KERNEL_DS); ret = sys_getrlimit(resource, &r); set_fs(old_fs); if (!ret) { ret = put_user(RESOURCE32(r.rlim_cur), &rlim->rlim_cur); ret |= put_user(RESOURCE32(r.rlim_max), &rlim->rlim_max); } return ret;}asmlinkage longsys32_getrlimit (unsigned int resource, struct rlimit32 *rlim){ mm_segment_t old_fs = get_fs(); struct rlimit r; int ret; set_fs(KERNEL_DS); ret = sys_getrlimit(resource, &r); set_fs(old_fs); if (!ret) { if (r.rlim_cur >= 0xffffffff) r.rlim_cur = 0xffffffff; if (r.rlim_max >= 0xffffffff) r.rlim_max = 0xffffffff; ret = put_user(r.rlim_cur, &rlim->rlim_cur); ret |= put_user(r.rlim_max, &rlim->rlim_max); } return ret;}extern asmlinkage long sys_setrlimit (unsigned int resource, struct rlimit *rlim);asmlinkage longsys32_setrlimit (unsigned int resource, struct rlimit32 *rlim){ struct rlimit r; int ret; mm_segment_t old_fs = get_fs(); if (resource >= RLIM_NLIMITS) return -EINVAL; if (get_user(r.rlim_cur, &rlim->rlim_cur) || get_user(r.rlim_max, &rlim->rlim_max)) return -EFAULT; if (r.rlim_cur == RLIM_INFINITY32) r.rlim_cur = RLIM_INFINITY; if (r.rlim_max == RLIM_INFINITY32) r.rlim_max = RLIM_INFINITY; set_fs(KERNEL_DS); ret = sys_setrlimit(resource, &r); set_fs(old_fs); return ret;}/* * Declare the IA32 version of the msghdr */struct msghdr32 { unsigned int msg_name; /* Socket name */ int msg_namelen; /* Length of name */ unsigned int msg_iov; /* Data blocks */ unsigned int msg_iovlen; /* Number of blocks */ unsigned int msg_control; /* Per protocol magic (eg BSD file descriptor passing) */ unsigned int msg_controllen; /* Length of cmsg list */ unsigned msg_flags;};struct cmsghdr32 { __kernel_size_t32 cmsg_len; int cmsg_level; int cmsg_type;};/* Bleech... */#define __CMSG32_NXTHDR(ctl, len, cmsg, cmsglen) __cmsg32_nxthdr((ctl),(len),(cmsg),(cmsglen))#define CMSG32_NXTHDR(mhdr, cmsg, cmsglen) cmsg32_nxthdr((mhdr), (cmsg), (cmsglen))#define CMSG32_ALIGN(len) ( ((len)+sizeof(int)-1) & ~(sizeof(int)-1) )#define CMSG32_DATA(cmsg) \ ((void *)((char *)(cmsg) + CMSG32_ALIGN(sizeof(struct cmsghdr32))))#define CMSG32_SPACE(len) \ (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + CMSG32_ALIGN(len))#define CMSG32_LEN(len) (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + (len))#define __CMSG32_FIRSTHDR(ctl,len) \ ((len) >= sizeof(struct cmsghdr32) ? (struct cmsghdr32 *)(ctl) : (struct cmsghdr32 *)NULL)#define CMSG32_FIRSTHDR(msg) __CMSG32_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen)static inline struct cmsghdr32 *__cmsg32_nxthdr (void *ctl, __kernel_size_t size, struct cmsghdr32 *cmsg, int cmsg_len){ struct cmsghdr32 * ptr; ptr = (struct cmsghdr32 *)(((unsigned char *) cmsg) + CMSG32_ALIGN(cmsg_len)); if ((unsigned long)((char*)(ptr+1) - (char *) ctl) > size) return NULL; return ptr;}static inline struct cmsghdr32 *cmsg32_nxthdr (struct msghdr *msg, struct cmsghdr32 *cmsg, int cmsg_len){ return __cmsg32_nxthdr(msg->msg_control, msg->msg_controllen, cmsg, cmsg_len);}static inline intget_msghdr32 (struct msghdr *mp, struct msghdr32 *mp32){ int ret; unsigned int i; if (!access_ok(VERIFY_READ, mp32, sizeof(*mp32))) return -EFAULT; ret = __get_user(i, &mp32->msg_name); mp->msg_name = (void *)A(i); ret |= __get_user(mp->msg_namelen, &mp32->msg_namelen); ret |= __get_user(i, &mp32->msg_iov); mp->msg_iov = (struct iovec *)A(i); ret |= __get_user(mp->msg_iovlen, &mp32->msg_iovlen); ret |= __get_user(i, &mp32->msg_control); mp->msg_control = (void *)A(i); ret |= __get_user(mp->msg_controllen, &mp32->msg_controllen); ret |= __get_user(mp->msg_flags, &mp32->msg_flags); return ret ? -EFAULT : 0;}/* * 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 intget_cmsghdr32 (struct msghdr *kmsg, unsigned char *stackbuf, struct sock *sk, size_t *bufsize){ struct cmsghdr *kcmsg, *kcmsg_base; __kernel_size_t kcmlen, tmp; __kernel_size_t32 ucmlen; struct cmsghdr32 *ucmsg; long err; 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 > *bufsize) { *bufsize = kcmlen; kcmsg_base = kcmsg = sock_kmalloc(sk, kcmlen, GFP_KERNEL); } if (kcmsg == NULL) return -ENOBUFS; /* Now copy them over neatly. */ memset(kcmsg, 0, kcmlen); ucmsg = CMSG32_FIRSTHDR(kmsg); while (ucmsg != NULL) { err = get_user(ucmlen, &ucmsg->cmsg_len); tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) + CMSG_ALIGN(sizeof(struct cmsghdr))); kcmsg->cmsg_len = tmp; err |= get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level); err |= get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type); /* Copy over the data. */ err |= copy_from_user(CMSG_DATA(kcmsg), CMSG32_DATA(ucmsg), (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg)))); if (err) 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) sock_kfree_s(sk, kcmsg_base, kcmlen); return -EFAULT;}/* * Verify & re-shape IA32 iovec. The caller must ensure that the * iovec is big enough to hold the re-shaped message iovec. * * Save time not doing verify_area. copy_*_user will make this work * in any case. * * Don't need to check the total size for overflow (cf net/core/iovec.c), * 32-bit sizes can't overflow a 64-bit count. */static inline intverify_iovec32 (struct msghdr *m, struct iovec *iov, char *address, int mode){ int size, err, ct; struct iovec32 *iov32; if (m->msg_namelen) { if (mode == VERIFY_READ) { err = move_addr_to_kernel(m->msg_name, m->msg_namelen, address); if (err < 0) goto out; } m->msg_name = address; } else m->msg_name = NULL; err = -EFAULT; size = m->msg_iovlen * sizeof(struct iovec32); if (copy_from_user(iov, m->msg_iov, size)) goto out; m->msg_iov = iov; err = 0; iov32 = (struct iovec32 *)iov; for (ct = m->msg_iovlen; ct-- > 0; ) { iov[ct].iov_len = (__kernel_size_t)iov32[ct].iov_len; iov[ct].iov_base = (void *) A(iov32[ct].iov_base); err += iov[ct].iov_len; }out: return err;}static voidput_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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -