xref: /PHP-7.4/ext/sockets/conversions.c (revision 8b4da177)
1 #include "sockaddr_conv.h"
2 #include "conversions.h"
3 #include "sendrecvmsg.h" /* for ancillary registry */
4 #ifdef PHP_WIN32
5 # include "windows_common.h"
6 #endif
7 
8 #include <Zend/zend_llist.h>
9 #include <zend_smart_str.h>
10 
11 #ifndef PHP_WIN32
12 # include <sys/types.h>
13 # include <sys/socket.h>
14 # include <arpa/inet.h>
15 # include <netinet/in.h>
16 # include <sys/un.h>
17 # include <sys/ioctl.h>
18 # include <net/if.h>
19 #else
20 # include <win32/php_stdint.h>
21 #endif
22 
23 #include <limits.h>
24 #include <stdarg.h>
25 #include <stddef.h>
26 
27 #ifdef PHP_WIN32
28 typedef unsigned short sa_family_t;
29 # define msghdr			_WSAMSG
30 /*
31 struct _WSAMSG {
32     LPSOCKADDR       name;				//void *msg_name
33     INT              namelen;			//socklen_t msg_namelen
34     LPWSABUF         lpBuffers;			//struct iovec *msg_iov
35     ULONG            dwBufferCount;		//size_t msg_iovlen
36     WSABUF           Control;			//void *msg_control, size_t msg_controllen
37     DWORD            dwFlags;			//int msg_flags
38 }
39 struct __WSABUF {
40   u_long			len;				//size_t iov_len (2nd member)
41   char FAR			*buf;				//void *iov_base (1st member)
42 }
43 struct _WSACMSGHDR {
44   UINT        cmsg_len;					//socklen_t cmsg_len
45   INT         cmsg_level;				//int       cmsg_level
46   INT         cmsg_type;				//int       cmsg_type;
47   followed by UCHAR cmsg_data[]
48 }
49 */
50 # define msg_name		name
51 # define msg_namelen	namelen
52 # define msg_iov		lpBuffers
53 # define msg_iovlen		dwBufferCount
54 # define msg_control	Control.buf
55 # define msg_controllen	Control.len
56 # define msg_flags		dwFlags
57 # define iov_base		buf
58 # define iov_len		len
59 
60 # define cmsghdr		_WSACMSGHDR
61 # ifdef CMSG_DATA
62 #  undef CMSG_DATA
63 # endif
64 # define CMSG_DATA		WSA_CMSG_DATA
65 #endif
66 
67 #define MAX_USER_BUFF_SIZE ((size_t)(100*1024*1024))
68 #define DEFAULT_BUFF_SIZE 8192
69 
70 struct _ser_context {
71 	HashTable		params; /* stores pointers; has to be first */
72 	struct err_s	err;
73 	zend_llist		keys,
74 	/* common part to res_context ends here */
75 					allocations;
76 	php_socket		*sock;
77 };
78 struct _res_context {
79 	HashTable		params; /* stores pointers; has to be first */
80 	struct err_s	err;
81 	zend_llist		keys;
82 };
83 
84 typedef struct {
85 	/* zval info */
86 	const char *name;
87 	unsigned name_size;
88 	int required;
89 
90 	/* structure info */
91 	size_t field_offset; /* 0 to pass full structure, e.g. when more than
92 							one field is to be changed; in that case the
93 							callbacks need to know the name of the fields */
94 
95 	/* callbacks */
96 	from_zval_write_field *from_zval;
97 	to_zval_read_field *to_zval;
98 } field_descriptor;
99 
100 #define KEY_FILL_SOCKADDR "fill_sockaddr"
101 #define KEY_RECVMSG_RET   "recvmsg_ret"
102 #define KEY_CMSG_LEN	  "cmsg_len"
103 
104 const struct key_value empty_key_value_list[] = {{0}};
105 
106 /* PARAMETERS */
param_get_bool(void * ctx,const char * key,int def)107 static int param_get_bool(void *ctx, const char *key, int def)
108 {
109 	int *elem;
110 	if ((elem = zend_hash_str_find_ptr(ctx, key, strlen(key))) != NULL) {
111 		return *elem;
112 	} else {
113 		return def;
114 	}
115 }
116 
117 /* MEMORY */
accounted_emalloc(size_t alloc_size,ser_context * ctx)118 static inline void *accounted_emalloc(size_t alloc_size, ser_context *ctx)
119 {
120 	void *ret = emalloc(alloc_size);
121 	zend_llist_add_element(&ctx->allocations, &ret);
122 	return ret;
123 }
accounted_ecalloc(size_t nmemb,size_t alloc_size,ser_context * ctx)124 static inline void *accounted_ecalloc(size_t nmemb, size_t alloc_size, ser_context *ctx)
125 {
126 	void *ret = ecalloc(nmemb, alloc_size);
127 	zend_llist_add_element(&ctx->allocations, &ret);
128 	return ret;
129 }
accounted_safe_ecalloc(size_t nmemb,size_t alloc_size,size_t offset,ser_context * ctx)130 static inline void *accounted_safe_ecalloc(size_t nmemb, size_t alloc_size, size_t offset, ser_context *ctx)
131 {
132 	void *ret = safe_emalloc(nmemb, alloc_size, offset);
133 	memset(ret, '\0', nmemb * alloc_size + offset);
134 	zend_llist_add_element(&ctx->allocations, &ret);
135 	return ret;
136 }
137 
138 /* ERRORS */
do_from_to_zval_err(struct err_s * err,zend_llist * keys,const char * what_conv,const char * fmt,va_list ap)139 static void do_from_to_zval_err(struct err_s *err,
140 								zend_llist *keys,
141 								const char *what_conv,
142 								const char *fmt,
143 								va_list ap)
144 {
145 	smart_str			path = {0};
146 	const char			**node;
147 	char				*user_msg;
148 	int					user_msg_size;
149 	zend_llist_position	pos;
150 
151 	if (err->has_error) {
152 		return;
153 	}
154 
155 	for (node = zend_llist_get_first_ex(keys, &pos);
156 			node != NULL;
157 			node = zend_llist_get_next_ex(keys, &pos)) {
158 		smart_str_appends(&path, *node);
159 		smart_str_appends(&path, " > ");
160 	}
161 
162 	if (path.s && ZSTR_LEN(path.s) > 3) {
163 		ZSTR_LEN(path.s) -= 3;
164 	}
165 	smart_str_0(&path);
166 
167 	user_msg_size = vspprintf(&user_msg, 0, fmt, ap);
168 
169 	err->has_error = 1;
170 	err->level = E_WARNING;
171 	spprintf(&err->msg, 0, "error converting %s data (path: %s): %.*s",
172 			what_conv,
173 			path.s && *ZSTR_VAL(path.s) != '\0' ? ZSTR_VAL(path.s) : "unavailable",
174 			user_msg_size, user_msg);
175 	err->should_free = 1;
176 
177 	efree(user_msg);
178 	smart_str_free(&path);
179 }
180 ZEND_ATTRIBUTE_FORMAT(printf, 2 ,3)
do_from_zval_err(ser_context * ctx,const char * fmt,...)181 static void do_from_zval_err(ser_context *ctx, const char *fmt, ...)
182 {
183 	va_list ap;
184 
185 	va_start(ap, fmt);
186 	do_from_to_zval_err(&ctx->err, &ctx->keys, "user", fmt, ap);
187 	va_end(ap);
188 }
189 ZEND_ATTRIBUTE_FORMAT(printf, 2 ,3)
do_to_zval_err(res_context * ctx,const char * fmt,...)190 static void do_to_zval_err(res_context *ctx, const char *fmt, ...)
191 {
192 	va_list ap;
193 
194 	va_start(ap, fmt);
195 	do_from_to_zval_err(&ctx->err, &ctx->keys, "native", fmt, ap);
196 	va_end(ap);
197 }
198 
err_msg_dispose(struct err_s * err)199 void err_msg_dispose(struct err_s *err)
200 {
201 	if (err->msg != NULL) {
202 		php_error_docref(NULL, err->level, "%s", err->msg);
203 		if (err->should_free) {
204 			efree(err->msg);
205 		}
206 	}
207 }
allocations_dispose(zend_llist ** allocations)208 void allocations_dispose(zend_llist **allocations)
209 {
210 	zend_llist_destroy(*allocations);
211 	efree(*allocations);
212 	*allocations = NULL;
213 }
214 
from_array_iterate(const zval * arr,void (* func)(zval * elem,unsigned i,void ** args,ser_context * ctx),void ** args,ser_context * ctx)215 static unsigned from_array_iterate(const zval *arr,
216 								   void (*func)(zval *elem, unsigned i, void **args, ser_context *ctx),
217 								   void **args,
218 								   ser_context *ctx)
219 {
220 	unsigned		i;
221 	zval			*elem;
222 	char			buf[sizeof("element #4294967295")];
223 	char			*bufp = buf;
224 
225 	/* Note i starts at 1, not 0! */
226 	i = 1;
227 	ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(arr), elem) {
228 		if ((size_t)snprintf(buf, sizeof(buf), "element #%u", i) >= sizeof(buf)) {
229 			memcpy(buf, "element", sizeof("element"));
230 		}
231 		zend_llist_add_element(&ctx->keys, &bufp);
232 
233 		func(elem, i, args, ctx);
234 
235 		zend_llist_remove_tail(&ctx->keys);
236 		if (ctx->err.has_error) {
237 			break;
238 		}
239 		i++;
240     } ZEND_HASH_FOREACH_END();
241 
242     return i -1;
243 }
244 
245 /* Generic Aggregated conversions */
from_zval_write_aggregation(const zval * container,char * structure,const field_descriptor * descriptors,ser_context * ctx)246 static void from_zval_write_aggregation(const zval *container,
247 										char *structure,
248 										const field_descriptor *descriptors,
249 										ser_context *ctx)
250 {
251 	const field_descriptor	*descr;
252 	zval					*elem;
253 
254 	if (Z_TYPE_P(container) != IS_ARRAY) {
255 		do_from_zval_err(ctx, "%s", "expected an array here");
256 	}
257 
258 	for (descr = descriptors; descr->name != NULL && !ctx->err.has_error; descr++) {
259 		if ((elem = zend_hash_str_find(Z_ARRVAL_P(container),
260 				descr->name, descr->name_size - 1)) != NULL) {
261 
262 			if (descr->from_zval == NULL) {
263 				do_from_zval_err(ctx, "No information on how to convert value "
264 						"of key '%s'", descr->name);
265 				break;
266 			}
267 
268 			zend_llist_add_element(&ctx->keys, (void*)&descr->name);
269 			descr->from_zval(elem, ((char*)structure) + descr->field_offset, ctx);
270 			zend_llist_remove_tail(&ctx->keys);
271 
272 		} else if (descr->required) {
273 			do_from_zval_err(ctx, "The key '%s' is required", descr->name);
274 			break;
275 		}
276 	}
277 }
to_zval_read_aggregation(const char * structure,zval * zarr,const field_descriptor * descriptors,res_context * ctx)278 static void to_zval_read_aggregation(const char *structure,
279 									 zval *zarr, /* initialized array */
280 									 const field_descriptor *descriptors,
281 									 res_context *ctx)
282 {
283 	const field_descriptor	*descr;
284 
285 	assert(Z_TYPE_P(zarr) == IS_ARRAY);
286 	assert(Z_ARRVAL_P(zarr) != NULL);
287 
288 	for (descr = descriptors; descr->name != NULL && !ctx->err.has_error; descr++) {
289 		zval *new_zv, tmp;
290 
291 		if (descr->to_zval == NULL) {
292 			do_to_zval_err(ctx, "No information on how to convert native "
293 					"field into value for key '%s'", descr->name);
294 			break;
295 		}
296 
297 		ZVAL_NULL(&tmp);
298 		new_zv = zend_symtable_str_update(Z_ARRVAL_P(zarr), descr->name, descr->name_size - 1, &tmp);
299 
300 		zend_llist_add_element(&ctx->keys, (void*)&descr->name);
301 		descr->to_zval(structure + descr->field_offset, new_zv, ctx);
302 		zend_llist_remove_tail(&ctx->keys);
303 	}
304 }
305 
306 /* CONVERSIONS for integers */
from_zval_integer_common(const zval * arr_value,ser_context * ctx)307 static zend_long from_zval_integer_common(const zval *arr_value, ser_context *ctx)
308 {
309 	zend_long ret = 0;
310 	zval lzval;
311 
312 	ZVAL_NULL(&lzval);
313 	if (Z_TYPE_P(arr_value) != IS_LONG) {
314 		ZVAL_COPY(&lzval, (zval *)arr_value);
315 		arr_value = &lzval;
316 	}
317 
318 	switch (Z_TYPE_P(arr_value)) {
319 	case IS_LONG:
320 long_case:
321 		ret = Z_LVAL_P(arr_value);
322 		break;
323 
324 	/* if not long we're operating on lzval */
325 	case IS_DOUBLE:
326 double_case:
327 		convert_to_long(&lzval);
328 		goto long_case;
329 
330 	case IS_OBJECT:
331 	case IS_STRING: {
332 		zend_long lval;
333 		double dval;
334 
335 		if (!try_convert_to_string(&lzval)) {
336 			ctx->err.has_error = 1;
337 			break;
338 		}
339 
340 		switch (is_numeric_string(Z_STRVAL(lzval), Z_STRLEN(lzval), &lval, &dval, 0)) {
341 		case IS_DOUBLE:
342 			zval_ptr_dtor_str(&lzval);
343 			ZVAL_DOUBLE(&lzval, dval);
344 			goto double_case;
345 
346 		case IS_LONG:
347 			zval_ptr_dtor_str(&lzval);
348 			ZVAL_LONG(&lzval, lval);
349 			goto long_case;
350 		}
351 
352 		/* if we get here, we don't have a numeric string */
353 		do_from_zval_err(ctx, "expected an integer, but got a non numeric "
354 				"string (possibly from a converted object): '%s'", Z_STRVAL_P(arr_value));
355 		break;
356 	}
357 
358 	default:
359 		do_from_zval_err(ctx, "%s", "expected an integer, either of a PHP "
360 				"integer type or of a convertible type");
361 		break;
362 	}
363 
364 	zval_ptr_dtor(&lzval);
365 
366 	return ret;
367 }
from_zval_write_int(const zval * arr_value,char * field,ser_context * ctx)368 void from_zval_write_int(const zval *arr_value, char *field, ser_context *ctx)
369 {
370 	zend_long lval;
371 	int ival;
372 
373 	lval = from_zval_integer_common(arr_value, ctx);
374 	if (ctx->err.has_error) {
375 		return;
376 	}
377 
378 	if (lval > INT_MAX || lval < INT_MIN) {
379 		do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
380 				"for a native int");
381 		return;
382 	}
383 
384 	ival = (int)lval;
385 	memcpy(field, &ival, sizeof(ival));
386 }
from_zval_write_uint32(const zval * arr_value,char * field,ser_context * ctx)387 static void from_zval_write_uint32(const zval *arr_value, char *field, ser_context *ctx)
388 {
389 	zend_long lval;
390 	uint32_t ival;
391 
392 	lval = from_zval_integer_common(arr_value, ctx);
393 	if (ctx->err.has_error) {
394 		return;
395 	}
396 
397 	if (sizeof(zend_long) > sizeof(uint32_t) && (lval < 0 || lval > 0xFFFFFFFF)) {
398 		do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
399 				"for an unsigned 32-bit integer");
400 		return;
401 	}
402 
403 	ival = (uint32_t)lval;
404 	memcpy(field, &ival, sizeof(ival));
405 }
from_zval_write_net_uint16(const zval * arr_value,char * field,ser_context * ctx)406 static void from_zval_write_net_uint16(const zval *arr_value, char *field, ser_context *ctx)
407 {
408 	zend_long lval;
409 	uint16_t ival;
410 
411 	lval = from_zval_integer_common(arr_value, ctx);
412 	if (ctx->err.has_error) {
413 		return;
414 	}
415 
416 	if (lval < 0 || lval > 0xFFFF) {
417 		do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
418 				"for an unsigned 16-bit integer");
419 		return;
420 	}
421 
422 	ival = htons((uint16_t)lval);
423 	memcpy(field, &ival, sizeof(ival));
424 }
from_zval_write_sa_family(const zval * arr_value,char * field,ser_context * ctx)425 static void from_zval_write_sa_family(const zval *arr_value, char *field, ser_context *ctx)
426 {
427 	zend_long lval;
428 	sa_family_t ival;
429 
430 	lval = from_zval_integer_common(arr_value, ctx);
431 	if (ctx->err.has_error) {
432 		return;
433 	}
434 
435 	if (lval < 0 || lval > (sa_family_t)-1) { /* sa_family_t is unsigned */
436 		do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
437 				"for a sa_family_t value");
438 		return;
439 	}
440 
441 	ival = (sa_family_t)lval;
442 	memcpy(field, &ival, sizeof(ival));
443 }
444 
445 #ifdef SO_PASSCRED
from_zval_write_pid_t(const zval * arr_value,char * field,ser_context * ctx)446 static void from_zval_write_pid_t(const zval *arr_value, char *field, ser_context *ctx)
447 {
448 	zend_long lval;
449 	pid_t ival;
450 
451 	lval = from_zval_integer_common(arr_value, ctx);
452 	if (ctx->err.has_error) {
453 		return;
454 	}
455 
456 	if (lval < 0 || (pid_t)lval != lval) { /* pid_t is signed */
457 		do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
458 				"for a pid_t value");
459 		return;
460 	}
461 
462 	ival = (pid_t)lval;
463 	memcpy(field, &ival, sizeof(ival));
464 }
from_zval_write_uid_t(const zval * arr_value,char * field,ser_context * ctx)465 static void from_zval_write_uid_t(const zval *arr_value, char *field, ser_context *ctx)
466 {
467 	zend_long lval;
468 	uid_t ival;
469 
470 	lval = from_zval_integer_common(arr_value, ctx);
471 	if (ctx->err.has_error) {
472 		return;
473 	}
474 
475 	/* uid_t can be signed or unsigned (generally unsigned) */
476 	if ((uid_t)-1 > (uid_t)0) {
477 		if (sizeof(zend_long) > sizeof(uid_t) && (lval < 0 || (uid_t)lval != lval)) {
478 			do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
479 					"for a uid_t value");
480 			return;
481 		}
482 	} else {
483 		if (sizeof(zend_long) > sizeof(uid_t) && (uid_t)lval != lval) {
484 			do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
485 					"for a uid_t value");
486 			return;
487 		}
488 	}
489 
490 	ival = (uid_t)lval;
491 	memcpy(field, &ival, sizeof(ival));
492 }
493 #endif
494 
to_zval_read_int(const char * data,zval * zv,res_context * ctx)495 void to_zval_read_int(const char *data, zval *zv, res_context *ctx)
496 {
497 	int ival;
498 	memcpy(&ival, data, sizeof(ival));
499 
500 	ZVAL_LONG(zv, (zend_long)ival);
501 }
to_zval_read_net_uint16(const char * data,zval * zv,res_context * ctx)502 static void to_zval_read_net_uint16(const char *data, zval *zv, res_context *ctx)
503 {
504 	uint16_t ival;
505 	memcpy(&ival, data, sizeof(ival));
506 
507 	ZVAL_LONG(zv, (zend_long)ntohs(ival));
508 }
to_zval_read_sa_family(const char * data,zval * zv,res_context * ctx)509 static void to_zval_read_sa_family(const char *data, zval *zv, res_context *ctx)
510 {
511 	sa_family_t ival;
512 	memcpy(&ival, data, sizeof(ival));
513 
514 	ZVAL_LONG(zv, (zend_long)ival);
515 }
516 #if HAVE_IPV6
to_zval_read_unsigned(const char * data,zval * zv,res_context * ctx)517 static void to_zval_read_unsigned(const char *data, zval *zv, res_context *ctx)
518 {
519 	unsigned ival;
520 	memcpy(&ival, data, sizeof(ival));
521 
522 	ZVAL_LONG(zv, (zend_long)ival);
523 }
to_zval_read_uint32(const char * data,zval * zv,res_context * ctx)524 static void to_zval_read_uint32(const char *data, zval *zv, res_context *ctx)
525 {
526 	uint32_t ival;
527 	memcpy(&ival, data, sizeof(ival));
528 
529 	ZVAL_LONG(zv, (zend_long)ival);
530 }
531 #endif
532 #ifdef SO_PASSCRED
to_zval_read_pid_t(const char * data,zval * zv,res_context * ctx)533 static void to_zval_read_pid_t(const char *data, zval *zv, res_context *ctx)
534 {
535 	pid_t ival;
536 	memcpy(&ival, data, sizeof(ival));
537 
538 	ZVAL_LONG(zv, (zend_long)ival);
539 }
to_zval_read_uid_t(const char * data,zval * zv,res_context * ctx)540 static void to_zval_read_uid_t(const char *data, zval *zv, res_context *ctx)
541 {
542 	uid_t ival;
543 	memcpy(&ival, data, sizeof(ival));
544 
545 	ZVAL_LONG(zv, (zend_long)ival);
546 }
547 #endif
548 
549 /* CONVERSIONS for sockaddr */
from_zval_write_sin_addr(const zval * zaddr_str,char * inaddr,ser_context * ctx)550 static void from_zval_write_sin_addr(const zval *zaddr_str, char *inaddr, ser_context *ctx)
551 {
552 	int					res;
553 	struct sockaddr_in	saddr = {0};
554 	zend_string			*addr_str, *tmp_addr_str;
555 
556 	addr_str = zval_get_tmp_string((zval *) zaddr_str, &tmp_addr_str);
557 	res = php_set_inet_addr(&saddr, ZSTR_VAL(addr_str), ctx->sock);
558 	if (res) {
559 		memcpy(inaddr, &saddr.sin_addr, sizeof saddr.sin_addr);
560 	} else {
561 		/* error already emitted, but let's emit another more relevant */
562 		do_from_zval_err(ctx, "could not resolve address '%s' to get an AF_INET "
563 				"address", ZSTR_VAL(addr_str));
564 	}
565 
566 	zend_tmp_string_release(tmp_addr_str);
567 }
to_zval_read_sin_addr(const char * data,zval * zv,res_context * ctx)568 static void to_zval_read_sin_addr(const char *data, zval *zv, res_context *ctx)
569 {
570 	const struct in_addr *addr = (const struct in_addr *)data;
571 	socklen_t size = INET_ADDRSTRLEN;
572 	zend_string *str = zend_string_alloc(size - 1, 0);
573 	memset(ZSTR_VAL(str), '\0', size);
574 
575 	ZVAL_NEW_STR(zv, str);
576 
577 	if (inet_ntop(AF_INET, addr, Z_STRVAL_P(zv), size) == NULL) {
578 		do_to_zval_err(ctx, "could not convert IPv4 address to string "
579 				"(errno %d)", errno);
580 		return;
581 	}
582 
583 	Z_STRLEN_P(zv) = strlen(Z_STRVAL_P(zv));
584 }
585 static const field_descriptor descriptors_sockaddr_in[] = {
586 		{"family", sizeof("family"), 0, offsetof(struct sockaddr_in, sin_family), from_zval_write_sa_family, to_zval_read_sa_family},
587 		{"addr", sizeof("addr"), 0, offsetof(struct sockaddr_in, sin_addr), from_zval_write_sin_addr, to_zval_read_sin_addr},
588 		{"port", sizeof("port"), 0, offsetof(struct sockaddr_in, sin_port), from_zval_write_net_uint16, to_zval_read_net_uint16},
589 		{0}
590 };
from_zval_write_sockaddr_in(const zval * container,char * sockaddr,ser_context * ctx)591 static void from_zval_write_sockaddr_in(const zval *container, char *sockaddr, ser_context *ctx)
592 {
593 	from_zval_write_aggregation(container, sockaddr, descriptors_sockaddr_in, ctx);
594 }
to_zval_read_sockaddr_in(const char * data,zval * zv,res_context * ctx)595 static void to_zval_read_sockaddr_in(const char *data, zval *zv, res_context *ctx)
596 {
597 	to_zval_read_aggregation(data, zv, descriptors_sockaddr_in, ctx);
598 }
599 #if HAVE_IPV6
from_zval_write_sin6_addr(const zval * zaddr_str,char * addr6,ser_context * ctx)600 static void from_zval_write_sin6_addr(const zval *zaddr_str, char *addr6, ser_context *ctx)
601 {
602 	int					res;
603 	struct sockaddr_in6	saddr6 = {0};
604 	zend_string			*addr_str, *tmp_addr_str;
605 
606 	addr_str = zval_get_tmp_string((zval *) zaddr_str, &tmp_addr_str);
607 	res = php_set_inet6_addr(&saddr6, ZSTR_VAL(addr_str), ctx->sock);
608 	if (res) {
609 		memcpy(addr6, &saddr6.sin6_addr, sizeof saddr6.sin6_addr);
610 	} else {
611 		/* error already emitted, but let's emit another more relevant */
612 		do_from_zval_err(ctx, "could not resolve address '%s' to get an AF_INET6 "
613 				"address", Z_STRVAL_P(zaddr_str));
614 	}
615 
616 	zend_tmp_string_release(tmp_addr_str);
617 }
to_zval_read_sin6_addr(const char * data,zval * zv,res_context * ctx)618 static void to_zval_read_sin6_addr(const char *data, zval *zv, res_context *ctx)
619 {
620 	const struct in6_addr *addr = (const struct in6_addr *)data;
621 	socklen_t size = INET6_ADDRSTRLEN;
622 	zend_string *str = zend_string_alloc(size - 1, 0);
623 
624 	memset(ZSTR_VAL(str), '\0', size);
625 
626 	ZVAL_NEW_STR(zv, str);
627 
628 	if (inet_ntop(AF_INET6, addr, Z_STRVAL_P(zv), size) == NULL) {
629 		do_to_zval_err(ctx, "could not convert IPv6 address to string "
630 				"(errno %d)", errno);
631 		return;
632 	}
633 
634 	Z_STRLEN_P(zv) = strlen(Z_STRVAL_P(zv));
635 }
636 static const field_descriptor descriptors_sockaddr_in6[] = {
637 		{"family", sizeof("family"), 0, offsetof(struct sockaddr_in6, sin6_family), from_zval_write_sa_family, to_zval_read_sa_family},
638 		{"addr", sizeof("addr"), 0, offsetof(struct sockaddr_in6, sin6_addr), from_zval_write_sin6_addr, to_zval_read_sin6_addr},
639 		{"port", sizeof("port"), 0, offsetof(struct sockaddr_in6, sin6_port), from_zval_write_net_uint16, to_zval_read_net_uint16},
640 		{"flowinfo", sizeof("flowinfo"), 0, offsetof(struct sockaddr_in6, sin6_flowinfo), from_zval_write_uint32, to_zval_read_uint32},
641 		{"scope_id", sizeof("scope_id"), 0, offsetof(struct sockaddr_in6, sin6_scope_id), from_zval_write_uint32, to_zval_read_uint32},
642 		{0}
643 };
from_zval_write_sockaddr_in6(const zval * container,char * sockaddr6,ser_context * ctx)644 static void from_zval_write_sockaddr_in6(const zval *container, char *sockaddr6, ser_context *ctx)
645 {
646 	from_zval_write_aggregation(container, sockaddr6, descriptors_sockaddr_in6, ctx);
647 }
to_zval_read_sockaddr_in6(const char * data,zval * zv,res_context * ctx)648 static void to_zval_read_sockaddr_in6(const char *data, zval *zv, res_context *ctx)
649 {
650 	to_zval_read_aggregation(data, zv, descriptors_sockaddr_in6, ctx);
651 }
652 #endif /* HAVE_IPV6 */
from_zval_write_sun_path(const zval * path,char * sockaddr_un_c,ser_context * ctx)653 static void from_zval_write_sun_path(const zval *path, char *sockaddr_un_c, ser_context *ctx)
654 {
655 	zend_string			*path_str, *tmp_path_str;
656 	struct sockaddr_un	*saddr = (struct sockaddr_un*)sockaddr_un_c;
657 
658 	path_str = zval_get_tmp_string((zval *) path, &tmp_path_str);
659 
660 	/* code in this file relies on the path being nul terminated, even though
661 	 * this is not required, at least on linux for abstract paths. It also
662 	 * assumes that the path is not empty */
663 	if (ZSTR_LEN(path_str) == 0) {
664 		do_from_zval_err(ctx, "%s", "the path is cannot be empty");
665 		zend_tmp_string_release(tmp_path_str);
666 		return;
667 	}
668 	if (ZSTR_LEN(path_str) >= sizeof(saddr->sun_path)) {
669 		do_from_zval_err(ctx, "the path is too long, the maximum permitted "
670 				"length is %zd", sizeof(saddr->sun_path) - 1);
671 		zend_tmp_string_release(tmp_path_str);
672 		return;
673 	}
674 
675 	memcpy(&saddr->sun_path, ZSTR_VAL(path_str), ZSTR_LEN(path_str));
676 	saddr->sun_path[ZSTR_LEN(path_str)] = '\0';
677 
678 	zend_tmp_string_release(tmp_path_str);
679 }
to_zval_read_sun_path(const char * data,zval * zv,res_context * ctx)680 static void to_zval_read_sun_path(const char *data, zval *zv, res_context *ctx) {
681 	struct sockaddr_un	*saddr = (struct sockaddr_un*)data;
682 	char *nul_pos;
683 
684 	nul_pos = memchr(&saddr->sun_path, '\0', sizeof(saddr->sun_path));
685 	if (nul_pos == NULL) {
686 		do_to_zval_err(ctx, "could not find a NUL in the path");
687 		return;
688 	}
689 
690 	ZVAL_STRINGL(zv, saddr->sun_path, nul_pos - (char*)&saddr->sun_path);
691 }
692 static const field_descriptor descriptors_sockaddr_un[] = {
693 		{"family", sizeof("family"), 0, offsetof(struct sockaddr_un, sun_family), from_zval_write_sa_family, to_zval_read_sa_family},
694 		{"path", sizeof("path"), 0, 0, from_zval_write_sun_path, to_zval_read_sun_path},
695 		{0}
696 };
from_zval_write_sockaddr_un(const zval * container,char * sockaddr,ser_context * ctx)697 static void from_zval_write_sockaddr_un(const zval *container, char *sockaddr, ser_context *ctx)
698 {
699 	from_zval_write_aggregation(container, sockaddr, descriptors_sockaddr_un, ctx);
700 }
to_zval_read_sockaddr_un(const char * data,zval * zv,res_context * ctx)701 static void to_zval_read_sockaddr_un(const char *data, zval *zv, res_context *ctx)
702 {
703 	to_zval_read_aggregation(data, zv, descriptors_sockaddr_un, ctx);
704 }
from_zval_write_sockaddr_aux(const zval * container,struct sockaddr ** sockaddr_ptr,socklen_t * sockaddr_len,ser_context * ctx)705 static void from_zval_write_sockaddr_aux(const zval *container,
706 										 struct sockaddr **sockaddr_ptr,
707 										 socklen_t *sockaddr_len,
708 										 ser_context *ctx)
709 {
710 	int		family;
711 	zval	*elem;
712 	int		fill_sockaddr;
713 
714 	*sockaddr_ptr = NULL;
715 	*sockaddr_len = 0;
716 
717 	if (Z_TYPE_P(container) != IS_ARRAY) {
718 		do_from_zval_err(ctx, "%s", "expected an array here");
719 		return;
720 	}
721 
722 	fill_sockaddr = param_get_bool(ctx, KEY_FILL_SOCKADDR, 1);
723 
724 	if ((elem = zend_hash_str_find(Z_ARRVAL_P(container), "family", sizeof("family") - 1)) != NULL
725 			&& Z_TYPE_P(elem) != IS_NULL) {
726 		const char *node = "family";
727 		zend_llist_add_element(&ctx->keys, &node);
728 		from_zval_write_int(elem, (char*)&family, ctx);
729 		zend_llist_remove_tail(&ctx->keys);
730 	} else {
731 		family = ctx->sock->type;
732 	}
733 
734 	switch (family) {
735 	case AF_INET:
736 		/* though not all OSes support sockaddr_in used in IPv6 sockets */
737 		if (ctx->sock->type != AF_INET && ctx->sock->type != AF_INET6) {
738 			do_from_zval_err(ctx, "the specified family (number %d) is not "
739 					"supported on this socket", family);
740 			return;
741 		}
742 		*sockaddr_ptr = accounted_ecalloc(1, sizeof(struct sockaddr_in), ctx);
743 		*sockaddr_len = sizeof(struct sockaddr_in);
744 		if (fill_sockaddr) {
745 			from_zval_write_sockaddr_in(container, (char*)*sockaddr_ptr, ctx);
746 			(*sockaddr_ptr)->sa_family = AF_INET;
747 		}
748 		break;
749 
750 #if HAVE_IPV6
751 	case AF_INET6:
752 		if (ctx->sock->type != AF_INET6) {
753 			do_from_zval_err(ctx, "the specified family (AF_INET6) is not "
754 					"supported on this socket");
755 			return;
756 		}
757 		*sockaddr_ptr = accounted_ecalloc(1, sizeof(struct sockaddr_in6), ctx);
758 		*sockaddr_len = sizeof(struct sockaddr_in6);
759 		if (fill_sockaddr) {
760 			from_zval_write_sockaddr_in6(container, (char*)*sockaddr_ptr, ctx);
761 			(*sockaddr_ptr)->sa_family = AF_INET6;
762 		}
763 		break;
764 #endif /* HAVE_IPV6 */
765 
766 	case AF_UNIX:
767 		if (ctx->sock->type != AF_UNIX) {
768 			do_from_zval_err(ctx, "the specified family (AF_UNIX) is not "
769 					"supported on this socket");
770 			return;
771 		}
772 		*sockaddr_ptr = accounted_ecalloc(1, sizeof(struct sockaddr_un), ctx);
773 		if (fill_sockaddr) {
774 			struct sockaddr_un *sock_un = (struct sockaddr_un*)*sockaddr_ptr;
775 
776 			from_zval_write_sockaddr_un(container, (char*)*sockaddr_ptr, ctx);
777 			(*sockaddr_ptr)->sa_family = AF_UNIX;
778 
779 			/* calculating length is more complicated here. Giving the size of
780 			 * struct sockaddr_un here and relying on the nul termination of
781 			 * sun_path does not work for paths in the abstract namespace. Note
782 			 * that we always assume the path is not empty and nul terminated */
783 			*sockaddr_len = offsetof(struct sockaddr_un, sun_path) +
784 					(sock_un->sun_path[0] == '\0'
785 					? (1 + strlen(&sock_un->sun_path[1]))
786 					: strlen(sock_un->sun_path));
787 		} else {
788 			*sockaddr_len = sizeof(struct sockaddr_un);
789 		}
790 		break;
791 
792 	default:
793 		do_from_zval_err(ctx, "%s", "the only families currently supported are "
794 				"AF_INET, AF_INET6 and AF_UNIX");
795 		break;
796 	}
797 }
to_zval_read_sockaddr_aux(const char * sockaddr_c,zval * zv,res_context * ctx)798 static void to_zval_read_sockaddr_aux(const char *sockaddr_c, zval *zv, res_context *ctx)
799 {
800 	const struct sockaddr *saddr = (struct sockaddr *)sockaddr_c;
801 
802 	if (saddr->sa_family == 0) {
803 		ZVAL_NULL(zv);
804 		return;
805 	}
806 
807 	array_init(zv);
808 
809 	switch (saddr->sa_family) {
810 	case AF_INET:
811 		to_zval_read_sockaddr_in(sockaddr_c, zv, ctx);
812 		break;
813 
814 #if HAVE_IPV6
815 	case AF_INET6:
816 		to_zval_read_sockaddr_in6(sockaddr_c, zv, ctx);
817 		break;
818 #endif /* HAVE_IPV6 */
819 
820 	case AF_UNIX:
821 		to_zval_read_sockaddr_un(sockaddr_c, zv, ctx);
822 		break;
823 
824 	default:
825 		do_to_zval_err(ctx, "cannot read struct sockaddr with family %d; "
826 				"not supported",
827 				(int)saddr->sa_family);
828 		break;
829 	}
830 }
831 
832 /* CONVERSIONS for cmsghdr */
833 /*
834  * [ level => , type => , data => [],]
835  * struct cmsghdr {
836  *  socklen_t cmsg_len;    // data byte count, including header
837  *  int       cmsg_level;  // originating protocol
838  *  int       cmsg_type;   // protocol-specific type
839  *  // followed by unsigned char cmsg_data[];
840  * };
841  */
from_zval_write_control(const zval * arr,void ** control_buf,zend_llist_element * alloc,size_t * control_len,size_t * offset,ser_context * ctx)842 static void from_zval_write_control(const zval			*arr,
843 									void				**control_buf,
844 									zend_llist_element	*alloc,
845 									size_t				*control_len,
846 									size_t				*offset,
847 									ser_context			*ctx)
848 {
849 	struct cmsghdr		*cmsghdr;
850 	int					level,
851 						type;
852 	size_t				data_len,
853 						req_space,
854 						space_left;
855 	ancillary_reg_entry	*entry;
856 
857 	static const field_descriptor descriptor_level[] = {
858 			{"level", sizeof("level"), 0, 0, from_zval_write_int, 0},
859 			{0}
860 	};
861 	static const field_descriptor descriptor_type[] = {
862 			{"type", sizeof("type"), 0, 0, from_zval_write_int, 0},
863 			{0}
864 	};
865 	field_descriptor descriptor_data[] = {
866 			{"data", sizeof("data"), 0, 0, 0, 0},
867 			{0}
868 	};
869 
870 	from_zval_write_aggregation(arr, (char *)&level, descriptor_level, ctx);
871 	if (ctx->err.has_error) {
872 		return;
873 	}
874 	from_zval_write_aggregation(arr, (char *)&type, descriptor_type, ctx);
875 	if (ctx->err.has_error) {
876 		return;
877 	}
878 
879 	entry = get_ancillary_reg_entry(level, type);
880 	if (entry == NULL) {
881 		do_from_zval_err(ctx, "cmsghdr with level %d and type %d not supported",
882 				level, type);
883 		return;
884 	}
885 
886 	if (entry->calc_space) {
887 		zval *data_elem;
888 		/* arr must be an array at this point */
889 		if ((data_elem = zend_hash_str_find(Z_ARRVAL_P(arr), "data", sizeof("data") - 1)) == NULL) {
890 			do_from_zval_err(ctx, "cmsghdr should have a 'data' element here");
891 			return;
892 		}
893 		data_len = entry->calc_space(data_elem, ctx);
894 		if (ctx->err.has_error) {
895 			return;
896 		}
897 	} else {
898 		data_len = entry->size;
899 	}
900 	req_space = CMSG_SPACE(data_len);
901 	space_left = *control_len - *offset;
902 	assert(*control_len >= *offset);
903 
904 	if (space_left < req_space) {
905 		*control_buf = safe_erealloc(*control_buf, 2, req_space, *control_len);
906 		*control_len += 2 * req_space;
907 		memset((char *)*control_buf + *offset, '\0', *control_len - *offset);
908 		memcpy(&alloc->data, control_buf, sizeof *control_buf);
909 	}
910 
911 	cmsghdr = (struct cmsghdr*)(((char*)*control_buf) + *offset);
912 	cmsghdr->cmsg_level	= level;
913 	cmsghdr->cmsg_type	= type;
914 	cmsghdr->cmsg_len	= CMSG_LEN(data_len);
915 
916 	descriptor_data[0].from_zval = entry->from_array;
917 	from_zval_write_aggregation(arr, (char*)CMSG_DATA(cmsghdr), descriptor_data, ctx);
918 
919 	*offset += req_space;
920 }
from_zval_write_control_array(const zval * arr,char * msghdr_c,ser_context * ctx)921 static void from_zval_write_control_array(const zval *arr, char *msghdr_c, ser_context *ctx)
922 {
923 	char				buf[sizeof("element #4294967295")];
924 	char				*bufp = buf;
925 	zval				*elem;
926 	uint32_t			i = 0;
927 	int					num_elems;
928 	void				*control_buf;
929 	zend_llist_element	*alloc;
930 	size_t				control_len,
931 						cur_offset;
932 	struct msghdr		*msg = (struct msghdr*)msghdr_c;
933 
934 	if (Z_TYPE_P(arr) != IS_ARRAY) {
935 		do_from_zval_err(ctx, "%s", "expected an array here");
936 		return;
937 	}
938 
939 	num_elems = zend_hash_num_elements(Z_ARRVAL_P(arr));
940 	if (num_elems == 0) {
941 		return;
942 	}
943 
944 	/* estimate each message at 20 bytes */
945 	control_buf	= accounted_safe_ecalloc(num_elems, CMSG_SPACE(20), 0, ctx);
946 	alloc		= ctx->allocations.tail;
947 	control_len = (size_t)num_elems * CMSG_SPACE(20);
948 	cur_offset	= 0;
949 
950 	ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(arr), elem) {
951 		if (ctx->err.has_error) {
952 			break;
953 		}
954 
955 		if ((size_t)snprintf(buf, sizeof(buf), "element #%u", (unsigned)i++) >= sizeof(buf)) {
956 			memcpy(buf, "element", sizeof("element"));
957 		}
958 		zend_llist_add_element(&ctx->keys, &bufp);
959 
960 		from_zval_write_control(elem, &control_buf, alloc, &control_len, &cur_offset, ctx);
961 
962 		zend_llist_remove_tail(&ctx->keys);
963 	} ZEND_HASH_FOREACH_END();
964 
965     msg->msg_control = control_buf;
966     msg->msg_controllen = cur_offset; /* not control_len, which may be larger */
967 }
to_zval_read_cmsg_data(const char * cmsghdr_c,zval * zv,res_context * ctx)968 static void to_zval_read_cmsg_data(const char *cmsghdr_c, zval *zv, res_context *ctx)
969 {
970 	const struct cmsghdr	*cmsg = (const struct cmsghdr *)cmsghdr_c;
971 	ancillary_reg_entry		*entry;
972 	size_t					len,
973 							*len_p = &len;
974 
975 	entry = get_ancillary_reg_entry(cmsg->cmsg_level, cmsg->cmsg_type);
976 	if (entry == NULL) {
977 		do_to_zval_err(ctx, "cmsghdr with level %d and type %d not supported",
978 				cmsg->cmsg_level, cmsg->cmsg_type);
979 		return;
980 	}
981 	if (CMSG_LEN(entry->size) > cmsg->cmsg_len) {
982 		do_to_zval_err(ctx, "the cmsghdr structure is unexpectedly small; "
983 				"expected a length of at least " ZEND_LONG_FMT ", but got " ZEND_LONG_FMT,
984 				(zend_long)CMSG_LEN(entry->size), (zend_long)cmsg->cmsg_len);
985 		return;
986 	}
987 
988 	len = (size_t)cmsg->cmsg_len; /* use another var because type of cmsg_len varies */
989 
990 	if (zend_hash_str_add_ptr(&ctx->params, KEY_CMSG_LEN, sizeof(KEY_CMSG_LEN) - 1, len_p) == NULL) {
991 		do_to_zval_err(ctx, "%s", "could not set parameter " KEY_CMSG_LEN);
992 		return;
993 	}
994 
995 	entry->to_array((const char *)CMSG_DATA(cmsg), zv, ctx);
996 
997 	zend_hash_str_del(&ctx->params, KEY_CMSG_LEN, sizeof(KEY_CMSG_LEN) - 1);
998 }
to_zval_read_control(const char * cmsghdr_c,zval * zv,res_context * ctx)999 static void to_zval_read_control(const char *cmsghdr_c, zval *zv, res_context *ctx)
1000 {
1001 	/* takes a cmsghdr, not a msghdr like from_zval_write_control */
1002 	static const field_descriptor descriptors[] = {
1003 			{"level", sizeof("level"), 0, offsetof(struct cmsghdr, cmsg_level), 0, to_zval_read_int},
1004 			{"type", sizeof("type"), 0, offsetof(struct cmsghdr, cmsg_type), 0, to_zval_read_int},
1005 			{"data", sizeof("data"), 0, 0 /* cmsghdr passed */, 0, to_zval_read_cmsg_data},
1006 			{0}
1007 	};
1008 
1009 	array_init_size(zv, 3);
1010 	to_zval_read_aggregation(cmsghdr_c, zv, descriptors, ctx);
1011 }
to_zval_read_control_array(const char * msghdr_c,zval * zv,res_context * ctx)1012 static void to_zval_read_control_array(const char *msghdr_c, zval *zv, res_context *ctx)
1013 {
1014 	struct msghdr	*msg = (struct msghdr *)msghdr_c;
1015 	struct cmsghdr	*cmsg;
1016 	char			buf[sizeof("element #4294967295")];
1017 	char			*bufp = buf;
1018 	uint32_t		i = 1;
1019 
1020 	array_init(zv);
1021 
1022 	for (cmsg = CMSG_FIRSTHDR(msg);
1023 			cmsg != NULL && !ctx->err.has_error;
1024 			cmsg = CMSG_NXTHDR(msg, cmsg)) {
1025 		zval *elem, tmp;
1026 
1027 		ZVAL_NULL(&tmp);
1028 		elem = zend_hash_next_index_insert(Z_ARRVAL_P(zv), &tmp);
1029 
1030 		if ((size_t)snprintf(buf, sizeof(buf), "element #%u", (unsigned)i++) >= sizeof(buf)) {
1031 			memcpy(buf, "element", sizeof("element"));
1032 		}
1033 		zend_llist_add_element(&ctx->keys, &bufp);
1034 
1035 		to_zval_read_control((const char *)cmsg, elem, ctx);
1036 
1037 		zend_llist_remove_tail(&ctx->keys);
1038 	}
1039 }
1040 
1041 /* CONVERSIONS for msghdr */
from_zval_write_name(const zval * zname_arr,char * msghdr_c,ser_context * ctx)1042 static void from_zval_write_name(const zval *zname_arr, char *msghdr_c, ser_context *ctx)
1043 {
1044 	struct sockaddr	*sockaddr;
1045 	socklen_t		sockaddr_len;
1046 	struct msghdr	*msghdr = (struct msghdr *)msghdr_c;
1047 
1048 	from_zval_write_sockaddr_aux(zname_arr, &sockaddr, &sockaddr_len, ctx);
1049 
1050 	msghdr->msg_name = sockaddr;
1051 	msghdr->msg_namelen = sockaddr_len;
1052 }
to_zval_read_name(const char * sockaddr_p,zval * zv,res_context * ctx)1053 static void to_zval_read_name(const char *sockaddr_p, zval *zv, res_context *ctx)
1054 {
1055 	void *name = (void*)*(void**)sockaddr_p;
1056 	if (name == NULL) {
1057 		ZVAL_NULL(zv);
1058 	} else {
1059 		to_zval_read_sockaddr_aux(name, zv, ctx);
1060 	}
1061 }
from_zval_write_msghdr_buffer_size(const zval * elem,char * msghdr_c,ser_context * ctx)1062 static void from_zval_write_msghdr_buffer_size(const zval *elem, char *msghdr_c, ser_context *ctx)
1063 {
1064 	zend_long lval;
1065 	struct msghdr *msghdr = (struct msghdr *)msghdr_c;
1066 
1067 	lval = from_zval_integer_common(elem, ctx);
1068 	if (ctx->err.has_error) {
1069 		return;
1070 	}
1071 
1072 	if (lval < 0 || (zend_ulong)lval > MAX_USER_BUFF_SIZE) {
1073 		do_from_zval_err(ctx, "the buffer size must be between 1 and " ZEND_LONG_FMT "; "
1074 				"given " ZEND_LONG_FMT, (zend_long)MAX_USER_BUFF_SIZE, lval);
1075 		return;
1076 	}
1077 
1078 	msghdr->msg_iovlen = 1;
1079 	msghdr->msg_iov = accounted_emalloc(sizeof(*msghdr->msg_iov) * 1, ctx);
1080 	msghdr->msg_iov[0].iov_base = accounted_emalloc((size_t)lval, ctx);
1081 	msghdr->msg_iov[0].iov_len = (size_t)lval;
1082 }
from_zval_write_iov_array_aux(zval * elem,unsigned i,void ** args,ser_context * ctx)1083 static void from_zval_write_iov_array_aux(zval *elem, unsigned i, void **args, ser_context *ctx)
1084 {
1085 	struct msghdr	*msg = args[0];
1086 	zend_string     *str, *tmp_str;
1087 
1088 	str = zval_get_tmp_string(elem, &tmp_str);
1089 
1090 	msg->msg_iov[i - 1].iov_base = accounted_emalloc(ZSTR_LEN(str), ctx);
1091 	msg->msg_iov[i - 1].iov_len = ZSTR_LEN(str);
1092 	memcpy(msg->msg_iov[i - 1].iov_base, ZSTR_VAL(str), ZSTR_LEN(str));
1093 
1094 	zend_tmp_string_release(tmp_str);
1095 }
from_zval_write_iov_array(const zval * arr,char * msghdr_c,ser_context * ctx)1096 static void from_zval_write_iov_array(const zval *arr, char *msghdr_c, ser_context *ctx)
1097 {
1098 	int				num_elem;
1099 	struct msghdr	*msg = (struct msghdr*)msghdr_c;
1100 
1101 	if (Z_TYPE_P(arr) != IS_ARRAY) {
1102 		do_from_zval_err(ctx, "%s", "expected an array here");
1103 		return;
1104 	}
1105 
1106 	num_elem = zend_hash_num_elements(Z_ARRVAL_P(arr));
1107 	if (num_elem == 0) {
1108 		return;
1109 	}
1110 
1111 	msg->msg_iov = accounted_safe_ecalloc(num_elem, sizeof *msg->msg_iov, 0, ctx);
1112 	msg->msg_iovlen = (size_t)num_elem;
1113 
1114     from_array_iterate(arr, from_zval_write_iov_array_aux, (void**)&msg, ctx);
1115 }
from_zval_write_controllen(const zval * elem,char * msghdr_c,ser_context * ctx)1116 static void from_zval_write_controllen(const zval *elem, char *msghdr_c, ser_context *ctx)
1117 {
1118 	struct msghdr *msghdr = (struct msghdr *)msghdr_c;
1119 	uint32_t len;
1120 
1121 	/* controllen should be an unsigned with at least 32-bit. Let's assume
1122 	 * this least common denominator
1123 	 */
1124 	from_zval_write_uint32(elem, (char*)&len, ctx);
1125 	if (!ctx->err.has_error && len == 0) {
1126 		do_from_zval_err(ctx, "controllen cannot be 0");
1127 		return;
1128 	}
1129 	msghdr->msg_control = accounted_emalloc(len, ctx);
1130 	msghdr->msg_controllen = len;
1131 }
from_zval_write_msghdr_send(const zval * container,char * msghdr_c,ser_context * ctx)1132 void from_zval_write_msghdr_send(const zval *container, char *msghdr_c, ser_context *ctx)
1133 {
1134 	static const field_descriptor descriptors[] = {
1135 			{"name", sizeof("name"), 0, 0, from_zval_write_name, 0},
1136 			{"iov", sizeof("iov"), 0, 0, from_zval_write_iov_array, 0},
1137 			{"control", sizeof("control"), 0, 0, from_zval_write_control_array, 0},
1138 			{0}
1139 	};
1140 
1141 	from_zval_write_aggregation(container, msghdr_c, descriptors, ctx);
1142 }
from_zval_write_msghdr_recv(const zval * container,char * msghdr_c,ser_context * ctx)1143 void from_zval_write_msghdr_recv(const zval *container, char *msghdr_c, ser_context *ctx)
1144 {
1145 	/* zval to struct msghdr, version for recvmsg(). It differs from the version
1146 	 * for sendmsg() in that it:
1147 	 * 	- has a buffer_size instead of an iov array;
1148 	 * 	- has no control element; has a controllen element instead
1149 	 * struct msghdr {
1150 	 *    void *msg_name;
1151 	 *    socklen_t msg_namelen;
1152 	 *    struct iovec *msg_iov;
1153 	 *    size_t msg_iovlen;
1154 	 *    void *msg_control;
1155 	 *    size_t msg_controllen; //can also be socklen_t
1156 	 *    int msg_flags;
1157 	 * };
1158 	 */
1159 	static const field_descriptor descriptors[] = {
1160 			{"name", sizeof("name"), 0, 0, from_zval_write_name, 0},
1161 			{"buffer_size", sizeof("buffer_size"), 0, 0, from_zval_write_msghdr_buffer_size, 0},
1162 			{"controllen", sizeof("controllen"), 1, 0, from_zval_write_controllen, 0},
1163 			{0}
1164 	};
1165 	struct msghdr 	*msghdr = (struct msghdr *)msghdr_c;
1166 	const int		falsev = 0,
1167 					*falsevp = &falsev;
1168 
1169 	if (zend_hash_str_add_ptr(&ctx->params, KEY_FILL_SOCKADDR, sizeof(KEY_FILL_SOCKADDR) - 1, (void *)falsevp) == NULL) {
1170 		do_from_zval_err(ctx, "could not add fill_sockaddr; this is a bug");
1171 		return;
1172 	}
1173 
1174 	from_zval_write_aggregation(container, msghdr_c, descriptors, ctx);
1175 
1176 	zend_hash_str_del(&ctx->params, KEY_FILL_SOCKADDR, sizeof(KEY_FILL_SOCKADDR) - 1);
1177 	if (ctx->err.has_error) {
1178 		return;
1179 	}
1180 
1181 	if (msghdr->msg_iovlen == 0) {
1182 		msghdr->msg_iovlen = 1;
1183 		msghdr->msg_iov = accounted_emalloc(sizeof(*msghdr->msg_iov) * 1, ctx);
1184 		msghdr->msg_iov[0].iov_base = accounted_emalloc((size_t)DEFAULT_BUFF_SIZE, ctx);
1185 		msghdr->msg_iov[0].iov_len = (size_t)DEFAULT_BUFF_SIZE;
1186 	}
1187 }
1188 
to_zval_read_iov(const char * msghdr_c,zval * zv,res_context * ctx)1189 static void to_zval_read_iov(const char *msghdr_c, zval *zv, res_context *ctx)
1190 {
1191 	const struct msghdr	*msghdr = (const struct msghdr *)msghdr_c;
1192 	size_t				iovlen = msghdr->msg_iovlen;
1193 	ssize_t				*recvmsg_ret,
1194 						bytes_left;
1195 	uint32_t			i;
1196 
1197 	if (iovlen > UINT_MAX) {
1198 		do_to_zval_err(ctx, "unexpectedly large value for iov_len: %lu",
1199 				(unsigned long)iovlen);
1200 	}
1201 	array_init_size(zv, (uint32_t)iovlen);
1202 
1203 	if ((recvmsg_ret = zend_hash_str_find_ptr(&ctx->params, KEY_RECVMSG_RET, sizeof(KEY_RECVMSG_RET) - 1)) == NULL) {
1204 		do_to_zval_err(ctx, "recvmsg_ret not found in params. This is a bug");
1205 		return;
1206 	}
1207 	bytes_left = *recvmsg_ret;
1208 
1209 	for (i = 0; bytes_left > 0 && i < (uint32_t)iovlen; i++) {
1210 		zval elem;
1211 		size_t len = MIN(msghdr->msg_iov[i].iov_len, (size_t)bytes_left);
1212 		zend_string	*buf = zend_string_alloc(len, 0);
1213 
1214 		memcpy(ZSTR_VAL(buf), msghdr->msg_iov[i].iov_base, ZSTR_LEN(buf));
1215 		ZSTR_VAL(buf)[ZSTR_LEN(buf)] = '\0';
1216 
1217 		ZVAL_NEW_STR(&elem, buf);
1218 		add_next_index_zval(zv, &elem);
1219 		bytes_left -= len;
1220 	}
1221 }
to_zval_read_msghdr(const char * msghdr_c,zval * zv,res_context * ctx)1222 void to_zval_read_msghdr(const char *msghdr_c, zval *zv, res_context *ctx)
1223 {
1224 	static const field_descriptor descriptors[] = {
1225 			{"name", sizeof("name"), 0, offsetof(struct msghdr, msg_name), 0, to_zval_read_name},
1226 			{"control", sizeof("control"), 0, 0, 0, to_zval_read_control_array},
1227 			{"iov", sizeof("iov"), 0, 0, 0, to_zval_read_iov},
1228 			{"flags", sizeof("flags"), 0, offsetof(struct msghdr, msg_flags), 0, to_zval_read_int},
1229 			{0}
1230 	};
1231 
1232 	array_init_size(zv, 4);
1233 
1234 	to_zval_read_aggregation(msghdr_c, zv, descriptors, ctx);
1235 }
1236 
1237 #if defined(IPV6_PKTINFO) && HAVE_IPV6
1238 /* CONVERSIONS for if_index */
from_zval_write_ifindex(const zval * zv,char * uinteger,ser_context * ctx)1239 static void from_zval_write_ifindex(const zval *zv, char *uinteger, ser_context *ctx)
1240 {
1241 	unsigned ret = 0;
1242 
1243 	if (Z_TYPE_P(zv) == IS_LONG) {
1244 		if (Z_LVAL_P(zv) < 0 || (zend_ulong)Z_LVAL_P(zv) > UINT_MAX) { /* allow 0 (unspecified interface) */
1245 			do_from_zval_err(ctx, "the interface index cannot be negative or "
1246 					"larger than %u; given " ZEND_LONG_FMT, UINT_MAX, Z_LVAL_P(zv));
1247 		} else {
1248 			ret = (unsigned)Z_LVAL_P(zv);
1249 		}
1250 	} else {
1251 		zend_string *str, *tmp_str;
1252 
1253 		str = zval_get_tmp_string((zval *) zv, &tmp_str);
1254 
1255 #if HAVE_IF_NAMETOINDEX
1256 		ret = if_nametoindex(ZSTR_VAL(str));
1257 		if (ret == 0) {
1258 			do_from_zval_err(ctx, "no interface with name \"%s\" could be found", ZSTR_VAL(str));
1259 		}
1260 #elif defined(SIOCGIFINDEX)
1261 		{
1262 			struct ifreq ifr;
1263 			if (strlcpy(ifr.ifr_name, ZSTR_VAL(str), sizeof(ifr.ifr_name))
1264 					>= sizeof(ifr.ifr_name)) {
1265 				do_from_zval_err(ctx, "the interface name \"%s\" is too large ", ZSTR_VAL(str));
1266 			} else if (ioctl(ctx->sock->bsd_socket, SIOCGIFINDEX, &ifr) < 0) {
1267 				if (errno == ENODEV) {
1268 					do_from_zval_err(ctx, "no interface with name \"%s\" could be "
1269 							"found", ZSTR_VAL(str));
1270 				} else {
1271 					do_from_zval_err(ctx, "error fetching interface index for "
1272 							"interface with name \"%s\" (errno %d)",
1273 							ZSTR_VAL(str), errno);
1274 				}
1275 			} else {
1276 				ret = (unsigned)ifr.ifr_ifindex;
1277 			}
1278 		}
1279 #else
1280 		do_from_zval_err(ctx,
1281 				"this platform does not support looking up an interface by "
1282 				"name, an integer interface index must be supplied instead");
1283 #endif
1284 
1285 		zend_tmp_string_release(tmp_str);
1286 	}
1287 
1288 	if (!ctx->err.has_error) {
1289 		memcpy(uinteger, &ret, sizeof(ret));
1290 	}
1291 }
1292 
1293 /* CONVERSIONS for struct in6_pktinfo */
1294 static const field_descriptor descriptors_in6_pktinfo[] = {
1295 		{"addr", sizeof("addr"), 1, offsetof(struct in6_pktinfo, ipi6_addr), from_zval_write_sin6_addr, to_zval_read_sin6_addr},
1296 		{"ifindex", sizeof("ifindex"), 1, offsetof(struct in6_pktinfo, ipi6_ifindex), from_zval_write_ifindex, to_zval_read_unsigned},
1297 		{0}
1298 };
from_zval_write_in6_pktinfo(const zval * container,char * in6_pktinfo_c,ser_context * ctx)1299 void from_zval_write_in6_pktinfo(const zval *container, char *in6_pktinfo_c, ser_context *ctx)
1300 {
1301 	from_zval_write_aggregation(container, in6_pktinfo_c, descriptors_in6_pktinfo, ctx);
1302 }
to_zval_read_in6_pktinfo(const char * data,zval * zv,res_context * ctx)1303 void to_zval_read_in6_pktinfo(const char *data, zval *zv, res_context *ctx)
1304 {
1305 	array_init_size(zv, 2);
1306 
1307 	to_zval_read_aggregation(data, zv, descriptors_in6_pktinfo, ctx);
1308 }
1309 #endif
1310 
1311 /* CONVERSIONS for struct ucred */
1312 #ifdef SO_PASSCRED
1313 static const field_descriptor descriptors_ucred[] = {
1314 		{"pid", sizeof("pid"), 1, offsetof(struct ucred, pid), from_zval_write_pid_t, to_zval_read_pid_t},
1315 		{"uid", sizeof("uid"), 1, offsetof(struct ucred, uid), from_zval_write_uid_t, to_zval_read_uid_t},
1316 		/* assume the type gid_t is the same as uid_t: */
1317 		{"gid", sizeof("gid"), 1, offsetof(struct ucred, gid), from_zval_write_uid_t, to_zval_read_uid_t},
1318 		{0}
1319 };
from_zval_write_ucred(const zval * container,char * ucred_c,ser_context * ctx)1320 void from_zval_write_ucred(const zval *container, char *ucred_c, ser_context *ctx)
1321 {
1322 	from_zval_write_aggregation(container, ucred_c, descriptors_ucred, ctx);
1323 }
to_zval_read_ucred(const char * data,zval * zv,res_context * ctx)1324 void to_zval_read_ucred(const char *data, zval *zv, res_context *ctx)
1325 {
1326 	array_init_size(zv, 3);
1327 
1328 	to_zval_read_aggregation(data, zv, descriptors_ucred, ctx);
1329 }
1330 #endif
1331 
1332 /* CONVERSIONS for SCM_RIGHTS */
1333 #ifdef SCM_RIGHTS
calculate_scm_rights_space(const zval * arr,ser_context * ctx)1334 size_t calculate_scm_rights_space(const zval *arr, ser_context *ctx)
1335 {
1336 	int num_elems;
1337 
1338 	if (Z_TYPE_P(arr) != IS_ARRAY) {
1339 		do_from_zval_err(ctx, "%s", "expected an array here");
1340 		return (size_t)-1;
1341 	}
1342 
1343 	num_elems = zend_hash_num_elements(Z_ARRVAL_P(arr));
1344 	if (num_elems == 0) {
1345 		do_from_zval_err(ctx, "%s", "expected at least one element in this array");
1346 		return (size_t)-1;
1347 	}
1348 
1349 	return zend_hash_num_elements(Z_ARRVAL_P(arr)) * sizeof(int);
1350 }
from_zval_write_fd_array_aux(zval * elem,unsigned i,void ** args,ser_context * ctx)1351 static void from_zval_write_fd_array_aux(zval *elem, unsigned i, void **args, ser_context *ctx)
1352 {
1353 	int *iarr = args[0];
1354 
1355 	if (Z_TYPE_P(elem) == IS_RESOURCE) {
1356 		php_stream *stream;
1357 		php_socket *sock;
1358 
1359 		sock = (php_socket *)zend_fetch_resource_ex(elem, NULL, php_sockets_le_socket());
1360 		if (sock) {
1361 			iarr[i] = sock->bsd_socket;
1362 			return;
1363 		}
1364 
1365 		stream = (php_stream *)zend_fetch_resource2_ex(elem, NULL, php_file_le_stream(), php_file_le_pstream());
1366 		if (stream == NULL) {
1367 			do_from_zval_err(ctx, "resource is not a stream or a socket");
1368 			return;
1369 		}
1370 
1371 		if (php_stream_cast(stream, PHP_STREAM_AS_FD, (void **)&iarr[i - 1],
1372 				REPORT_ERRORS) == FAILURE) {
1373 			do_from_zval_err(ctx, "cast stream to file descriptor failed");
1374 			return;
1375 		}
1376 	} else {
1377 		do_from_zval_err(ctx, "expected a resource variable");
1378 	}
1379 }
from_zval_write_fd_array(const zval * arr,char * int_arr,ser_context * ctx)1380 void from_zval_write_fd_array(const zval *arr, char *int_arr, ser_context *ctx)
1381 {
1382 	if (Z_TYPE_P(arr) != IS_ARRAY) {
1383 		do_from_zval_err(ctx, "%s", "expected an array here");
1384 		return;
1385 	}
1386 
1387    from_array_iterate(arr, &from_zval_write_fd_array_aux, (void**)&int_arr, ctx);
1388 }
to_zval_read_fd_array(const char * data,zval * zv,res_context * ctx)1389 void to_zval_read_fd_array(const char *data, zval *zv, res_context *ctx)
1390 {
1391 	size_t			*cmsg_len;
1392 	int				num_elems,
1393 					i;
1394 	struct cmsghdr	*dummy_cmsg = 0;
1395 	size_t			data_offset;
1396 
1397 	data_offset = (unsigned char *)CMSG_DATA(dummy_cmsg)
1398 			- (unsigned char *)dummy_cmsg;
1399 
1400 	if ((cmsg_len = zend_hash_str_find_ptr(&ctx->params, KEY_CMSG_LEN, sizeof(KEY_CMSG_LEN) - 1)) == NULL) {
1401 		do_to_zval_err(ctx, "could not get value of parameter " KEY_CMSG_LEN);
1402 		return;
1403 	}
1404 
1405 	if (*cmsg_len < data_offset) {
1406 		do_to_zval_err(ctx, "length of cmsg is smaller than its data member "
1407 				"offset (" ZEND_LONG_FMT " vs " ZEND_LONG_FMT ")", (zend_long)*cmsg_len, (zend_long)data_offset);
1408 		return;
1409 	}
1410 	num_elems = (*cmsg_len - data_offset) / sizeof(int);
1411 
1412 	array_init_size(zv, num_elems);
1413 
1414 	for (i = 0; i < num_elems; i++) {
1415 		zval		elem;
1416 		int			fd;
1417 		struct stat	statbuf;
1418 
1419 		fd = *((int *)data + i);
1420 
1421 		/* determine whether we have a socket */
1422 		if (fstat(fd, &statbuf) == -1) {
1423 			do_to_zval_err(ctx, "error creating resource for received file "
1424 					"descriptor %d: fstat() call failed with errno %d", fd, errno);
1425 			return;
1426 		}
1427 		if (S_ISSOCK(statbuf.st_mode)) {
1428 			php_socket *sock = socket_import_file_descriptor(fd);
1429 			ZVAL_RES(&elem, zend_register_resource(sock, php_sockets_le_socket()));
1430 		} else {
1431 			php_stream *stream = php_stream_fopen_from_fd(fd, "rw", NULL);
1432 			php_stream_to_zval(stream, &elem);
1433 		}
1434 
1435 		add_next_index_zval(zv, &elem);
1436 	}
1437 }
1438 #endif
1439 
1440 /* ENTRY POINT for conversions */
free_from_zval_allocation(void * alloc_ptr_ptr)1441 static void free_from_zval_allocation(void *alloc_ptr_ptr)
1442 {
1443 	efree(*(void**)alloc_ptr_ptr);
1444 }
from_zval_run_conversions(const zval * container,php_socket * sock,from_zval_write_field * writer,size_t struct_size,const char * top_name,zend_llist ** allocations,struct err_s * err)1445 void *from_zval_run_conversions(const zval			*container,
1446 								php_socket			*sock,
1447 								from_zval_write_field	*writer,
1448 								size_t				struct_size,
1449 								const char			*top_name,
1450 								zend_llist			**allocations /* out */,
1451 								struct err_s			*err /* in/out */)
1452 {
1453 	ser_context ctx;
1454 	char *structure;
1455 
1456 	*allocations = NULL;
1457 
1458 	if (err->has_error) {
1459 		return NULL;
1460 	}
1461 
1462 	memset(&ctx, 0, sizeof(ctx));
1463 	zend_hash_init(&ctx.params, 8, NULL, NULL, 0);
1464 	zend_llist_init(&ctx.keys, sizeof(const char *), NULL, 0);
1465 	zend_llist_init(&ctx.allocations, sizeof(void *), &free_from_zval_allocation, 0);
1466 	ctx.sock = sock;
1467 
1468 	structure = ecalloc(1, struct_size);
1469 
1470 	zend_llist_add_element(&ctx.keys, &top_name);
1471 	zend_llist_add_element(&ctx.allocations, &structure);
1472 
1473 	/* main call */
1474 	writer(container, structure, &ctx);
1475 
1476 	if (ctx.err.has_error) {
1477 		zend_llist_destroy(&ctx.allocations); /* deallocates structure as well */
1478 		structure = NULL;
1479 		*err = ctx.err;
1480 	} else {
1481 		*allocations = emalloc(sizeof **allocations);
1482 		**allocations = ctx.allocations;
1483 	}
1484 
1485 	zend_llist_destroy(&ctx.keys);
1486 	zend_hash_destroy(&ctx.params);
1487 
1488 	return structure;
1489 }
to_zval_run_conversions(const char * structure,to_zval_read_field * reader,const char * top_name,const struct key_value * key_value_pairs,struct err_s * err,zval * zv)1490 zval *to_zval_run_conversions(const char *structure,
1491 							  to_zval_read_field *reader,
1492 							  const char *top_name,
1493 							  const struct key_value *key_value_pairs,
1494 							  struct err_s *err, zval *zv)
1495 {
1496 	res_context				ctx;
1497 	const struct key_value	*kv;
1498 
1499 	if (err->has_error) {
1500 		return NULL;
1501 	}
1502 
1503 	memset(&ctx, 0, sizeof(ctx));
1504 	zend_llist_init(&ctx.keys, sizeof(const char *), NULL, 0);
1505 	zend_llist_add_element(&ctx.keys, &top_name);
1506 
1507 	zend_hash_init(&ctx.params, 8, NULL, NULL, 0);
1508 	for (kv = key_value_pairs; kv->key != NULL; kv++) {
1509 		zend_hash_str_update_ptr(&ctx.params, kv->key, kv->key_size - 1, kv->value);
1510 	}
1511 
1512 	ZVAL_NULL(zv);
1513 	/* main call */
1514 	reader(structure, zv, &ctx);
1515 
1516 	if (ctx.err.has_error) {
1517 		zval_ptr_dtor(zv);
1518 		ZVAL_UNDEF(zv);
1519 		*err = ctx.err;
1520 	}
1521 
1522 	zend_llist_destroy(&ctx.keys);
1523 	zend_hash_destroy(&ctx.params);
1524 
1525 	return Z_ISUNDEF_P(zv)? NULL : zv;
1526 }
1527