aboutsummaryrefslogtreecommitdiffstats
path: root/net/compat.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-04-27 12:26:46 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-04-27 12:26:46 -0400
commit15c54033964a943de7b0763efd3bd0ede7326395 (patch)
tree840b292612d1b5396d5bab5bde537a9013db3ceb /net/compat.c
parentad5da3cf39a5b11a198929be1f2644e17ecd767e (diff)
parent912a41a4ab935ce8c4308428ec13fc7f8b1f18f4 (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.c79
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:
215int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *data) 215int 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}
560EXPORT_SYMBOL(compat_sock_get_timestamp); 573EXPORT_SYMBOL(compat_sock_get_timestamp);
561 574
575int 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}
597EXPORT_SYMBOL(compat_sock_get_timestampns);
598
562asmlinkage long compat_sys_getsockopt(int fd, int level, int optname, 599asmlinkage 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;