diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-04-27 12:26:46 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-04-27 12:26:46 -0400 |
commit | 15c54033964a943de7b0763efd3bd0ede7326395 (patch) | |
tree | 840b292612d1b5396d5bab5bde537a9013db3ceb /net/compat.c | |
parent | ad5da3cf39a5b11a198929be1f2644e17ecd767e (diff) | |
parent | 912a41a4ab935ce8c4308428ec13fc7f8b1f18f4 (diff) |
Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6: (448 commits)
[IPV4] nl_fib_lookup: Initialise res.r before fib_res_put(&res)
[IPV6]: Fix thinko in ipv6_rthdr_rcv() changes.
[IPV4]: Add multipath cached to feature-removal-schedule.txt
[WIRELESS] cfg80211: Clarify locking comment.
[WIRELESS] cfg80211: Fix locking in wiphy_new.
[WEXT] net_device: Don't include wext bits if not required.
[WEXT]: Misc code cleanups.
[WEXT]: Reduce inline abuse.
[WEXT]: Move EXPORT_SYMBOL statements where they belong.
[WEXT]: Cleanup early ioctl call path.
[WEXT]: Remove options.
[WEXT]: Remove dead debug code.
[WEXT]: Clean up how wext is called.
[WEXT]: Move to net/wireless
[AFS]: Eliminate cmpxchg() usage in vlocation code.
[RXRPC]: Fix pointers passed to bitops.
[RXRPC]: Remove bogus atomic_* overrides.
[AFS]: Fix u64 printing in debug logging.
[AFS]: Add "directory write" support.
[AFS]: Implement the CB.InitCallBackState3 operation.
...
Diffstat (limited to 'net/compat.c')
-rw-r--r-- | net/compat.c | 79 |
1 files changed, 58 insertions, 21 deletions
diff --git a/net/compat.c b/net/compat.c index 1f32866d09b7..9a0f5f2b90c8 100644 --- a/net/compat.c +++ b/net/compat.c | |||
@@ -34,11 +34,11 @@ static inline int iov_from_user_compat_to_kern(struct iovec *kiov, | |||
34 | { | 34 | { |
35 | int tot_len = 0; | 35 | int tot_len = 0; |
36 | 36 | ||
37 | while(niov > 0) { | 37 | while (niov > 0) { |
38 | compat_uptr_t buf; | 38 | compat_uptr_t buf; |
39 | compat_size_t len; | 39 | compat_size_t len; |
40 | 40 | ||
41 | if(get_user(len, &uiov32->iov_len) || | 41 | if (get_user(len, &uiov32->iov_len) || |
42 | get_user(buf, &uiov32->iov_base)) { | 42 | get_user(buf, &uiov32->iov_base)) { |
43 | tot_len = -EFAULT; | 43 | tot_len = -EFAULT; |
44 | break; | 44 | break; |
@@ -78,12 +78,12 @@ int verify_compat_iovec(struct msghdr *kern_msg, struct iovec *kern_iov, | |||
78 | { | 78 | { |
79 | int tot_len; | 79 | int tot_len; |
80 | 80 | ||
81 | if(kern_msg->msg_namelen) { | 81 | if (kern_msg->msg_namelen) { |
82 | if(mode==VERIFY_READ) { | 82 | if (mode==VERIFY_READ) { |
83 | int err = move_addr_to_kernel(kern_msg->msg_name, | 83 | int err = move_addr_to_kernel(kern_msg->msg_name, |
84 | kern_msg->msg_namelen, | 84 | kern_msg->msg_namelen, |
85 | kern_address); | 85 | kern_address); |
86 | if(err < 0) | 86 | if (err < 0) |
87 | return err; | 87 | return err; |
88 | } | 88 | } |
89 | kern_msg->msg_name = kern_address; | 89 | kern_msg->msg_name = kern_address; |
@@ -93,7 +93,7 @@ int verify_compat_iovec(struct msghdr *kern_msg, struct iovec *kern_iov, | |||
93 | tot_len = iov_from_user_compat_to_kern(kern_iov, | 93 | tot_len = iov_from_user_compat_to_kern(kern_iov, |
94 | (struct compat_iovec __user *)kern_msg->msg_iov, | 94 | (struct compat_iovec __user *)kern_msg->msg_iov, |
95 | kern_msg->msg_iovlen); | 95 | kern_msg->msg_iovlen); |
96 | if(tot_len >= 0) | 96 | if (tot_len >= 0) |
97 | kern_msg->msg_iov = kern_iov; | 97 | kern_msg->msg_iov = kern_iov; |
98 | 98 | ||
99 | return tot_len; | 99 | return tot_len; |
@@ -146,8 +146,8 @@ int cmsghdr_from_user_compat_to_kern(struct msghdr *kmsg, struct sock *sk, | |||
146 | kcmlen = 0; | 146 | kcmlen = 0; |
147 | kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf; | 147 | kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf; |
148 | ucmsg = CMSG_COMPAT_FIRSTHDR(kmsg); | 148 | ucmsg = CMSG_COMPAT_FIRSTHDR(kmsg); |
149 | while(ucmsg != NULL) { | 149 | while (ucmsg != NULL) { |
150 | if(get_user(ucmlen, &ucmsg->cmsg_len)) | 150 | if (get_user(ucmlen, &ucmsg->cmsg_len)) |
151 | return -EFAULT; | 151 | return -EFAULT; |
152 | 152 | ||
153 | /* Catch bogons. */ | 153 | /* Catch bogons. */ |
@@ -160,7 +160,7 @@ int cmsghdr_from_user_compat_to_kern(struct msghdr *kmsg, struct sock *sk, | |||
160 | kcmlen += tmp; | 160 | kcmlen += tmp; |
161 | ucmsg = cmsg_compat_nxthdr(kmsg, ucmsg, ucmlen); | 161 | ucmsg = cmsg_compat_nxthdr(kmsg, ucmsg, ucmlen); |
162 | } | 162 | } |
163 | if(kcmlen == 0) | 163 | if (kcmlen == 0) |
164 | return -EINVAL; | 164 | return -EINVAL; |
165 | 165 | ||
166 | /* The kcmlen holds the 64-bit version of the control length. | 166 | /* The kcmlen holds the 64-bit version of the control length. |
@@ -176,7 +176,7 @@ int cmsghdr_from_user_compat_to_kern(struct msghdr *kmsg, struct sock *sk, | |||
176 | /* Now copy them over neatly. */ | 176 | /* Now copy them over neatly. */ |
177 | memset(kcmsg, 0, kcmlen); | 177 | memset(kcmsg, 0, kcmlen); |
178 | ucmsg = CMSG_COMPAT_FIRSTHDR(kmsg); | 178 | ucmsg = CMSG_COMPAT_FIRSTHDR(kmsg); |
179 | while(ucmsg != NULL) { | 179 | while (ucmsg != NULL) { |
180 | if (__get_user(ucmlen, &ucmsg->cmsg_len)) | 180 | if (__get_user(ucmlen, &ucmsg->cmsg_len)) |
181 | goto Efault; | 181 | goto Efault; |
182 | if (!CMSG_COMPAT_OK(ucmlen, ucmsg, kmsg)) | 182 | if (!CMSG_COMPAT_OK(ucmlen, ucmsg, kmsg)) |
@@ -215,11 +215,12 @@ Efault: | |||
215 | int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *data) | 215 | int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *data) |
216 | { | 216 | { |
217 | struct compat_timeval ctv; | 217 | struct compat_timeval ctv; |
218 | struct compat_timespec cts; | ||
218 | struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control; | 219 | struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control; |
219 | struct compat_cmsghdr cmhdr; | 220 | struct compat_cmsghdr cmhdr; |
220 | int cmlen; | 221 | int cmlen; |
221 | 222 | ||
222 | if(cm == NULL || kmsg->msg_controllen < sizeof(*cm)) { | 223 | if (cm == NULL || kmsg->msg_controllen < sizeof(*cm)) { |
223 | kmsg->msg_flags |= MSG_CTRUNC; | 224 | kmsg->msg_flags |= MSG_CTRUNC; |
224 | return 0; /* XXX: return error? check spec. */ | 225 | return 0; /* XXX: return error? check spec. */ |
225 | } | 226 | } |
@@ -229,11 +230,18 @@ int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *dat | |||
229 | ctv.tv_sec = tv->tv_sec; | 230 | ctv.tv_sec = tv->tv_sec; |
230 | ctv.tv_usec = tv->tv_usec; | 231 | ctv.tv_usec = tv->tv_usec; |
231 | data = &ctv; | 232 | data = &ctv; |
232 | len = sizeof(struct compat_timeval); | 233 | len = sizeof(ctv); |
234 | } | ||
235 | if (level == SOL_SOCKET && type == SO_TIMESTAMPNS) { | ||
236 | struct timespec *ts = (struct timespec *)data; | ||
237 | cts.tv_sec = ts->tv_sec; | ||
238 | cts.tv_nsec = ts->tv_nsec; | ||
239 | data = &cts; | ||
240 | len = sizeof(cts); | ||
233 | } | 241 | } |
234 | 242 | ||
235 | cmlen = CMSG_COMPAT_LEN(len); | 243 | cmlen = CMSG_COMPAT_LEN(len); |
236 | if(kmsg->msg_controllen < cmlen) { | 244 | if (kmsg->msg_controllen < cmlen) { |
237 | kmsg->msg_flags |= MSG_CTRUNC; | 245 | kmsg->msg_flags |= MSG_CTRUNC; |
238 | cmlen = kmsg->msg_controllen; | 246 | cmlen = kmsg->msg_controllen; |
239 | } | 247 | } |
@@ -241,9 +249,9 @@ int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *dat | |||
241 | cmhdr.cmsg_type = type; | 249 | cmhdr.cmsg_type = type; |
242 | cmhdr.cmsg_len = cmlen; | 250 | cmhdr.cmsg_len = cmlen; |
243 | 251 | ||
244 | if(copy_to_user(cm, &cmhdr, sizeof cmhdr)) | 252 | if (copy_to_user(cm, &cmhdr, sizeof cmhdr)) |
245 | return -EFAULT; | 253 | return -EFAULT; |
246 | if(copy_to_user(CMSG_COMPAT_DATA(cm), data, cmlen - sizeof(struct compat_cmsghdr))) | 254 | if (copy_to_user(CMSG_COMPAT_DATA(cm), data, cmlen - sizeof(struct compat_cmsghdr))) |
247 | return -EFAULT; | 255 | return -EFAULT; |
248 | cmlen = CMSG_COMPAT_SPACE(len); | 256 | cmlen = CMSG_COMPAT_SPACE(len); |
249 | kmsg->msg_control += cmlen; | 257 | kmsg->msg_control += cmlen; |
@@ -545,20 +553,49 @@ int compat_sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp) | |||
545 | struct compat_timeval __user *ctv = | 553 | struct compat_timeval __user *ctv = |
546 | (struct compat_timeval __user*) userstamp; | 554 | (struct compat_timeval __user*) userstamp; |
547 | int err = -ENOENT; | 555 | int err = -ENOENT; |
556 | struct timeval tv; | ||
548 | 557 | ||
549 | if (!sock_flag(sk, SOCK_TIMESTAMP)) | 558 | if (!sock_flag(sk, SOCK_TIMESTAMP)) |
550 | sock_enable_timestamp(sk); | 559 | sock_enable_timestamp(sk); |
551 | if (sk->sk_stamp.tv_sec == -1) | 560 | tv = ktime_to_timeval(sk->sk_stamp); |
561 | if (tv.tv_sec == -1) | ||
552 | return err; | 562 | return err; |
553 | if (sk->sk_stamp.tv_sec == 0) | 563 | if (tv.tv_sec == 0) { |
554 | do_gettimeofday(&sk->sk_stamp); | 564 | sk->sk_stamp = ktime_get_real(); |
555 | if (put_user(sk->sk_stamp.tv_sec, &ctv->tv_sec) || | 565 | tv = ktime_to_timeval(sk->sk_stamp); |
556 | put_user(sk->sk_stamp.tv_usec, &ctv->tv_usec)) | 566 | } |
567 | err = 0; | ||
568 | if (put_user(tv.tv_sec, &ctv->tv_sec) || | ||
569 | put_user(tv.tv_usec, &ctv->tv_usec)) | ||
557 | err = -EFAULT; | 570 | err = -EFAULT; |
558 | return err; | 571 | return err; |
559 | } | 572 | } |
560 | EXPORT_SYMBOL(compat_sock_get_timestamp); | 573 | EXPORT_SYMBOL(compat_sock_get_timestamp); |
561 | 574 | ||
575 | int compat_sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp) | ||
576 | { | ||
577 | struct compat_timespec __user *ctv = | ||
578 | (struct compat_timespec __user*) userstamp; | ||
579 | int err = -ENOENT; | ||
580 | struct timespec ts; | ||
581 | |||
582 | if (!sock_flag(sk, SOCK_TIMESTAMP)) | ||
583 | sock_enable_timestamp(sk); | ||
584 | ts = ktime_to_timespec(sk->sk_stamp); | ||
585 | if (ts.tv_sec == -1) | ||
586 | return err; | ||
587 | if (ts.tv_sec == 0) { | ||
588 | sk->sk_stamp = ktime_get_real(); | ||
589 | ts = ktime_to_timespec(sk->sk_stamp); | ||
590 | } | ||
591 | err = 0; | ||
592 | if (put_user(ts.tv_sec, &ctv->tv_sec) || | ||
593 | put_user(ts.tv_nsec, &ctv->tv_nsec)) | ||
594 | err = -EFAULT; | ||
595 | return err; | ||
596 | } | ||
597 | EXPORT_SYMBOL(compat_sock_get_timestampns); | ||
598 | |||
562 | asmlinkage long compat_sys_getsockopt(int fd, int level, int optname, | 599 | asmlinkage long compat_sys_getsockopt(int fd, int level, int optname, |
563 | char __user *optval, int __user *optlen) | 600 | char __user *optval, int __user *optlen) |
564 | { | 601 | { |
@@ -617,7 +654,7 @@ asmlinkage long compat_sys_socketcall(int call, u32 __user *args) | |||
617 | a0 = a[0]; | 654 | a0 = a[0]; |
618 | a1 = a[1]; | 655 | a1 = a[1]; |
619 | 656 | ||
620 | switch(call) { | 657 | switch (call) { |
621 | case SYS_SOCKET: | 658 | case SYS_SOCKET: |
622 | ret = sys_socket(a0, a1, a[2]); | 659 | ret = sys_socket(a0, a1, a[2]); |
623 | break; | 660 | break; |