1 /* Copyright (C) 1992-2022 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3 
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8 
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <https://www.gnu.org/licenses/>.  */
17 
18 #include <errno.h>
19 #include <sys/ioctl.h>
20 #include <hurd.h>
21 #include <hurd/fd.h>
22 #include <hurd/signal.h>
23 #include <stdarg.h>
24 #include <mach/notify.h>
25 #include <assert.h>
26 #include <string.h>
27 #include <stdint.h>
28 #include <hurd/ioctl.h>
29 #include <mach/mig_support.h>
30 #include <sysdep-cancel.h>
31 
32 #include <hurd/ioctls.defs>
33 
34 #define typesize(type)	(1 << (type))
35 
36 
37 /* Perform the I/O control operation specified by REQUEST on FD.
38    The actual type and use of ARG and the return value depend on REQUEST.  */
39 int
__ioctl(int fd,unsigned long int request,...)40 __ioctl (int fd, unsigned long int request, ...)
41 {
42 #ifdef MACH_MSG_TYPE_CHAR
43   /* Map individual type fields to Mach IPC types.  */
44   static const int mach_types[] =
45     { MACH_MSG_TYPE_CHAR, MACH_MSG_TYPE_INTEGER_16, MACH_MSG_TYPE_INTEGER_32,
46       MACH_MSG_TYPE_INTEGER_64 };
47 #define io2mach_type(count, type) \
48   ((mach_msg_type_t) { mach_types[type], typesize (type) * 8, count, 1, 0, 0 })
49 #endif
50 
51   /* Extract the type information encoded in the request.  */
52   unsigned int type = _IOC_TYPE (request);
53 
54   /* Message buffer.  */
55 #define msg_align(x) \
56   (((x) + sizeof (mach_msg_type_t) - 1) & ~(sizeof (mach_msg_type_t) - 1))
57   struct
58   {
59 #ifdef MACH_MSG_TYPE_BIT
60     union
61     {
62       mig_reply_header_t header;
63       struct
64       {
65 	mach_msg_header_t	Head;
66 	int			RetCodeType;
67 	kern_return_t		RetCode;
68       } header_typecheck;
69     };
70     char data[3 * sizeof (mach_msg_type_t)
71 	      + msg_align (_IOT_COUNT0 (type) * typesize (_IOT_TYPE0 (type)))
72 	      + msg_align (_IOT_COUNT1 (type) * typesize (_IOT_TYPE1 (type)))
73 	      + _IOT_COUNT2 (type) * typesize (_IOT_TYPE2 (type))];
74 #else  /* Untyped Mach IPC format.  */
75     mig_reply_error_t header;
76     char data[_IOT_COUNT0 (type) * typesize (_IOT_TYPE0 (type))
77 	      + _IOT_COUNT1 (type) * typesize (_IOT_TYPE1 (type))
78 	      + _IOT_COUNT2 (type) * typesize (_IOT_TYPE2 (type))];
79     mach_msg_trailer_t trailer;
80 #endif
81   } msg;
82   mach_msg_header_t *const m = &msg.header.Head;
83   mach_msg_id_t msgid;
84   unsigned int reply_size;
85 #ifdef MACH_MSG_TYPE_BIT
86   mach_msg_type_t *t;
87 #else
88   void *p;
89 #endif
90 
91   void *arg = NULL;
92 
93   error_t err;
94 
95   /* Send the RPC already packed up in MSG to IOPORT
96      and decode the return value.  */
97   error_t send_rpc (io_t ioport)
98     {
99       error_t err;
100 #ifdef MACH_MSG_TYPE_BIT
101       mach_msg_type_t *t = &msg.header.RetCodeType;
102 #else
103       void *p = &msg.header.RetCode;
104 #endif
105 
106       /* Marshal the request arguments into the message buffer.
107 	 We must redo this work each time we retry the RPC after a SIGTTOU,
108 	 because the reply message containing the EBACKGROUND error code
109 	 clobbers the same message buffer also used for the request.  */
110 
111       if (_IOC_INOUT (request) & IOC_IN)
112 	{
113 	  /* We don't want to advance ARG since it will be used to copy out
114 	     too if IOC_OUT is also set.  */
115 	  void *argptr = arg;
116 	  int zero = 0;
117 
118 	  if (request == TIOCFLUSH && !argptr)
119 	    argptr = &zero;
120 
121 	  /* Pack an argument into the message buffer.  */
122 	  void in (unsigned int count, enum __ioctl_datum type)
123 	    {
124 	      if (count > 0)
125 		{
126 		  const size_t len = count * typesize ((unsigned int) type);
127 #ifdef MACH_MSG_TYPE_BIT
128 		  void *p = &t[1];
129 		  *t = io2mach_type (count, type);
130 		  p = __mempcpy (p, argptr, len);
131 		  p = (void *) (((uintptr_t) p + sizeof (*t) - 1)
132 				& ~(sizeof (*t) - 1));
133 		  t = p;
134 #else
135 		  p = __mempcpy (p, argptr, len);
136 #endif
137 		  argptr += len;
138 		}
139 	    }
140 
141 	  /* Pack the argument data.  */
142 	  in (_IOT_COUNT0 (type), _IOT_TYPE0 (type));
143 	  in (_IOT_COUNT1 (type), _IOT_TYPE1 (type));
144 	  in (_IOT_COUNT2 (type), _IOT_TYPE2 (type));
145 	}
146       else if (_IOC_INOUT (request) == IOC_VOID && _IOT_COUNT0 (type) != 0)
147 	{
148 	  /* The RPC takes a single integer_t argument.
149 	     Rather than pointing to the value, ARG is the value itself.  */
150 #ifdef MACH_MSG_TYPE_BIT
151 	  *t++ = io2mach_type (1, _IOTS (integer_t));
152 	  *(integer_t *) t = (integer_t) arg;
153 	  t = (void *) t + sizeof (integer_t);
154 #else
155 	  *(integer_t *) p = (integer_t) arg;
156 	  p = (void *) p + sizeof (integer_t);
157 #endif
158 	}
159 
160       memset (m, 0, sizeof *m);	/* Clear unused fields.  */
161       m->msgh_size = (
162 #ifdef MACH_MSG_TYPE_BIT
163 		      (char *) t
164 #else
165 		      (char *) p
166 #endif
167 		      - (char *) &msg);
168       m->msgh_remote_port = ioport;
169       m->msgh_local_port = __mig_get_reply_port ();
170       m->msgh_id = msgid;
171       m->msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND,
172 				     MACH_MSG_TYPE_MAKE_SEND_ONCE);
173       err = _hurd_intr_rpc_mach_msg (m, MACH_SEND_MSG|MACH_RCV_MSG,
174 				     m->msgh_size, sizeof (msg),
175 				     m->msgh_local_port,
176 				     MACH_MSG_TIMEOUT_NONE,
177 				     MACH_PORT_NULL);
178       switch (err)
179 	{
180 	case MACH_MSG_SUCCESS:
181 	  break;
182 	case MACH_SEND_INVALID_REPLY:
183 	case MACH_RCV_INVALID_NAME:
184 	  __mig_dealloc_reply_port (m->msgh_local_port);
185 	  /* Fall through.  */
186 	default:
187 	  return err;
188 	}
189 
190       if ((m->msgh_bits & MACH_MSGH_BITS_COMPLEX))
191 	{
192 	  /* Allow no ports or VM.  */
193 	  __mach_msg_destroy (m);
194 	  /* Want to return a different error below for a different msgid.  */
195 	  if (m->msgh_id == msgid + 100)
196 	    return MIG_TYPE_ERROR;
197 	}
198 
199       if (m->msgh_id != msgid + 100)
200 	return (m->msgh_id == MACH_NOTIFY_SEND_ONCE
201 		? MIG_SERVER_DIED : MIG_REPLY_MISMATCH);
202 
203       if (m->msgh_size != reply_size
204 	  && m->msgh_size != sizeof msg.header)
205 	return MIG_TYPE_ERROR;
206 
207 #ifdef MACH_MSG_TYPE_BIT
208       if (msg.header_typecheck.RetCodeType
209 	  != ((union { mach_msg_type_t t; int i; })
210 	    { t: io2mach_type (1, _IOTS (msg.header.RetCode)) }).i)
211 	return MIG_TYPE_ERROR;
212 #endif
213       return msg.header.RetCode;
214     }
215 
216   if (_IOT_COUNT0 (type) != 0)
217     {
218       /* Data need either be sent, received, or even both.  */
219       va_list ap;
220 
221       va_start (ap, request);
222       arg = va_arg (ap, void *);
223       va_end (ap);
224     }
225 
226   {
227     /* Check for a registered handler for REQUEST.  */
228     ioctl_handler_t handler = _hurd_lookup_ioctl_handler (request);
229     if (handler)
230       {
231 	/* This handler groks REQUEST.  Se lo puntamonos.  */
232 	int save = errno;
233 	int result = (*handler) (fd, request, arg);
234 	if (result != -1 || errno != ENOTTY)
235 	  return result;
236 
237 	/* The handler doesn't really grok this one.
238 	   Try the normal RPC translation.  */
239 	errno = save;
240       }
241   }
242 
243   /* Compute the Mach message ID for the RPC from the group and command
244      parts of the ioctl request.  */
245   msgid = IOC_MSGID (request);
246 
247   /* Compute the expected size of the reply.  There is a standard header
248      consisting of the message header and the reply code.  Then, for out
249      and in/out ioctls, there come the data with their type headers.  */
250   reply_size = sizeof msg.header;
251 
252   if (_IOC_INOUT (request) & IOC_OUT)
253     {
254       inline void figure_reply (unsigned int count, enum __ioctl_datum type)
255 	{
256 	  if (count > 0)
257 	    {
258 #ifdef MACH_MSG_TYPE_BIT
259 	      /* Add the size of the type and data.  */
260 	      reply_size += sizeof (mach_msg_type_t) + typesize (type) * count;
261 	      /* Align it to word size.  */
262 	      reply_size += sizeof (mach_msg_type_t) - 1;
263 	      reply_size &= ~(sizeof (mach_msg_type_t) - 1);
264 #else
265 	      reply_size += typesize (type) * count;
266 #endif
267 	    }
268 	}
269       figure_reply (_IOT_COUNT0 (type), _IOT_TYPE0 (type));
270       figure_reply (_IOT_COUNT1 (type), _IOT_TYPE1 (type));
271       figure_reply (_IOT_COUNT2 (type), _IOT_TYPE2 (type));
272     }
273 
274   /* Marshal the arguments into the request message and make the RPC.
275      This wrapper function handles EBACKGROUND returns, turning them
276      into either SIGTTOU or EIO.  */
277   if (request == TIOCDRAIN)
278     {
279       /* This is a cancellation point.  */
280       int cancel_oldtype = LIBC_CANCEL_ASYNC();
281       err = HURD_DPORT_USE_CANCEL (fd, _hurd_ctty_output (port, ctty, send_rpc));
282       LIBC_CANCEL_RESET (cancel_oldtype);
283     }
284   else
285     err = HURD_DPORT_USE (fd, _hurd_ctty_output (port, ctty, send_rpc));
286 
287 #ifdef MACH_MSG_TYPE_BIT
288   t = (mach_msg_type_t *) msg.data;
289 #else
290   p = (void *) msg.data;
291 #endif
292   switch (err)
293     {
294       /* Unpack the message buffer into the argument location.  */
295       int out (unsigned int count, unsigned int type,
296 	       void *store, void **update)
297 	{
298 	  if (count > 0)
299 	    {
300 	      const size_t len = count * typesize (type);
301 #ifdef MACH_MSG_TYPE_BIT
302 	      union { mach_msg_type_t t; int i; } ipctype;
303 	      ipctype.t = io2mach_type (count, type);
304 	      if (*(int *) t != ipctype.i)
305 		return 1;
306 	      ++t;
307 	      memcpy (store, t, len);
308 	      if (update != NULL)
309 		*update += len;
310 	      t = (void *) (((uintptr_t) t + len + sizeof (*t) - 1)
311 			    & ~(sizeof (*t) - 1));
312 #else
313 	      memcpy (store, p, len);
314 	      p += len;
315 	      if (update != NULL)
316 		*update += len;
317 #endif
318 	    }
319 	  return 0;
320 	}
321 
322     case 0:
323       if (m->msgh_size != reply_size
324 	  || ((_IOC_INOUT (request) & IOC_OUT)
325 	      && (out (_IOT_COUNT0 (type), _IOT_TYPE0 (type), arg, &arg)
326 		  || out (_IOT_COUNT1 (type), _IOT_TYPE1 (type), arg, &arg)
327 		  || out (_IOT_COUNT2 (type), _IOT_TYPE2 (type), arg, &arg))))
328 	return __hurd_fail (MIG_TYPE_ERROR);
329       return 0;
330 
331     case MIG_BAD_ID:
332     case EOPNOTSUPP:
333       /* The server didn't understand the RPC.  */
334       err = ENOTTY;
335       /* Fall through.  */
336     default:
337       return __hurd_fail (err);
338     }
339 }
340 
341 libc_hidden_def (__ioctl)
342 weak_alias (__ioctl, ioctl)
343