Blame view

net/compat.c 14.2 KB
457c89965   Thomas Gleixner   treewide: Add SPD...
1
  // SPDX-License-Identifier: GPL-2.0-only
4768fbcbc   YOSHIFUJI Hideaki   [NET]: Fix whites...
2
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
5
6
7
8
9
10
11
   * 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>
4768fbcbc   YOSHIFUJI Hideaki   [NET]: Fix whites...
12
   * Copyright (C) 2000,2001	Andi Kleen, SuSE Labs
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
14
15
   */
  
  #include <linux/kernel.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
16
  #include <linux/gfp.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
  #include <linux/fs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
20
21
22
23
24
  #include <linux/types.h>
  #include <linux/file.h>
  #include <linux/icmpv6.h>
  #include <linux/socket.h>
  #include <linux/syscalls.h>
  #include <linux/filter.h>
  #include <linux/compat.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
  #include <linux/security.h>
62bc306e2   Richard Guy Briggs   audit: log 32-bit...
26
  #include <linux/audit.h>
bc3b2d7fb   Paul Gortmaker   net: Add export.h...
27
  #include <linux/export.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
30
  
  #include <net/scm.h>
  #include <net/sock.h>
dae502954   David L Stevens   ipv4/ipv6 compat:...
31
32
  #include <net/ip.h>
  #include <net/ipv6.h>
7c0f6ba68   Linus Torvalds   Replace <asm/uacc...
33
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
  #include <net/compat.h>
0a384abfa   Jens Axboe   net: abstract out...
35
36
37
38
  int __get_compat_msghdr(struct msghdr *kmsg,
  			struct compat_msghdr __user *umsg,
  			struct sockaddr __user **save_addr,
  			compat_uptr_t *ptr, compat_size_t *len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
  {
5da028a8a   Al Viro   get_compat_msghdr...
40
  	struct compat_msghdr msg;
08adb7dab   Al Viro   fold verify_iovec...
41
  	ssize_t err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42

5da028a8a   Al Viro   get_compat_msghdr...
43
  	if (copy_from_user(&msg, umsg, sizeof(*umsg)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
  		return -EFAULT;
91edd096e   Catalin Marinas   net: compat: Upda...
45

5da028a8a   Al Viro   get_compat_msghdr...
46
47
48
49
  	kmsg->msg_flags = msg.msg_flags;
  	kmsg->msg_namelen = msg.msg_namelen;
  
  	if (!msg.msg_name)
91edd096e   Catalin Marinas   net: compat: Upda...
50
51
52
53
  		kmsg->msg_namelen = 0;
  
  	if (kmsg->msg_namelen < 0)
  		return -EINVAL;
1661bf364   Dan Carpenter   net: heap overflo...
54
  	if (kmsg->msg_namelen > sizeof(struct sockaddr_storage))
db31c55a6   Dan Carpenter   net: clamp ->msg_...
55
  		kmsg->msg_namelen = sizeof(struct sockaddr_storage);
5da028a8a   Al Viro   get_compat_msghdr...
56

1f466e1f1   Christoph Hellwig   net: cleanly hand...
57
58
  	kmsg->msg_control_is_user = true;
  	kmsg->msg_control_user = compat_ptr(msg.msg_control);
5da028a8a   Al Viro   get_compat_msghdr...
59
  	kmsg->msg_controllen = msg.msg_controllen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60

08adb7dab   Al Viro   fold verify_iovec...
61
  	if (save_addr)
5da028a8a   Al Viro   get_compat_msghdr...
62
  		*save_addr = compat_ptr(msg.msg_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63

5da028a8a   Al Viro   get_compat_msghdr...
64
  	if (msg.msg_name && kmsg->msg_namelen) {
08adb7dab   Al Viro   fold verify_iovec...
65
  		if (!save_addr) {
5da028a8a   Al Viro   get_compat_msghdr...
66
  			err = move_addr_to_kernel(compat_ptr(msg.msg_name),
08adb7dab   Al Viro   fold verify_iovec...
67
68
  						  kmsg->msg_namelen,
  						  kmsg->msg_name);
e71a4783a   Stephen Hemminger   [NET] core: white...
69
  			if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
  				return err;
  		}
40eea803c   Andrey Ryabinin   net: sendmsg: fix...
72
  	} else {
08adb7dab   Al Viro   fold verify_iovec...
73
74
  		kmsg->msg_name = NULL;
  		kmsg->msg_namelen = 0;
40eea803c   Andrey Ryabinin   net: sendmsg: fix...
75
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76

5da028a8a   Al Viro   get_compat_msghdr...
77
  	if (msg.msg_iovlen > UIO_MAXIOV)
084493200   Al Viro   {compat_,}verify_...
78
  		return -EMSGSIZE;
0345f9313   tadeusz.struk@intel.com   net: socket: add ...
79
  	kmsg->msg_iocb = NULL;
0a384abfa   Jens Axboe   net: abstract out...
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
  	*ptr = msg.msg_iov;
  	*len = msg.msg_iovlen;
  	return 0;
  }
  
  int get_compat_msghdr(struct msghdr *kmsg,
  		      struct compat_msghdr __user *umsg,
  		      struct sockaddr __user **save_addr,
  		      struct iovec **iov)
  {
  	compat_uptr_t ptr;
  	compat_size_t len;
  	ssize_t err;
  
  	err = __get_compat_msghdr(kmsg, umsg, save_addr, &ptr, &len);
  	if (err)
  		return err;
0345f9313   tadeusz.struk@intel.com   net: socket: add ...
97

89cd35c58   Christoph Hellwig   iov_iter: transpa...
98
99
  	err = import_iovec(save_addr ? READ : WRITE, compat_ptr(ptr), len,
  			   UIO_FASTIOV, iov, &kmsg->msg_iter);
87e5e6dab   Jens Axboe   uio: make import_...
100
  	return err < 0 ? err : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
102
103
104
105
106
  }
  
  /* Bleech... */
  #define CMSG_COMPAT_ALIGN(len)	ALIGN((len), sizeof(s32))
  
  #define CMSG_COMPAT_DATA(cmsg)				\
1ff8cebf4   yuan linyu   scm: remove use C...
107
  	((void __user *)((char __user *)(cmsg) + sizeof(struct compat_cmsghdr)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
  #define CMSG_COMPAT_SPACE(len)				\
1ff8cebf4   yuan linyu   scm: remove use C...
109
  	(sizeof(struct compat_cmsghdr) + CMSG_COMPAT_ALIGN(len))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
  #define CMSG_COMPAT_LEN(len)				\
1ff8cebf4   yuan linyu   scm: remove use C...
111
  	(sizeof(struct compat_cmsghdr) + (len))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
113
114
115
116
117
118
119
120
121
  
  #define CMSG_COMPAT_FIRSTHDR(msg)			\
  	(((msg)->msg_controllen) >= sizeof(struct compat_cmsghdr) ?	\
  	 (struct compat_cmsghdr __user *)((msg)->msg_control) :		\
  	 (struct compat_cmsghdr __user *)NULL)
  
  #define CMSG_COMPAT_OK(ucmlen, ucmsg, mhdr) \
  	((ucmlen) >= sizeof(struct compat_cmsghdr) && \
  	 (ucmlen) <= (unsigned long) \
  	 ((mhdr)->msg_controllen - \
1f466e1f1   Christoph Hellwig   net: cleanly hand...
122
  	  ((char __user *)(ucmsg) - (char __user *)(mhdr)->msg_control_user)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
  
  static inline struct compat_cmsghdr __user *cmsg_compat_nxthdr(struct msghdr *msg,
  		struct compat_cmsghdr __user *cmsg, int cmsg_len)
  {
  	char __user *ptr = (char __user *)cmsg + CMSG_COMPAT_ALIGN(cmsg_len);
  	if ((unsigned long)(ptr + 1 - (char __user *)msg->msg_control) >
  			msg->msg_controllen)
  		return NULL;
  	return (struct compat_cmsghdr __user *)ptr;
  }
  
  /* 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
   */
8920e8f94   Al Viro   [PATCH] Fix 32bit...
138
  int cmsghdr_from_user_compat_to_kern(struct msghdr *kmsg, struct sock *sk,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
140
141
142
143
144
  			       unsigned char *stackbuf, int stackbuf_size)
  {
  	struct compat_cmsghdr __user *ucmsg;
  	struct cmsghdr *kcmsg, *kcmsg_base;
  	compat_size_t ucmlen;
  	__kernel_size_t kcmlen, tmp;
8920e8f94   Al Viro   [PATCH] Fix 32bit...
145
  	int err = -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146

ac4340fc3   David S. Miller   net: Assert at bu...
147
148
  	BUILD_BUG_ON(sizeof(struct compat_cmsghdr) !=
  		     CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
150
151
  	kcmlen = 0;
  	kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf;
  	ucmsg = CMSG_COMPAT_FIRSTHDR(kmsg);
e71a4783a   Stephen Hemminger   [NET] core: white...
152
153
  	while (ucmsg != NULL) {
  		if (get_user(ucmlen, &ucmsg->cmsg_len))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
155
156
157
158
  			return -EFAULT;
  
  		/* Catch bogons. */
  		if (!CMSG_COMPAT_OK(ucmlen, ucmsg, kmsg))
  			return -EINVAL;
1ff8cebf4   yuan linyu   scm: remove use C...
159
  		tmp = ((ucmlen - sizeof(*ucmsg)) + sizeof(struct cmsghdr));
8920e8f94   Al Viro   [PATCH] Fix 32bit...
160
  		tmp = CMSG_ALIGN(tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
162
163
  		kcmlen += tmp;
  		ucmsg = cmsg_compat_nxthdr(kmsg, ucmsg, ucmlen);
  	}
e71a4783a   Stephen Hemminger   [NET] core: white...
164
  	if (kcmlen == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
166
167
168
169
170
171
  		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.
  	 */
8920e8f94   Al Viro   [PATCH] Fix 32bit...
172
173
174
  	if (kcmlen > stackbuf_size)
  		kcmsg_base = kcmsg = sock_kmalloc(sk, kcmlen, GFP_KERNEL);
  	if (kcmsg == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
176
177
178
179
  		return -ENOBUFS;
  
  	/* Now copy them over neatly. */
  	memset(kcmsg, 0, kcmlen);
  	ucmsg = CMSG_COMPAT_FIRSTHDR(kmsg);
e71a4783a   Stephen Hemminger   [NET] core: white...
180
  	while (ucmsg != NULL) {
547ce4cfb   Al Viro   switch cmsghdr_fr...
181
182
  		struct compat_cmsghdr cmsg;
  		if (copy_from_user(&cmsg, ucmsg, sizeof(cmsg)))
8920e8f94   Al Viro   [PATCH] Fix 32bit...
183
  			goto Efault;
547ce4cfb   Al Viro   switch cmsghdr_fr...
184
  		if (!CMSG_COMPAT_OK(cmsg.cmsg_len, ucmsg, kmsg))
8920e8f94   Al Viro   [PATCH] Fix 32bit...
185
  			goto Einval;
547ce4cfb   Al Viro   switch cmsghdr_fr...
186
  		tmp = ((cmsg.cmsg_len - sizeof(*ucmsg)) + sizeof(struct cmsghdr));
8920e8f94   Al Viro   [PATCH] Fix 32bit...
187
188
  		if ((char *)kcmsg_base + kcmlen - (char *)kcmsg < CMSG_ALIGN(tmp))
  			goto Einval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
  		kcmsg->cmsg_len = tmp;
547ce4cfb   Al Viro   switch cmsghdr_fr...
190
191
  		kcmsg->cmsg_level = cmsg.cmsg_level;
  		kcmsg->cmsg_type = cmsg.cmsg_type;
8920e8f94   Al Viro   [PATCH] Fix 32bit...
192
  		tmp = CMSG_ALIGN(tmp);
547ce4cfb   Al Viro   switch cmsghdr_fr...
193
  		if (copy_from_user(CMSG_DATA(kcmsg),
8920e8f94   Al Viro   [PATCH] Fix 32bit...
194
  				   CMSG_COMPAT_DATA(ucmsg),
547ce4cfb   Al Viro   switch cmsghdr_fr...
195
  				   (cmsg.cmsg_len - sizeof(*ucmsg))))
8920e8f94   Al Viro   [PATCH] Fix 32bit...
196
  			goto Efault;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197
198
  
  		/* Advance. */
8920e8f94   Al Viro   [PATCH] Fix 32bit...
199
  		kcmsg = (struct cmsghdr *)((char *)kcmsg + tmp);
181964e61   Al Viro   fix a braino in c...
200
  		ucmsg = cmsg_compat_nxthdr(kmsg, ucmsg, cmsg.cmsg_len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
  	}
c2a64bb9f   Meng Xu   net: compat: asse...
202
203
204
205
206
207
  	/*
  	 * check the length of messages copied in is the same as the
  	 * what we get from the first loop
  	 */
  	if ((char *)kcmsg - (char *)kcmsg_base != kcmlen)
  		goto Einval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
210
211
  	/* Ok, looks like we made it.  Hook it up and return success. */
  	kmsg->msg_control = kcmsg_base;
  	kmsg->msg_controllen = kcmlen;
  	return 0;
8920e8f94   Al Viro   [PATCH] Fix 32bit...
212
213
214
215
216
217
  Einval:
  	err = -EINVAL;
  Efault:
  	if (kcmsg_base != (struct cmsghdr *)stackbuf)
  		sock_kfree_s(sk, kcmsg_base, kcmlen);
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
219
220
221
  }
  
  int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *data)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
223
  	struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control;
  	struct compat_cmsghdr cmhdr;
13c6ee2a9   Deepa Dinamani   socket: Use old_t...
224
225
  	struct old_timeval32 ctv;
  	struct old_timespec32 cts[3];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
  	int cmlen;
e71a4783a   Stephen Hemminger   [NET] core: white...
227
  	if (cm == NULL || kmsg->msg_controllen < sizeof(*cm)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228
229
230
  		kmsg->msg_flags |= MSG_CTRUNC;
  		return 0; /* XXX: return error? check spec. */
  	}
ee4fa23c4   H. J. Lu   compat: Use COMPA...
231
  	if (!COMPAT_USE_64BIT_TIME) {
7f1bc6e95   Deepa Dinamani   sockopt: Rename S...
232
  		if (level == SOL_SOCKET && type == SO_TIMESTAMP_OLD) {
13c6ee2a9   Deepa Dinamani   socket: Use old_t...
233
  			struct __kernel_old_timeval *tv = (struct __kernel_old_timeval *)data;
ee4fa23c4   H. J. Lu   compat: Use COMPA...
234
235
236
237
238
239
  			ctv.tv_sec = tv->tv_sec;
  			ctv.tv_usec = tv->tv_usec;
  			data = &ctv;
  			len = sizeof(ctv);
  		}
  		if (level == SOL_SOCKET &&
7f1bc6e95   Deepa Dinamani   sockopt: Rename S...
240
241
  		    (type == SO_TIMESTAMPNS_OLD || type == SO_TIMESTAMPING_OLD)) {
  			int count = type == SO_TIMESTAMPNS_OLD ? 1 : 3;
ee4fa23c4   H. J. Lu   compat: Use COMPA...
242
  			int i;
df1b4ba9d   Arnd Bergmann   y2038: socket: us...
243
  			struct __kernel_old_timespec *ts = data;
ee4fa23c4   H. J. Lu   compat: Use COMPA...
244
245
246
247
248
249
  			for (i = 0; i < count; i++) {
  				cts[i].tv_sec = ts[i].tv_sec;
  				cts[i].tv_nsec = ts[i].tv_nsec;
  			}
  			data = &cts;
  			len = sizeof(cts[0]) * count;
20d494735   Patrick Ohly   net: socket infra...
250
  		}
4768fbcbc   YOSHIFUJI Hideaki   [NET]: Fix whites...
251
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
  	cmlen = CMSG_COMPAT_LEN(len);
e71a4783a   Stephen Hemminger   [NET] core: white...
253
  	if (kmsg->msg_controllen < cmlen) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
255
256
257
258
259
  		kmsg->msg_flags |= MSG_CTRUNC;
  		cmlen = kmsg->msg_controllen;
  	}
  	cmhdr.cmsg_level = level;
  	cmhdr.cmsg_type = type;
  	cmhdr.cmsg_len = cmlen;
e71a4783a   Stephen Hemminger   [NET] core: white...
260
  	if (copy_to_user(cm, &cmhdr, sizeof cmhdr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
  		return -EFAULT;
e71a4783a   Stephen Hemminger   [NET] core: white...
262
  	if (copy_to_user(CMSG_COMPAT_DATA(cm), data, cmlen - sizeof(struct compat_cmsghdr)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
264
  		return -EFAULT;
  	cmlen = CMSG_COMPAT_SPACE(len);
1ac70e7ad   Wei Yongjun   [NET]: Fix functi...
265
266
  	if (kmsg->msg_controllen < cmlen)
  		cmlen = kmsg->msg_controllen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267
268
269
270
  	kmsg->msg_control += cmlen;
  	kmsg->msg_controllen -= cmlen;
  	return 0;
  }
c0029de50   Kees Cook   net/scm: Regulari...
271
  static int scm_max_fds_compat(struct msghdr *msg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
  {
c0029de50   Kees Cook   net/scm: Regulari...
273
274
275
276
  	if (msg->msg_controllen <= sizeof(struct compat_cmsghdr))
  		return 0;
  	return (msg->msg_controllen - sizeof(struct compat_cmsghdr)) / sizeof(int);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277

c0029de50   Kees Cook   net/scm: Regulari...
278
279
280
281
282
283
  void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm)
  {
  	struct compat_cmsghdr __user *cm =
  		(struct compat_cmsghdr __user *)msg->msg_control;
  	unsigned int o_flags = (msg->msg_flags & MSG_CMSG_CLOEXEC) ? O_CLOEXEC : 0;
  	int fdmax = min_t(int, scm_max_fds_compat(msg), scm->fp->count);
16b89f695   Kees Cook   net/scm: Fix typo...
284
  	int __user *cmsg_data = CMSG_COMPAT_DATA(cm);
c0029de50   Kees Cook   net/scm: Regulari...
285
  	int err = 0, i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286

c0029de50   Kees Cook   net/scm: Regulari...
287
  	for (i = 0; i < fdmax; i++) {
665906104   Kees Cook   fs: Move __scm_in...
288
  		err = receive_fd_user(scm->fp->fp[i], cmsg_data + i, o_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
290
  		if (err < 0)
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
292
293
294
  	}
  
  	if (i > 0) {
  		int cmlen = CMSG_COMPAT_LEN(i * sizeof(int));
c0029de50   Kees Cook   net/scm: Regulari...
295

effee6a00   Miklos Szeredi   [NET]: File descr...
296
  		err = put_user(SOL_SOCKET, &cm->cmsg_level);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
298
299
300
301
302
  		if (!err)
  			err = put_user(SCM_RIGHTS, &cm->cmsg_type);
  		if (!err)
  			err = put_user(cmlen, &cm->cmsg_len);
  		if (!err) {
  			cmlen = CMSG_COMPAT_SPACE(i * sizeof(int));
c0029de50   Kees Cook   net/scm: Regulari...
303
304
305
306
  			if (msg->msg_controllen < cmlen)
  				cmlen = msg->msg_controllen;
  			msg->msg_control += cmlen;
  			msg->msg_controllen -= cmlen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
308
  		}
  	}
c0029de50   Kees Cook   net/scm: Regulari...
309
310
311
  
  	if (i < scm->fp->count || (scm->fp->count && fdmax <= 0))
  		msg->msg_flags |= MSG_CTRUNC;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
313
  
  	/*
c0029de50   Kees Cook   net/scm: Regulari...
314
315
  	 * All of the files that fit in the message have had their usage counts
  	 * incremented, so we just free the list.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
317
318
  	 */
  	__scm_destroy(scm);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
320
  /* Argument list sizes for compat_sys_socketcall */
  #define AL(x) ((x) * sizeof(u32))
228e548e6   Anton Blanchard   net: Add sendmmsg...
321
  static unsigned char nas[21] = {
c6d409cfd   Eric Dumazet   From abbffa2aa9bd...
322
323
324
  	AL(0), AL(3), AL(3), AL(3), AL(2), AL(3),
  	AL(3), AL(3), AL(4), AL(4), AL(4), AL(6),
  	AL(6), AL(2), AL(5), AL(5), AL(3), AL(3),
228e548e6   Anton Blanchard   net: Add sendmmsg...
325
  	AL(4), AL(5), AL(4)
c6d409cfd   Eric Dumazet   From abbffa2aa9bd...
326
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
  #undef AL
6df354653   Dominik Brodowski   net: socket: add ...
328
329
330
  static inline long __compat_sys_sendmsg(int fd,
  					struct compat_msghdr __user *msg,
  					unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
  {
e1834a329   Dominik Brodowski   net: socket: move...
332
333
  	return __sys_sendmsg(fd, (struct user_msghdr __user *)msg,
  			     flags | MSG_CMSG_COMPAT, false);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
  }
6df354653   Dominik Brodowski   net: socket: add ...
335
336
337
338
339
340
341
342
343
  COMPAT_SYSCALL_DEFINE3(sendmsg, int, fd, struct compat_msghdr __user *, msg,
  		       unsigned int, flags)
  {
  	return __compat_sys_sendmsg(fd, msg, flags);
  }
  
  static inline long __compat_sys_sendmmsg(int fd,
  					 struct compat_mmsghdr __user *mmsg,
  					 unsigned int vlen, unsigned int flags)
228e548e6   Anton Blanchard   net: Add sendmmsg...
344
345
  {
  	return __sys_sendmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
e1834a329   Dominik Brodowski   net: socket: move...
346
  			      flags | MSG_CMSG_COMPAT, false);
228e548e6   Anton Blanchard   net: Add sendmmsg...
347
  }
6df354653   Dominik Brodowski   net: socket: add ...
348
349
350
351
352
353
354
355
356
  COMPAT_SYSCALL_DEFINE4(sendmmsg, int, fd, struct compat_mmsghdr __user *, mmsg,
  		       unsigned int, vlen, unsigned int, flags)
  {
  	return __compat_sys_sendmmsg(fd, mmsg, vlen, flags);
  }
  
  static inline long __compat_sys_recvmsg(int fd,
  					struct compat_msghdr __user *msg,
  					unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
  {
e1834a329   Dominik Brodowski   net: socket: move...
358
359
  	return __sys_recvmsg(fd, (struct user_msghdr __user *)msg,
  			     flags | MSG_CMSG_COMPAT, false);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
  }
6df354653   Dominik Brodowski   net: socket: add ...
361
362
363
364
365
  COMPAT_SYSCALL_DEFINE3(recvmsg, int, fd, struct compat_msghdr __user *, msg,
  		       unsigned int, flags)
  {
  	return __compat_sys_recvmsg(fd, msg, flags);
  }
fd4e82f5b   Dominik Brodowski   net: socket: add ...
366
367
368
369
370
371
372
373
  static inline long __compat_sys_recvfrom(int fd, void __user *buf,
  					 compat_size_t len, unsigned int flags,
  					 struct sockaddr __user *addr,
  					 int __user *addrlen)
  {
  	return __sys_recvfrom(fd, buf, len, flags | MSG_CMSG_COMPAT, addr,
  			      addrlen);
  }
3a49a0f71   Heiko Carstens   net/compat: conve...
374
  COMPAT_SYSCALL_DEFINE4(recv, int, fd, void __user *, buf, compat_size_t, len, unsigned int, flags)
1dacc76d0   Johannes Berg   net/compat/wext: ...
375
  {
fd4e82f5b   Dominik Brodowski   net: socket: add ...
376
  	return __compat_sys_recvfrom(fd, buf, len, flags, NULL, NULL);
1dacc76d0   Johannes Berg   net/compat/wext: ...
377
  }
3a49a0f71   Heiko Carstens   net/compat: conve...
378
379
380
  COMPAT_SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, buf, compat_size_t, len,
  		       unsigned int, flags, struct sockaddr __user *, addr,
  		       int __user *, addrlen)
1dacc76d0   Johannes Berg   net/compat/wext: ...
381
  {
fd4e82f5b   Dominik Brodowski   net: socket: add ...
382
  	return __compat_sys_recvfrom(fd, buf, len, flags, addr, addrlen);
1dacc76d0   Johannes Berg   net/compat/wext: ...
383
  }
e11d4284e   Arnd Bergmann   y2038: socket: Ad...
384
385
386
  COMPAT_SYSCALL_DEFINE5(recvmmsg_time64, int, fd, struct compat_mmsghdr __user *, mmsg,
  		       unsigned int, vlen, unsigned int, flags,
  		       struct __kernel_timespec __user *, timeout)
a2e272554   Arnaldo Carvalho de Melo   net: Introduce re...
387
  {
e11d4284e   Arnd Bergmann   y2038: socket: Ad...
388
389
  	return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
  			      flags | MSG_CMSG_COMPAT, timeout, NULL);
a2e272554   Arnaldo Carvalho de Melo   net: Introduce re...
390
  }
e11d4284e   Arnd Bergmann   y2038: socket: Ad...
391
  #ifdef CONFIG_COMPAT_32BIT_TIME
8dabe7245   Arnd Bergmann   y2038: syscalls: ...
392
  COMPAT_SYSCALL_DEFINE5(recvmmsg_time32, int, fd, struct compat_mmsghdr __user *, mmsg,
157b334aa   Dominik Brodowski   net: socket: add ...
393
  		       unsigned int, vlen, unsigned int, flags,
9afc5eee6   Arnd Bergmann   y2038: globally r...
394
  		       struct old_timespec32 __user *, timeout)
157b334aa   Dominik Brodowski   net: socket: add ...
395
  {
e11d4284e   Arnd Bergmann   y2038: socket: Ad...
396
397
  	return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
  			      flags | MSG_CMSG_COMPAT, NULL, timeout);
157b334aa   Dominik Brodowski   net: socket: add ...
398
  }
e11d4284e   Arnd Bergmann   y2038: socket: Ad...
399
  #endif
157b334aa   Dominik Brodowski   net: socket: add ...
400

361d93c46   Heiko Carstens   net/compat: conve...
401
  COMPAT_SYSCALL_DEFINE2(socketcall, int, call, u32 __user *, args)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402
  {
62bc306e2   Richard Guy Briggs   audit: log 32-bit...
403
404
  	u32 a[AUDITSC_ARGS];
  	unsigned int len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
  	u32 a0, a1;
62bc306e2   Richard Guy Briggs   audit: log 32-bit...
406
  	int ret;
4768fbcbc   YOSHIFUJI Hideaki   [NET]: Fix whites...
407

228e548e6   Anton Blanchard   net: Add sendmmsg...
408
  	if (call < SYS_SOCKET || call > SYS_SENDMMSG)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
  		return -EINVAL;
62bc306e2   Richard Guy Briggs   audit: log 32-bit...
410
411
412
413
414
  	len = nas[call];
  	if (len > sizeof(a))
  		return -EINVAL;
  
  	if (copy_from_user(a, args, len))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
  		return -EFAULT;
62bc306e2   Richard Guy Briggs   audit: log 32-bit...
416
417
418
419
  
  	ret = audit_socketcall_compat(len / sizeof(a[0]), a);
  	if (ret)
  		return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
421
  	a0 = a[0];
  	a1 = a[1];
4768fbcbc   YOSHIFUJI Hideaki   [NET]: Fix whites...
422

e71a4783a   Stephen Hemminger   [NET] core: white...
423
  	switch (call) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
  	case SYS_SOCKET:
9d6a15c3f   Dominik Brodowski   net: socket: add ...
425
  		ret = __sys_socket(a0, a1, a[2]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426
427
  		break;
  	case SYS_BIND:
a87d35d87   Dominik Brodowski   net: socket: add ...
428
  		ret = __sys_bind(a0, compat_ptr(a1), a[2]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
430
  		break;
  	case SYS_CONNECT:
1387c2c2f   Dominik Brodowski   net: socket: add ...
431
  		ret = __sys_connect(a0, compat_ptr(a1), a[2]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
432
433
  		break;
  	case SYS_LISTEN:
25e290eed   Dominik Brodowski   net: socket: add ...
434
  		ret = __sys_listen(a0, a1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435
436
  		break;
  	case SYS_ACCEPT:
4541e8056   Dominik Brodowski   net: socket: add ...
437
  		ret = __sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
438
439
  		break;
  	case SYS_GETSOCKNAME:
8882a107b   Dominik Brodowski   net: socket: add ...
440
  		ret = __sys_getsockname(a0, compat_ptr(a1), compat_ptr(a[2]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
441
442
  		break;
  	case SYS_GETPEERNAME:
b21c8f838   Dominik Brodowski   net: socket: add ...
443
  		ret = __sys_getpeername(a0, compat_ptr(a1), compat_ptr(a[2]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
444
445
  		break;
  	case SYS_SOCKETPAIR:
6debc8d83   Dominik Brodowski   net: socket: add ...
446
  		ret = __sys_socketpair(a0, a1, a[2], compat_ptr(a[3]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
447
448
  		break;
  	case SYS_SEND:
f3bf896b1   Dominik Brodowski   net: socket: repl...
449
  		ret = __sys_sendto(a0, compat_ptr(a1), a[2], a[3], NULL, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
450
451
  		break;
  	case SYS_SENDTO:
211b634b7   Dominik Brodowski   net: socket: add ...
452
453
  		ret = __sys_sendto(a0, compat_ptr(a1), a[2], a[3],
  				   compat_ptr(a[4]), a[5]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454
455
  		break;
  	case SYS_RECV:
fd4e82f5b   Dominik Brodowski   net: socket: add ...
456
457
  		ret = __compat_sys_recvfrom(a0, compat_ptr(a1), a[2], a[3],
  					    NULL, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
459
  		break;
  	case SYS_RECVFROM:
fd4e82f5b   Dominik Brodowski   net: socket: add ...
460
461
462
  		ret = __compat_sys_recvfrom(a0, compat_ptr(a1), a[2], a[3],
  					    compat_ptr(a[4]),
  					    compat_ptr(a[5]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
463
464
  		break;
  	case SYS_SHUTDOWN:
005a1aeac   Dominik Brodowski   net: socket: add ...
465
  		ret = __sys_shutdown(a0, a1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
466
467
  		break;
  	case SYS_SETSOCKOPT:
55db9c0e8   Christoph Hellwig   net: remove compa...
468
  		ret = __sys_setsockopt(a0, a1, a[2], compat_ptr(a[3]), a[4]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
470
  		break;
  	case SYS_GETSOCKOPT:
55db9c0e8   Christoph Hellwig   net: remove compa...
471
472
  		ret = __sys_getsockopt(a0, a1, a[2], compat_ptr(a[3]),
  				       compat_ptr(a[4]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
473
474
  		break;
  	case SYS_SENDMSG:
6df354653   Dominik Brodowski   net: socket: add ...
475
  		ret = __compat_sys_sendmsg(a0, compat_ptr(a1), a[2]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
  		break;
228e548e6   Anton Blanchard   net: Add sendmmsg...
477
  	case SYS_SENDMMSG:
6df354653   Dominik Brodowski   net: socket: add ...
478
  		ret = __compat_sys_sendmmsg(a0, compat_ptr(a1), a[2], a[3]);
228e548e6   Anton Blanchard   net: Add sendmmsg...
479
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
480
  	case SYS_RECVMSG:
6df354653   Dominik Brodowski   net: socket: add ...
481
  		ret = __compat_sys_recvmsg(a0, compat_ptr(a1), a[2]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
  		break;
a2e272554   Arnaldo Carvalho de Melo   net: Introduce re...
483
  	case SYS_RECVMMSG:
e11d4284e   Arnd Bergmann   y2038: socket: Ad...
484
485
486
  		ret = __sys_recvmmsg(a0, compat_ptr(a1), a[2],
  				     a[3] | MSG_CMSG_COMPAT, NULL,
  				     compat_ptr(a[4]));
a2e272554   Arnaldo Carvalho de Melo   net: Introduce re...
487
  		break;
de11defeb   Ulrich Drepper   reintroduce accept4
488
  	case SYS_ACCEPT4:
4541e8056   Dominik Brodowski   net: socket: add ...
489
  		ret = __sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), a[3]);
aaca0bdca   Ulrich Drepper   flag parameters: ...
490
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
492
493
494
495
496
  	default:
  		ret = -EINVAL;
  		break;
  	}
  	return ret;
  }