📄 sys_parisc32.c
字号:
unsigned long cmsg_ptr; int err, total_len, len = 0; if(msghdr_from_user32_to_kern(&kern_msg, user_msg)) return -EFAULT; if(kern_msg.msg_iovlen > UIO_MAXIOV) return -EINVAL; uaddr = kern_msg.msg_name; uaddr_len = &user_msg->msg_namelen; err = verify_iovec32(&kern_msg, iov, addr, VERIFY_WRITE); if (err < 0) goto out; total_len = err; cmsg_ptr = (unsigned long) kern_msg.msg_control; kern_msg.msg_flags = 0; sock = sockfd_lookup(fd, &err); if (sock != NULL) { struct scm_cookie scm; if (sock->file->f_flags & O_NONBLOCK) user_flags |= MSG_DONTWAIT; memset(&scm, 0, sizeof(scm)); err = sock->ops->recvmsg(sock, &kern_msg, total_len, user_flags, &scm); if(err >= 0) { len = err; if(!kern_msg.msg_control) { if(sock->passcred || scm.fp) kern_msg.msg_flags |= MSG_CTRUNC; if(scm.fp) __scm_destroy(&scm); } else { /* If recvmsg processing itself placed some * control messages into user space, it's is * using 64-bit CMSG processing, so we need * to fix it up before we tack on more stuff. */ if((unsigned long) kern_msg.msg_control != cmsg_ptr) cmsg32_recvmsg_fixup(&kern_msg, cmsg_ptr); /* Wheee... */ if(sock->passcred) put_cmsg32(&kern_msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(scm.creds), &scm.creds); if(scm.fp != NULL) scm_detach_fds32(&kern_msg, &scm); } } sockfd_put(sock); } if(uaddr != NULL && err >= 0) err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, uaddr_len); if(cmsg_ptr != 0 && err >= 0) { unsigned long ucmsg_ptr = ((unsigned long)kern_msg.msg_control); __kernel_size_t32 uclen = (__kernel_size_t32) (ucmsg_ptr - cmsg_ptr); err |= __put_user(uclen, &user_msg->msg_controllen); } if(err >= 0) err = __put_user(kern_msg.msg_flags, &user_msg->msg_flags); if(kern_msg.msg_iov != iov) kfree(kern_msg.msg_iov);out: if(err < 0) return err; return len;}extern asmlinkage int sys_setsockopt(int fd, int level, int optname, char *optval, int optlen);static int do_set_attach_filter(int fd, int level, int optname, char *optval, int optlen){ struct sock_fprog32 { __u16 len; __u32 filter; } *fprog32 = (struct sock_fprog32 *)optval; struct sock_fprog kfprog; struct sock_filter *kfilter; unsigned int fsize; mm_segment_t old_fs; __u32 uptr; int ret; if (get_user(kfprog.len, &fprog32->len) || __get_user(uptr, &fprog32->filter)) return -EFAULT; kfprog.filter = (struct sock_filter *)A(uptr); fsize = kfprog.len * sizeof(struct sock_filter); kfilter = (struct sock_filter *)kmalloc(fsize, GFP_KERNEL); if (kfilter == NULL) return -ENOMEM; if (copy_from_user(kfilter, kfprog.filter, fsize)) { kfree(kfilter); return -EFAULT; } kfprog.filter = kfilter; old_fs = get_fs(); set_fs(KERNEL_DS); ret = sys_setsockopt(fd, level, optname, (char *)&kfprog, sizeof(kfprog)); set_fs(old_fs); kfree(kfilter); return ret;}static int do_set_icmpv6_filter(int fd, int level, int optname, char *optval, int optlen){ struct icmp6_filter kfilter; mm_segment_t old_fs; int ret, i; if (copy_from_user(&kfilter, optval, sizeof(kfilter))) return -EFAULT; for (i = 0; i < 8; i += 2) { u32 tmp = kfilter.data[i]; kfilter.data[i] = kfilter.data[i + 1]; kfilter.data[i + 1] = tmp; } old_fs = get_fs(); set_fs(KERNEL_DS); ret = sys_setsockopt(fd, level, optname, (char *) &kfilter, sizeof(kfilter)); set_fs(old_fs); return ret;}static int do_ipv4_set_replace(int fd, int level, int optname, char *optval, int optlen)#if 1/* Fields happen to be padded such that this works.** Don't need to change iptables.h:struct ipt_replace*/{ struct ipt_replace *repl = (struct ipt_replace *) optval; unsigned long ptr64; unsigned int ptr32; int ret; if (copy_from_user(&ptr32, &repl->counters, sizeof(ptr32))) return -EFAULT; ptr64 = (unsigned long) ptr32; if (copy_to_user(&repl->counters, &ptr64, sizeof(ptr64))) return -EFAULT; ret = sys_setsockopt(fd, level, optname, (char *) optval, optlen); /* Restore 32-bit ptr */ if (copy_to_user(&repl->counters, &ptr32, sizeof(ptr32))) return -EFAULT; return ret;}#else/* This version tries to "do it right". ie allocate kernel buffers for** everything and copy data in/out. Way too complicated.** NOT TESTED for correctness!*/{ struct ipt_replace *kern_repl; struct ipt_counters *kern_counters; unsigned int user_counters; mm_segment_t old_fs; int ret = 0; kern_repl = (struct ipt_replace *) kmalloc(optlen+8, GFP_KERNEL); if (!kern_repl) return -ENOMEM; if (copy_from_user(kern_repl, optval, optlen)) { ret = -EFAULT; goto err02; } /* 32-bit ptr is in the MSB's */ user_counters = (unsigned int) (((unsigned long) kern_repl->counters) >> 32); /* ** We are going to set_fs() to kernel space - and thus need ** "relocate" the counters buffer to the kernel space. */ kern_counters = (struct ipt_counters *) kmalloc(kern_repl->num_counters * sizeof(struct ipt_counters), GFP_KERNEL); if (!user_counters) { ret = -ENOMEM; goto err02; } if (copy_from_user(kern_counters, (char *) user_counters, optlen)) { ret = -EFAULT; goto err01; } /* We can update the kernel ptr now that we have the data. */ kern_repl->counters = kern_counters; old_fs = get_fs(); set_fs(KERNEL_DS); ret = sys_setsockopt(fd, level, optname, (char *) optval, optlen); set_fs(old_fs); /* Copy counters back out to user space */ if (copy_to_user((char *) user_counters, kern_counters, kern_repl->num_counters * sizeof(struct ipt_counters))) { ret = -EFAULT; goto err01; } /* restore counters so userspace can consume it */ kern_repl->counters = NULL; (unsigned int) kern_repl->counters = user_counters; /* Copy repl back out to user space */ if (copy_to_user(optval, kern_repl, optlen)) { ret = -EFAULT; }err01: kfree(kern_counters);err02: kfree(kern_repl); return ret;}#endifasmlinkage int sys32_setsockopt(int fd, int level, int optname, char *optval, int optlen){ if (optname == SO_ATTACH_FILTER) return do_set_attach_filter(fd, level, optname, optval, optlen); if (level == SOL_ICMPV6 && optname == ICMPV6_FILTER) return do_set_icmpv6_filter(fd, level, optname, optval, optlen); /* ** Beware: IPT_SO_SET_REPLACE == IP6T_SO_SET_REPLACE */ if (level == IPPROTO_IP && optname == IPT_SO_SET_REPLACE) return do_ipv4_set_replace(fd, level, optname, optval, optlen); if (level == IPPROTO_IPV6 && optname == IP6T_SO_SET_REPLACE)#if 0 /* FIXME: I don't (yet) use IPV6. -ggg */ return do_ipv6_set_replace(fd, level, optname, optval, optlen);#else { BUG(); return -ENXIO; }#endif return sys_setsockopt(fd, level, optname, optval, optlen);}/*** copied from mips64 ***//* * Ooo, nasty. We need here to frob 32-bit unsigned longs to * 64-bit unsigned longs. */static inline intget_fd_set32(unsigned long n, u32 *ufdset, unsigned long *fdset){ n = (n + 8*sizeof(u32) - 1) / (8*sizeof(u32)); if (ufdset) { unsigned long odd; if (verify_area(VERIFY_WRITE, ufdset, n*sizeof(u32))) return -EFAULT; odd = n & 1UL; n &= ~1UL; while (n) { unsigned long h, l; __get_user(l, ufdset); __get_user(h, ufdset+1); ufdset += 2; *fdset++ = h << 32 | l; n -= 2; } if (odd) __get_user(*fdset, ufdset); } else { /* Tricky, must clear full unsigned long in the * kernel fdset at the end, this makes sure that * actually happens. */ memset(fdset, 0, ((n + 1) & ~1)*sizeof(u32)); } return 0;}static inline voidset_fd_set32(unsigned long n, u32 *ufdset, unsigned long *fdset){ unsigned long odd; n = (n + 8*sizeof(u32) - 1) / (8*sizeof(u32)); if (!ufdset) return; odd = n & 1UL; n &= ~1UL; while (n) { unsigned long h, l; l = *fdset++; h = l >> 32; __put_user(l, ufdset); __put_user(h, ufdset+1); ufdset += 2; n -= 2; } if (odd) __put_user(*fdset, ufdset);}/*** This is a virtual copy of sys_select from fs/select.c and probably *** should be compared to it from time to time ***/static inline void *select_bits_alloc(int size){ return kmalloc(6 * size, GFP_KERNEL);}static inline void select_bits_free(void *bits, int size){ kfree(bits);}/* * We can actually return ERESTARTSYS instead of EINTR, but I'd * like to be certain this leads to no problems. So I return * EINTR just for safety. * * Update: ERESTARTSYS breaks at least the xview clock binary, so * I'm trying ERESTARTNOHAND which restart only when you want to. */#define MAX_SELECT_SECONDS \ ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)#define DIVIDE_ROUND_UP(x,y) (((x)+(y)-1)/(y))asmlinkage longsys32_select(int n, u32 *inp, u32 *outp, u32 *exp, struct timeval32 *tvp){ fd_set_bits fds; char *bits; long timeout; int ret, size, err; timeout = MAX_SCHEDULE_TIMEOUT; if (tvp) { struct timeval32 tv32; time_t sec, usec; if ((ret = copy_from_user(&tv32, tvp, sizeof tv32))) goto out_nofds; sec = tv32.tv_sec; usec = tv32.tv_usec; ret = -EINVAL; if (sec < 0 || usec < 0) goto out_nofds; if ((unsigned long) sec < MAX_SELECT_SECONDS) { timeout = DIVIDE_ROUND_UP(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 = select_bits_alloc(size); 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_set32(n, inp, fds.in)) || (ret = get_fd_set32(n, outp, fds.out)) || (ret = get_fd_set32(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 (tvp && !(current->personality & STICKY_TIMEOUTS)) { time_t sec = 0, usec = 0; if (timeout) { sec = timeout / HZ; usec = timeout % HZ; usec *= (1000000/HZ); } err = put_user(sec, &tvp->tv_sec); err |= __put_user(usec, &tvp->tv_usec); if (err) ret = -EFAULT; } if (ret < 0) goto out; if (!ret) { ret = -ERESTARTNOHAND; if (signal_pending(current)) goto out; ret = 0; } set_fd_set32(n, inp, fds.res_in); set_fd_set32(n, outp, fds.res_out); set_fd_set32(n, exp, fds.res_ex);out: select_bits_free(bits, size);out_nofds: return ret;}struct msgbuf32 { int mtype; char mtext[1];};asmlinkage long sys32_msgsnd(int msqid, struct msgbuf32 *umsgp32, size_t msgsz, int msgflg){ struct msgbuf *mb; struct msgbuf32 mb32; int err; if ((mb = kmalloc(msgsz + sizeof *mb + 4, GFP_KERNEL)) == NULL) return -ENOMEM; err = get_user(mb32.mtype, &umsgp32->mtype); mb->mtype = mb32.mtype; err |= copy_from_user(mb->mtext, &umsgp32->mtext, msgsz); if (err) err = -EFAULT; else KERNEL_SYSCALL(err, sys_msgsnd, msqid, mb, msgsz, msgflg); kfree(mb); return err;}asmlinkage long sys32_msgrcv(int msqid, struct msgbuf32 *umsgp32, size_t msgsz, long msgtyp, int msgflg){ struct msgbuf *mb; struct msgbuf32 mb32; int err, len; if ((mb = kmalloc(msgsz + sizeof *mb + 4, GFP_KERNEL)) == NULL) return -ENOMEM; KERNEL_SYSCALL(err, sys_msgrcv, msqid, mb, msgsz, msgtyp, msgflg); if (err >= 0) { len = err; mb32.mtype = mb->mtype; err = put_user(mb32.mtype, &umsgp32->mtype); err |= copy_to_user(&umsgp32->mtext, mb->mtext, len); if (err) err = -EFAULT; else err = len; } kfree(mb); return err;}/* LFS */extern asmlinkage long sys_truncate(const char *, loff_t);extern asmlinkage long sys_ftruncate(unsigned int, loff_t);extern asmlinkage long sys_fcntl(unsigned int, unsigned int, unsigned long);extern asmlinkage ssize_t sys_pread(unsigned int, char *, size_t, loff_t);extern asmlinkage ssize_t sys_pwrite(unsigned int, char *, size_t, loff_t);asmlinkage long sys32_truncate64(const char * path, unsigned int high, unsigned int low){ return sys_truncate(path, (loff_t)high << 32 | low);}asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned int high, unsigned int low){ return sys_ftruncate(fd, (loff_t)high << 32 | low);}asmlinkage long sys32_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg){ switch (cmd) { case F_GETLK64: cmd = F_GETLK; break; case F_SETLK64: cmd = F_SETLK; break; case F_SETLKW64: cmd = F_SETLKW; break; default: break; } return sys_fcntl(fd, cmd, arg);}asmlinkage int sys32_pread(int fd, void *buf, size
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -