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_docref0(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 convert_to_string(&lzval);
336
337 switch (is_numeric_string(Z_STRVAL(lzval), Z_STRLEN(lzval), &lval, &dval, 0)) {
338 case IS_DOUBLE:
339 zval_ptr_dtor_str(&lzval);
340 ZVAL_DOUBLE(&lzval, dval);
341 goto double_case;
342
343 case IS_LONG:
344 zval_ptr_dtor_str(&lzval);
345 ZVAL_LONG(&lzval, lval);
346 goto long_case;
347 }
348
349 /* if we get here, we don't have a numeric string */
350 do_from_zval_err(ctx, "expected an integer, but got a non numeric "
351 "string (possibly from a converted object): '%s'", Z_STRVAL_P(arr_value));
352 break;
353 }
354
355 default:
356 do_from_zval_err(ctx, "%s", "expected an integer, either of a PHP "
357 "integer type or of a convertible type");
358 break;
359 }
360
361 zval_ptr_dtor(&lzval);
362
363 return ret;
364 }
from_zval_write_int(const zval * arr_value,char * field,ser_context * ctx)365 void from_zval_write_int(const zval *arr_value, char *field, ser_context *ctx)
366 {
367 zend_long lval;
368 int ival;
369
370 lval = from_zval_integer_common(arr_value, ctx);
371 if (ctx->err.has_error) {
372 return;
373 }
374
375 if (lval > INT_MAX || lval < INT_MIN) {
376 do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
377 "for a native int");
378 return;
379 }
380
381 ival = (int)lval;
382 memcpy(field, &ival, sizeof(ival));
383 }
from_zval_write_uint32(const zval * arr_value,char * field,ser_context * ctx)384 static void from_zval_write_uint32(const zval *arr_value, char *field, ser_context *ctx)
385 {
386 zend_long lval;
387 uint32_t ival;
388
389 lval = from_zval_integer_common(arr_value, ctx);
390 if (ctx->err.has_error) {
391 return;
392 }
393
394 if (sizeof(zend_long) > sizeof(uint32_t) && (lval < 0 || lval > 0xFFFFFFFF)) {
395 do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
396 "for an unsigned 32-bit integer");
397 return;
398 }
399
400 ival = (uint32_t)lval;
401 memcpy(field, &ival, sizeof(ival));
402 }
from_zval_write_net_uint16(const zval * arr_value,char * field,ser_context * ctx)403 static void from_zval_write_net_uint16(const zval *arr_value, char *field, ser_context *ctx)
404 {
405 zend_long lval;
406 uint16_t ival;
407
408 lval = from_zval_integer_common(arr_value, ctx);
409 if (ctx->err.has_error) {
410 return;
411 }
412
413 if (lval < 0 || lval > 0xFFFF) {
414 do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
415 "for an unsigned 16-bit integer");
416 return;
417 }
418
419 ival = htons((uint16_t)lval);
420 memcpy(field, &ival, sizeof(ival));
421 }
from_zval_write_sa_family(const zval * arr_value,char * field,ser_context * ctx)422 static void from_zval_write_sa_family(const zval *arr_value, char *field, ser_context *ctx)
423 {
424 zend_long lval;
425 sa_family_t ival;
426
427 lval = from_zval_integer_common(arr_value, ctx);
428 if (ctx->err.has_error) {
429 return;
430 }
431
432 if (lval < 0 || lval > (sa_family_t)-1) { /* sa_family_t is unsigned */
433 do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
434 "for a sa_family_t value");
435 return;
436 }
437
438 ival = (sa_family_t)lval;
439 memcpy(field, &ival, sizeof(ival));
440 }
from_zval_write_pid_t(const zval * arr_value,char * field,ser_context * ctx)441 static void from_zval_write_pid_t(const zval *arr_value, char *field, ser_context *ctx)
442 {
443 zend_long lval;
444 pid_t ival;
445
446 lval = from_zval_integer_common(arr_value, ctx);
447 if (ctx->err.has_error) {
448 return;
449 }
450
451 if (lval < 0 || (pid_t)lval != lval) { /* pid_t is signed */
452 do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
453 "for a pid_t value");
454 return;
455 }
456
457 ival = (pid_t)lval;
458 memcpy(field, &ival, sizeof(ival));
459 }
from_zval_write_uid_t(const zval * arr_value,char * field,ser_context * ctx)460 static void from_zval_write_uid_t(const zval *arr_value, char *field, ser_context *ctx)
461 {
462 zend_long lval;
463 uid_t ival;
464
465 lval = from_zval_integer_common(arr_value, ctx);
466 if (ctx->err.has_error) {
467 return;
468 }
469
470 /* uid_t can be signed or unsigned (generally unsigned) */
471 if ((uid_t)-1 > (uid_t)0) {
472 if (sizeof(zend_long) > sizeof(uid_t) && (lval < 0 || (uid_t)lval != lval)) {
473 do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
474 "for a uid_t value");
475 return;
476 }
477 } else {
478 if (sizeof(zend_long) > sizeof(uid_t) && (uid_t)lval != lval) {
479 do_from_zval_err(ctx, "%s", "given PHP integer is out of bounds "
480 "for a uid_t value");
481 return;
482 }
483 }
484
485 ival = (uid_t)lval;
486 memcpy(field, &ival, sizeof(ival));
487 }
488
to_zval_read_int(const char * data,zval * zv,res_context * ctx)489 void to_zval_read_int(const char *data, zval *zv, res_context *ctx)
490 {
491 int ival;
492 memcpy(&ival, data, sizeof(ival));
493
494 ZVAL_LONG(zv, (zend_long)ival);
495 }
to_zval_read_unsigned(const char * data,zval * zv,res_context * ctx)496 static void to_zval_read_unsigned(const char *data, zval *zv, res_context *ctx)
497 {
498 unsigned ival;
499 memcpy(&ival, data, sizeof(ival));
500
501 ZVAL_LONG(zv, (zend_long)ival);
502 }
to_zval_read_net_uint16(const char * data,zval * zv,res_context * ctx)503 static void to_zval_read_net_uint16(const char *data, zval *zv, res_context *ctx)
504 {
505 uint16_t ival;
506 memcpy(&ival, data, sizeof(ival));
507
508 ZVAL_LONG(zv, (zend_long)ntohs(ival));
509 }
to_zval_read_uint32(const char * data,zval * zv,res_context * ctx)510 static void to_zval_read_uint32(const char *data, zval *zv, res_context *ctx)
511 {
512 uint32_t ival;
513 memcpy(&ival, data, sizeof(ival));
514
515 ZVAL_LONG(zv, (zend_long)ival);
516 }
to_zval_read_sa_family(const char * data,zval * zv,res_context * ctx)517 static void to_zval_read_sa_family(const char *data, zval *zv, res_context *ctx)
518 {
519 sa_family_t ival;
520 memcpy(&ival, data, sizeof(ival));
521
522 ZVAL_LONG(zv, (zend_long)ival);
523 }
to_zval_read_pid_t(const char * data,zval * zv,res_context * ctx)524 static void to_zval_read_pid_t(const char *data, zval *zv, res_context *ctx)
525 {
526 pid_t ival;
527 memcpy(&ival, data, sizeof(ival));
528
529 ZVAL_LONG(zv, (zend_long)ival);
530 }
to_zval_read_uid_t(const char * data,zval * zv,res_context * ctx)531 static void to_zval_read_uid_t(const char *data, zval *zv, res_context *ctx)
532 {
533 uid_t ival;
534 memcpy(&ival, data, sizeof(ival));
535
536 ZVAL_LONG(zv, (zend_long)ival);
537 }
538
539 /* CONVERSIONS for sockaddr */
from_zval_write_sin_addr(const zval * zaddr_str,char * inaddr,ser_context * ctx)540 static void from_zval_write_sin_addr(const zval *zaddr_str, char *inaddr, ser_context *ctx)
541 {
542 int res;
543 struct sockaddr_in saddr = {0};
544 zend_string *addr_str, *tmp_addr_str;
545
546 addr_str = zval_get_tmp_string((zval *) zaddr_str, &tmp_addr_str);
547 res = php_set_inet_addr(&saddr, ZSTR_VAL(addr_str), ctx->sock);
548 if (res) {
549 memcpy(inaddr, &saddr.sin_addr, sizeof saddr.sin_addr);
550 } else {
551 /* error already emitted, but let's emit another more relevant */
552 do_from_zval_err(ctx, "could not resolve address '%s' to get an AF_INET "
553 "address", ZSTR_VAL(addr_str));
554 }
555
556 zend_tmp_string_release(tmp_addr_str);
557 }
to_zval_read_sin_addr(const char * data,zval * zv,res_context * ctx)558 static void to_zval_read_sin_addr(const char *data, zval *zv, res_context *ctx)
559 {
560 const struct in_addr *addr = (const struct in_addr *)data;
561 socklen_t size = INET_ADDRSTRLEN;
562 zend_string *str = zend_string_alloc(size - 1, 0);
563 memset(ZSTR_VAL(str), '\0', size);
564
565 ZVAL_NEW_STR(zv, str);
566
567 if (inet_ntop(AF_INET, addr, Z_STRVAL_P(zv), size) == NULL) {
568 do_to_zval_err(ctx, "could not convert IPv4 address to string "
569 "(errno %d)", errno);
570 return;
571 }
572
573 Z_STRLEN_P(zv) = strlen(Z_STRVAL_P(zv));
574 }
575 static const field_descriptor descriptors_sockaddr_in[] = {
576 {"family", sizeof("family"), 0, offsetof(struct sockaddr_in, sin_family), from_zval_write_sa_family, to_zval_read_sa_family},
577 {"addr", sizeof("addr"), 0, offsetof(struct sockaddr_in, sin_addr), from_zval_write_sin_addr, to_zval_read_sin_addr},
578 {"port", sizeof("port"), 0, offsetof(struct sockaddr_in, sin_port), from_zval_write_net_uint16, to_zval_read_net_uint16},
579 {0}
580 };
from_zval_write_sockaddr_in(const zval * container,char * sockaddr,ser_context * ctx)581 static void from_zval_write_sockaddr_in(const zval *container, char *sockaddr, ser_context *ctx)
582 {
583 from_zval_write_aggregation(container, sockaddr, descriptors_sockaddr_in, ctx);
584 }
to_zval_read_sockaddr_in(const char * data,zval * zv,res_context * ctx)585 static void to_zval_read_sockaddr_in(const char *data, zval *zv, res_context *ctx)
586 {
587 to_zval_read_aggregation(data, zv, descriptors_sockaddr_in, ctx);
588 }
589 #if HAVE_IPV6
from_zval_write_sin6_addr(const zval * zaddr_str,char * addr6,ser_context * ctx)590 static void from_zval_write_sin6_addr(const zval *zaddr_str, char *addr6, ser_context *ctx)
591 {
592 int res;
593 struct sockaddr_in6 saddr6 = {0};
594 zend_string *addr_str, *tmp_addr_str;
595
596 addr_str = zval_get_tmp_string((zval *) zaddr_str, &tmp_addr_str);
597 res = php_set_inet6_addr(&saddr6, ZSTR_VAL(addr_str), ctx->sock);
598 if (res) {
599 memcpy(addr6, &saddr6.sin6_addr, sizeof saddr6.sin6_addr);
600 } else {
601 /* error already emitted, but let's emit another more relevant */
602 do_from_zval_err(ctx, "could not resolve address '%s' to get an AF_INET6 "
603 "address", Z_STRVAL_P(zaddr_str));
604 }
605
606 zend_tmp_string_release(tmp_addr_str);
607 }
to_zval_read_sin6_addr(const char * data,zval * zv,res_context * ctx)608 static void to_zval_read_sin6_addr(const char *data, zval *zv, res_context *ctx)
609 {
610 const struct in6_addr *addr = (const struct in6_addr *)data;
611 socklen_t size = INET6_ADDRSTRLEN;
612 zend_string *str = zend_string_alloc(size - 1, 0);
613
614 memset(ZSTR_VAL(str), '\0', size);
615
616 ZVAL_NEW_STR(zv, str);
617
618 if (inet_ntop(AF_INET6, addr, Z_STRVAL_P(zv), size) == NULL) {
619 do_to_zval_err(ctx, "could not convert IPv6 address to string "
620 "(errno %d)", errno);
621 return;
622 }
623
624 Z_STRLEN_P(zv) = strlen(Z_STRVAL_P(zv));
625 }
626 static const field_descriptor descriptors_sockaddr_in6[] = {
627 {"family", sizeof("family"), 0, offsetof(struct sockaddr_in6, sin6_family), from_zval_write_sa_family, to_zval_read_sa_family},
628 {"addr", sizeof("addr"), 0, offsetof(struct sockaddr_in6, sin6_addr), from_zval_write_sin6_addr, to_zval_read_sin6_addr},
629 {"port", sizeof("port"), 0, offsetof(struct sockaddr_in6, sin6_port), from_zval_write_net_uint16, to_zval_read_net_uint16},
630 {"flowinfo", sizeof("flowinfo"), 0, offsetof(struct sockaddr_in6, sin6_flowinfo), from_zval_write_uint32, to_zval_read_uint32},
631 {"scope_id", sizeof("scope_id"), 0, offsetof(struct sockaddr_in6, sin6_scope_id), from_zval_write_uint32, to_zval_read_uint32},
632 {0}
633 };
from_zval_write_sockaddr_in6(const zval * container,char * sockaddr6,ser_context * ctx)634 static void from_zval_write_sockaddr_in6(const zval *container, char *sockaddr6, ser_context *ctx)
635 {
636 from_zval_write_aggregation(container, sockaddr6, descriptors_sockaddr_in6, ctx);
637 }
to_zval_read_sockaddr_in6(const char * data,zval * zv,res_context * ctx)638 static void to_zval_read_sockaddr_in6(const char *data, zval *zv, res_context *ctx)
639 {
640 to_zval_read_aggregation(data, zv, descriptors_sockaddr_in6, ctx);
641 }
642 #endif /* HAVE_IPV6 */
from_zval_write_sun_path(const zval * path,char * sockaddr_un_c,ser_context * ctx)643 static void from_zval_write_sun_path(const zval *path, char *sockaddr_un_c, ser_context *ctx)
644 {
645 zend_string *path_str, *tmp_path_str;
646 struct sockaddr_un *saddr = (struct sockaddr_un*)sockaddr_un_c;
647
648 path_str = zval_get_tmp_string((zval *) path, &tmp_path_str);
649
650 /* code in this file relies on the path being nul terminated, even though
651 * this is not required, at least on linux for abstract paths. It also
652 * assumes that the path is not empty */
653 if (ZSTR_LEN(path_str) == 0) {
654 do_from_zval_err(ctx, "%s", "the path is cannot be empty");
655 zend_tmp_string_release(tmp_path_str);
656 return;
657 }
658 if (ZSTR_LEN(path_str) >= sizeof(saddr->sun_path)) {
659 do_from_zval_err(ctx, "the path is too long, the maximum permitted "
660 "length is %zd", sizeof(saddr->sun_path) - 1);
661 zend_tmp_string_release(tmp_path_str);
662 return;
663 }
664
665 memcpy(&saddr->sun_path, ZSTR_VAL(path_str), ZSTR_LEN(path_str));
666 saddr->sun_path[ZSTR_LEN(path_str)] = '\0';
667
668 zend_tmp_string_release(tmp_path_str);
669 }
to_zval_read_sun_path(const char * data,zval * zv,res_context * ctx)670 static void to_zval_read_sun_path(const char *data, zval *zv, res_context *ctx) {
671 struct sockaddr_un *saddr = (struct sockaddr_un*)data;
672 char *nul_pos;
673
674 nul_pos = memchr(&saddr->sun_path, '\0', sizeof(saddr->sun_path));
675 if (nul_pos == NULL) {
676 do_to_zval_err(ctx, "could not find a NUL in the path");
677 return;
678 }
679
680 ZVAL_STRINGL(zv, saddr->sun_path, nul_pos - (char*)&saddr->sun_path);
681 }
682 static const field_descriptor descriptors_sockaddr_un[] = {
683 {"family", sizeof("family"), 0, offsetof(struct sockaddr_un, sun_family), from_zval_write_sa_family, to_zval_read_sa_family},
684 {"path", sizeof("path"), 0, 0, from_zval_write_sun_path, to_zval_read_sun_path},
685 {0}
686 };
from_zval_write_sockaddr_un(const zval * container,char * sockaddr,ser_context * ctx)687 static void from_zval_write_sockaddr_un(const zval *container, char *sockaddr, ser_context *ctx)
688 {
689 from_zval_write_aggregation(container, sockaddr, descriptors_sockaddr_un, ctx);
690 }
to_zval_read_sockaddr_un(const char * data,zval * zv,res_context * ctx)691 static void to_zval_read_sockaddr_un(const char *data, zval *zv, res_context *ctx)
692 {
693 to_zval_read_aggregation(data, zv, descriptors_sockaddr_un, ctx);
694 }
from_zval_write_sockaddr_aux(const zval * container,struct sockaddr ** sockaddr_ptr,socklen_t * sockaddr_len,ser_context * ctx)695 static void from_zval_write_sockaddr_aux(const zval *container,
696 struct sockaddr **sockaddr_ptr,
697 socklen_t *sockaddr_len,
698 ser_context *ctx)
699 {
700 int family;
701 zval *elem;
702 int fill_sockaddr;
703
704 if (Z_TYPE_P(container) != IS_ARRAY) {
705 do_from_zval_err(ctx, "%s", "expected an array here");
706 return;
707 }
708
709 fill_sockaddr = param_get_bool(ctx, KEY_FILL_SOCKADDR, 1);
710
711 if ((elem = zend_hash_str_find(Z_ARRVAL_P(container), "family", sizeof("family") - 1)) != NULL
712 && Z_TYPE_P(elem) != IS_NULL) {
713 const char *node = "family";
714 zend_llist_add_element(&ctx->keys, &node);
715 from_zval_write_int(elem, (char*)&family, ctx);
716 zend_llist_remove_tail(&ctx->keys);
717 } else {
718 family = ctx->sock->type;
719 }
720
721 switch (family) {
722 case AF_INET:
723 /* though not all OSes support sockaddr_in used in IPv6 sockets */
724 if (ctx->sock->type != AF_INET && ctx->sock->type != AF_INET6) {
725 do_from_zval_err(ctx, "the specified family (number %d) is not "
726 "supported on this socket", family);
727 return;
728 }
729 *sockaddr_ptr = accounted_ecalloc(1, sizeof(struct sockaddr_in), ctx);
730 *sockaddr_len = sizeof(struct sockaddr_in);
731 if (fill_sockaddr) {
732 from_zval_write_sockaddr_in(container, (char*)*sockaddr_ptr, ctx);
733 (*sockaddr_ptr)->sa_family = AF_INET;
734 }
735 break;
736
737 #if HAVE_IPV6
738 case AF_INET6:
739 if (ctx->sock->type != AF_INET6) {
740 do_from_zval_err(ctx, "the specified family (AF_INET6) is not "
741 "supported on this socket");
742 return;
743 }
744 *sockaddr_ptr = accounted_ecalloc(1, sizeof(struct sockaddr_in6), ctx);
745 *sockaddr_len = sizeof(struct sockaddr_in6);
746 if (fill_sockaddr) {
747 from_zval_write_sockaddr_in6(container, (char*)*sockaddr_ptr, ctx);
748 (*sockaddr_ptr)->sa_family = AF_INET6;
749 }
750 break;
751 #endif /* HAVE_IPV6 */
752
753 case AF_UNIX:
754 if (ctx->sock->type != AF_UNIX) {
755 do_from_zval_err(ctx, "the specified family (AF_UNIX) is not "
756 "supported on this socket");
757 return;
758 }
759 *sockaddr_ptr = accounted_ecalloc(1, sizeof(struct sockaddr_un), ctx);
760 if (fill_sockaddr) {
761 struct sockaddr_un *sock_un = (struct sockaddr_un*)*sockaddr_ptr;
762
763 from_zval_write_sockaddr_un(container, (char*)*sockaddr_ptr, ctx);
764 (*sockaddr_ptr)->sa_family = AF_UNIX;
765
766 /* calculating length is more complicated here. Giving the size of
767 * struct sockaddr_un here and relying on the nul termination of
768 * sun_path does not work for paths in the abstract namespace. Note
769 * that we always assume the path is not empty and nul terminated */
770 *sockaddr_len = offsetof(struct sockaddr_un, sun_path) +
771 (sock_un->sun_path[0] == '\0'
772 ? (1 + strlen(&sock_un->sun_path[1]))
773 : strlen(sock_un->sun_path));
774 } else {
775 *sockaddr_len = sizeof(struct sockaddr_un);
776 }
777 break;
778
779 default:
780 do_from_zval_err(ctx, "%s", "the only families currently supported are "
781 "AF_INET, AF_INET6 and AF_UNIX");
782 break;
783 }
784 }
to_zval_read_sockaddr_aux(const char * sockaddr_c,zval * zv,res_context * ctx)785 static void to_zval_read_sockaddr_aux(const char *sockaddr_c, zval *zv, res_context *ctx)
786 {
787 const struct sockaddr *saddr = (struct sockaddr *)sockaddr_c;
788
789 if (saddr->sa_family == 0) {
790 ZVAL_NULL(zv);
791 return;
792 }
793
794 array_init(zv);
795
796 switch (saddr->sa_family) {
797 case AF_INET:
798 to_zval_read_sockaddr_in(sockaddr_c, zv, ctx);
799 break;
800
801 #if HAVE_IPV6
802 case AF_INET6:
803 to_zval_read_sockaddr_in6(sockaddr_c, zv, ctx);
804 break;
805 #endif /* HAVE_IPV6 */
806
807 case AF_UNIX:
808 to_zval_read_sockaddr_un(sockaddr_c, zv, ctx);
809 break;
810
811 default:
812 do_to_zval_err(ctx, "cannot read struct sockaddr with family %d; "
813 "not supported",
814 (int)saddr->sa_family);
815 break;
816 }
817 }
818
819 /* CONVERSIONS for cmsghdr */
820 /*
821 * [ level => , type => , data => [],]
822 * struct cmsghdr {
823 * socklen_t cmsg_len; // data byte count, including header
824 * int cmsg_level; // originating protocol
825 * int cmsg_type; // protocol-specific type
826 * // followed by unsigned char cmsg_data[];
827 * };
828 */
from_zval_write_control(const zval * arr,void ** control_buf,zend_llist_element * alloc,size_t * control_len,size_t * offset,ser_context * ctx)829 static void from_zval_write_control(const zval *arr,
830 void **control_buf,
831 zend_llist_element *alloc,
832 size_t *control_len,
833 size_t *offset,
834 ser_context *ctx)
835 {
836 struct cmsghdr *cmsghdr;
837 int level,
838 type;
839 size_t data_len,
840 req_space,
841 space_left;
842 ancillary_reg_entry *entry;
843
844 static const field_descriptor descriptor_level[] = {
845 {"level", sizeof("level"), 0, 0, from_zval_write_int, 0},
846 {0}
847 };
848 static const field_descriptor descriptor_type[] = {
849 {"type", sizeof("type"), 0, 0, from_zval_write_int, 0},
850 {0}
851 };
852 field_descriptor descriptor_data[] = {
853 {"data", sizeof("data"), 0, 0, 0, 0},
854 {0}
855 };
856
857 from_zval_write_aggregation(arr, (char *)&level, descriptor_level, ctx);
858 if (ctx->err.has_error) {
859 return;
860 }
861 from_zval_write_aggregation(arr, (char *)&type, descriptor_type, ctx);
862 if (ctx->err.has_error) {
863 return;
864 }
865
866 entry = get_ancillary_reg_entry(level, type);
867 if (entry == NULL) {
868 do_from_zval_err(ctx, "cmsghdr with level %d and type %d not supported",
869 level, type);
870 return;
871 }
872
873 if (entry->calc_space) {
874 zval *data_elem;
875 /* arr must be an array at this point */
876 if ((data_elem = zend_hash_str_find(Z_ARRVAL_P(arr), "data", sizeof("data") - 1)) == NULL) {
877 do_from_zval_err(ctx, "cmsghdr should have a 'data' element here");
878 return;
879 }
880 data_len = entry->calc_space(data_elem, ctx);
881 if (ctx->err.has_error) {
882 return;
883 }
884 } else {
885 data_len = entry->size;
886 }
887 req_space = CMSG_SPACE(data_len);
888 space_left = *control_len - *offset;
889 assert(*control_len >= *offset);
890
891 if (space_left < req_space) {
892 *control_buf = safe_erealloc(*control_buf, 2, req_space, *control_len);
893 *control_len += 2 * req_space;
894 memset((char *)*control_buf + *offset, '\0', *control_len - *offset);
895 memcpy(&alloc->data, control_buf, sizeof *control_buf);
896 }
897
898 cmsghdr = (struct cmsghdr*)(((char*)*control_buf) + *offset);
899 cmsghdr->cmsg_level = level;
900 cmsghdr->cmsg_type = type;
901 cmsghdr->cmsg_len = CMSG_LEN(data_len);
902
903 descriptor_data[0].from_zval = entry->from_array;
904 from_zval_write_aggregation(arr, (char*)CMSG_DATA(cmsghdr), descriptor_data, ctx);
905
906 *offset += req_space;
907 }
from_zval_write_control_array(const zval * arr,char * msghdr_c,ser_context * ctx)908 static void from_zval_write_control_array(const zval *arr, char *msghdr_c, ser_context *ctx)
909 {
910 char buf[sizeof("element #4294967295")];
911 char *bufp = buf;
912 zval *elem;
913 uint32_t i = 0;
914 int num_elems;
915 void *control_buf;
916 zend_llist_element *alloc;
917 size_t control_len,
918 cur_offset;
919 struct msghdr *msg = (struct msghdr*)msghdr_c;
920
921 if (Z_TYPE_P(arr) != IS_ARRAY) {
922 do_from_zval_err(ctx, "%s", "expected an array here");
923 return;
924 }
925
926 num_elems = zend_hash_num_elements(Z_ARRVAL_P(arr));
927 if (num_elems == 0) {
928 return;
929 }
930
931 /* estimate each message at 20 bytes */
932 control_buf = accounted_safe_ecalloc(num_elems, CMSG_SPACE(20), 0, ctx);
933 alloc = ctx->allocations.tail;
934 control_len = (size_t)num_elems * CMSG_SPACE(20);
935 cur_offset = 0;
936
937 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(arr), elem) {
938 if (ctx->err.has_error) {
939 break;
940 }
941
942 if ((size_t)snprintf(buf, sizeof(buf), "element #%u", (unsigned)i++) >= sizeof(buf)) {
943 memcpy(buf, "element", sizeof("element"));
944 }
945 zend_llist_add_element(&ctx->keys, &bufp);
946
947 from_zval_write_control(elem, &control_buf, alloc, &control_len, &cur_offset, ctx);
948
949 zend_llist_remove_tail(&ctx->keys);
950 } ZEND_HASH_FOREACH_END();
951
952 msg->msg_control = control_buf;
953 msg->msg_controllen = cur_offset; /* not control_len, which may be larger */
954 }
to_zval_read_cmsg_data(const char * cmsghdr_c,zval * zv,res_context * ctx)955 static void to_zval_read_cmsg_data(const char *cmsghdr_c, zval *zv, res_context *ctx)
956 {
957 const struct cmsghdr *cmsg = (const struct cmsghdr *)cmsghdr_c;
958 ancillary_reg_entry *entry;
959 size_t len,
960 *len_p = &len;
961
962 entry = get_ancillary_reg_entry(cmsg->cmsg_level, cmsg->cmsg_type);
963 if (entry == NULL) {
964 do_to_zval_err(ctx, "cmsghdr with level %d and type %d not supported",
965 cmsg->cmsg_level, cmsg->cmsg_type);
966 return;
967 }
968 if (CMSG_LEN(entry->size) > cmsg->cmsg_len) {
969 do_to_zval_err(ctx, "the cmsghdr structure is unexpectedly small; "
970 "expected a length of at least " ZEND_LONG_FMT ", but got " ZEND_LONG_FMT,
971 (zend_long)CMSG_LEN(entry->size), (zend_long)cmsg->cmsg_len);
972 return;
973 }
974
975 len = (size_t)cmsg->cmsg_len; /* use another var because type of cmsg_len varies */
976
977 if (zend_hash_str_add_ptr(&ctx->params, KEY_CMSG_LEN, sizeof(KEY_CMSG_LEN) - 1, len_p) == NULL) {
978 do_to_zval_err(ctx, "%s", "could not set parameter " KEY_CMSG_LEN);
979 return;
980 }
981
982 entry->to_array((const char *)CMSG_DATA(cmsg), zv, ctx);
983
984 zend_hash_str_del(&ctx->params, KEY_CMSG_LEN, sizeof(KEY_CMSG_LEN) - 1);
985 }
to_zval_read_control(const char * cmsghdr_c,zval * zv,res_context * ctx)986 static void to_zval_read_control(const char *cmsghdr_c, zval *zv, res_context *ctx)
987 {
988 /* takes a cmsghdr, not a msghdr like from_zval_write_control */
989 static const field_descriptor descriptors[] = {
990 {"level", sizeof("level"), 0, offsetof(struct cmsghdr, cmsg_level), 0, to_zval_read_int},
991 {"type", sizeof("type"), 0, offsetof(struct cmsghdr, cmsg_type), 0, to_zval_read_int},
992 {"data", sizeof("data"), 0, 0 /* cmsghdr passed */, 0, to_zval_read_cmsg_data},
993 {0}
994 };
995
996 array_init_size(zv, 3);
997 to_zval_read_aggregation(cmsghdr_c, zv, descriptors, ctx);
998 }
to_zval_read_control_array(const char * msghdr_c,zval * zv,res_context * ctx)999 static void to_zval_read_control_array(const char *msghdr_c, zval *zv, res_context *ctx)
1000 {
1001 struct msghdr *msg = (struct msghdr *)msghdr_c;
1002 struct cmsghdr *cmsg;
1003 char buf[sizeof("element #4294967295")];
1004 char *bufp = buf;
1005 uint32_t i = 1;
1006
1007 /*if (msg->msg_flags & MSG_CTRUNC) {
1008 php_error_docref0(NULL, E_WARNING, "The MSG_CTRUNC flag is present; will not "
1009 "attempt to read control messages");
1010 ZVAL_FALSE(zv);
1011 return;
1012 }*/
1013
1014 array_init(zv);
1015
1016 for (cmsg = CMSG_FIRSTHDR(msg);
1017 cmsg != NULL && !ctx->err.has_error;
1018 cmsg = CMSG_NXTHDR(msg, cmsg)) {
1019 zval *elem, tmp;
1020
1021 ZVAL_NULL(&tmp);
1022 elem = zend_hash_next_index_insert(Z_ARRVAL_P(zv), &tmp);
1023
1024 if ((size_t)snprintf(buf, sizeof(buf), "element #%u", (unsigned)i++) >= sizeof(buf)) {
1025 memcpy(buf, "element", sizeof("element"));
1026 }
1027 zend_llist_add_element(&ctx->keys, &bufp);
1028
1029 to_zval_read_control((const char *)cmsg, elem, ctx);
1030
1031 zend_llist_remove_tail(&ctx->keys);
1032 }
1033 }
1034
1035 /* CONVERSIONS for msghdr */
from_zval_write_name(const zval * zname_arr,char * msghdr_c,ser_context * ctx)1036 static void from_zval_write_name(const zval *zname_arr, char *msghdr_c, ser_context *ctx)
1037 {
1038 struct sockaddr *sockaddr;
1039 socklen_t sockaddr_len;
1040 struct msghdr *msghdr = (struct msghdr *)msghdr_c;
1041
1042 from_zval_write_sockaddr_aux(zname_arr, &sockaddr, &sockaddr_len, ctx);
1043
1044 msghdr->msg_name = sockaddr;
1045 msghdr->msg_namelen = sockaddr_len;
1046 }
to_zval_read_name(const char * sockaddr_p,zval * zv,res_context * ctx)1047 static void to_zval_read_name(const char *sockaddr_p, zval *zv, res_context *ctx)
1048 {
1049 void *name = (void*)*(void**)sockaddr_p;
1050 if (name == NULL) {
1051 ZVAL_NULL(zv);
1052 } else {
1053 to_zval_read_sockaddr_aux(name, zv, ctx);
1054 }
1055 }
from_zval_write_msghdr_buffer_size(const zval * elem,char * msghdr_c,ser_context * ctx)1056 static void from_zval_write_msghdr_buffer_size(const zval *elem, char *msghdr_c, ser_context *ctx)
1057 {
1058 zend_long lval;
1059 struct msghdr *msghdr = (struct msghdr *)msghdr_c;
1060
1061 lval = from_zval_integer_common(elem, ctx);
1062 if (ctx->err.has_error) {
1063 return;
1064 }
1065
1066 if (lval < 0 || (zend_ulong)lval > MAX_USER_BUFF_SIZE) {
1067 do_from_zval_err(ctx, "the buffer size must be between 1 and " ZEND_LONG_FMT "; "
1068 "given " ZEND_LONG_FMT, (zend_long)MAX_USER_BUFF_SIZE, lval);
1069 return;
1070 }
1071
1072 msghdr->msg_iovlen = 1;
1073 msghdr->msg_iov = accounted_emalloc(sizeof(*msghdr->msg_iov) * 1, ctx);
1074 msghdr->msg_iov[0].iov_base = accounted_emalloc((size_t)lval, ctx);
1075 msghdr->msg_iov[0].iov_len = (size_t)lval;
1076 }
from_zval_write_iov_array_aux(zval * elem,unsigned i,void ** args,ser_context * ctx)1077 static void from_zval_write_iov_array_aux(zval *elem, unsigned i, void **args, ser_context *ctx)
1078 {
1079 struct msghdr *msg = args[0];
1080 zend_string *str, *tmp_str;
1081
1082 str = zval_get_tmp_string(elem, &tmp_str);
1083
1084 msg->msg_iov[i - 1].iov_base = accounted_emalloc(ZSTR_LEN(str), ctx);
1085 msg->msg_iov[i - 1].iov_len = ZSTR_LEN(str);
1086 memcpy(msg->msg_iov[i - 1].iov_base, ZSTR_VAL(str), ZSTR_LEN(str));
1087
1088 zend_tmp_string_release(tmp_str);
1089 }
from_zval_write_iov_array(const zval * arr,char * msghdr_c,ser_context * ctx)1090 static void from_zval_write_iov_array(const zval *arr, char *msghdr_c, ser_context *ctx)
1091 {
1092 int num_elem;
1093 struct msghdr *msg = (struct msghdr*)msghdr_c;
1094
1095 if (Z_TYPE_P(arr) != IS_ARRAY) {
1096 do_from_zval_err(ctx, "%s", "expected an array here");
1097 return;
1098 }
1099
1100 num_elem = zend_hash_num_elements(Z_ARRVAL_P(arr));
1101 if (num_elem == 0) {
1102 return;
1103 }
1104
1105 msg->msg_iov = accounted_safe_ecalloc(num_elem, sizeof *msg->msg_iov, 0, ctx);
1106 msg->msg_iovlen = (size_t)num_elem;
1107
1108 from_array_iterate(arr, from_zval_write_iov_array_aux, (void**)&msg, ctx);
1109 }
from_zval_write_controllen(const zval * elem,char * msghdr_c,ser_context * ctx)1110 static void from_zval_write_controllen(const zval *elem, char *msghdr_c, ser_context *ctx)
1111 {
1112 struct msghdr *msghdr = (struct msghdr *)msghdr_c;
1113 uint32_t len;
1114
1115 /* controllen should be an unsigned with at least 32-bit. Let's assume
1116 * this least common denominator
1117 */
1118 from_zval_write_uint32(elem, (char*)&len, ctx);
1119 if (!ctx->err.has_error && len == 0) {
1120 do_from_zval_err(ctx, "controllen cannot be 0");
1121 return;
1122 }
1123 msghdr->msg_control = accounted_emalloc(len, ctx);
1124 msghdr->msg_controllen = len;
1125 }
from_zval_write_msghdr_send(const zval * container,char * msghdr_c,ser_context * ctx)1126 void from_zval_write_msghdr_send(const zval *container, char *msghdr_c, ser_context *ctx)
1127 {
1128 static const field_descriptor descriptors[] = {
1129 {"name", sizeof("name"), 0, 0, from_zval_write_name, 0},
1130 {"iov", sizeof("iov"), 0, 0, from_zval_write_iov_array, 0},
1131 {"control", sizeof("control"), 0, 0, from_zval_write_control_array, 0},
1132 {0}
1133 };
1134
1135 from_zval_write_aggregation(container, msghdr_c, descriptors, ctx);
1136 }
from_zval_write_msghdr_recv(const zval * container,char * msghdr_c,ser_context * ctx)1137 void from_zval_write_msghdr_recv(const zval *container, char *msghdr_c, ser_context *ctx)
1138 {
1139 /* zval to struct msghdr, version for recvmsg(). It differs from the version
1140 * for sendmsg() in that it:
1141 * - has a buffer_size instead of an iov array;
1142 * - has no control element; has a controllen element instead
1143 * struct msghdr {
1144 * void *msg_name;
1145 * socklen_t msg_namelen;
1146 * struct iovec *msg_iov;
1147 * size_t msg_iovlen;
1148 * void *msg_control;
1149 * size_t msg_controllen; //can also be socklen_t
1150 * int msg_flags;
1151 * };
1152 */
1153 static const field_descriptor descriptors[] = {
1154 {"name", sizeof("name"), 0, 0, from_zval_write_name, 0},
1155 {"buffer_size", sizeof("buffer_size"), 0, 0, from_zval_write_msghdr_buffer_size, 0},
1156 {"controllen", sizeof("controllen"), 1, 0, from_zval_write_controllen, 0},
1157 {0}
1158 };
1159 struct msghdr *msghdr = (struct msghdr *)msghdr_c;
1160 const int falsev = 0,
1161 *falsevp = &falsev;
1162
1163 if (zend_hash_str_add_ptr(&ctx->params, KEY_FILL_SOCKADDR, sizeof(KEY_FILL_SOCKADDR) - 1, (void *)falsevp) == NULL) {
1164 do_from_zval_err(ctx, "could not add fill_sockaddr; this is a bug");
1165 return;
1166 }
1167
1168 from_zval_write_aggregation(container, msghdr_c, descriptors, ctx);
1169
1170 zend_hash_str_del(&ctx->params, KEY_FILL_SOCKADDR, sizeof(KEY_FILL_SOCKADDR) - 1);
1171 if (ctx->err.has_error) {
1172 return;
1173 }
1174
1175 if (msghdr->msg_iovlen == 0) {
1176 msghdr->msg_iovlen = 1;
1177 msghdr->msg_iov = accounted_emalloc(sizeof(*msghdr->msg_iov) * 1, ctx);
1178 msghdr->msg_iov[0].iov_base = accounted_emalloc((size_t)DEFAULT_BUFF_SIZE, ctx);
1179 msghdr->msg_iov[0].iov_len = (size_t)DEFAULT_BUFF_SIZE;
1180 }
1181 }
1182
to_zval_read_iov(const char * msghdr_c,zval * zv,res_context * ctx)1183 static void to_zval_read_iov(const char *msghdr_c, zval *zv, res_context *ctx)
1184 {
1185 const struct msghdr *msghdr = (const struct msghdr *)msghdr_c;
1186 size_t iovlen = msghdr->msg_iovlen;
1187 ssize_t *recvmsg_ret,
1188 bytes_left;
1189 uint32_t i;
1190
1191 if (iovlen > UINT_MAX) {
1192 do_to_zval_err(ctx, "unexpectedly large value for iov_len: %lu",
1193 (unsigned long)iovlen);
1194 }
1195 array_init_size(zv, (uint32_t)iovlen);
1196
1197 if ((recvmsg_ret = zend_hash_str_find_ptr(&ctx->params, KEY_RECVMSG_RET, sizeof(KEY_RECVMSG_RET) - 1)) == NULL) {
1198 do_to_zval_err(ctx, "recvmsg_ret not found in params. This is a bug");
1199 return;
1200 }
1201 bytes_left = *recvmsg_ret;
1202
1203 for (i = 0; bytes_left > 0 && i < (uint32_t)iovlen; i++) {
1204 zval elem;
1205 size_t len = MIN(msghdr->msg_iov[i].iov_len, (size_t)bytes_left);
1206 zend_string *buf = zend_string_alloc(len, 0);
1207
1208 memcpy(ZSTR_VAL(buf), msghdr->msg_iov[i].iov_base, ZSTR_LEN(buf));
1209 ZSTR_VAL(buf)[ZSTR_LEN(buf)] = '\0';
1210
1211 ZVAL_NEW_STR(&elem, buf);
1212 add_next_index_zval(zv, &elem);
1213 bytes_left -= len;
1214 }
1215 }
to_zval_read_msghdr(const char * msghdr_c,zval * zv,res_context * ctx)1216 void to_zval_read_msghdr(const char *msghdr_c, zval *zv, res_context *ctx)
1217 {
1218 static const field_descriptor descriptors[] = {
1219 {"name", sizeof("name"), 0, offsetof(struct msghdr, msg_name), 0, to_zval_read_name},
1220 {"control", sizeof("control"), 0, 0, 0, to_zval_read_control_array},
1221 {"iov", sizeof("iov"), 0, 0, 0, to_zval_read_iov},
1222 {"flags", sizeof("flags"), 0, offsetof(struct msghdr, msg_flags), 0, to_zval_read_int},
1223 {0}
1224 };
1225
1226 array_init_size(zv, 4);
1227
1228 to_zval_read_aggregation(msghdr_c, zv, descriptors, ctx);
1229 }
1230
1231 /* CONVERSIONS for if_index */
from_zval_write_ifindex(const zval * zv,char * uinteger,ser_context * ctx)1232 static void from_zval_write_ifindex(const zval *zv, char *uinteger, ser_context *ctx)
1233 {
1234 unsigned ret = 0;
1235
1236 if (Z_TYPE_P(zv) == IS_LONG) {
1237 if (Z_LVAL_P(zv) < 0 || (zend_ulong)Z_LVAL_P(zv) > UINT_MAX) { /* allow 0 (unspecified interface) */
1238 do_from_zval_err(ctx, "the interface index cannot be negative or "
1239 "larger than %u; given " ZEND_LONG_FMT, UINT_MAX, Z_LVAL_P(zv));
1240 } else {
1241 ret = (unsigned)Z_LVAL_P(zv);
1242 }
1243 } else {
1244 zend_string *str, *tmp_str;
1245
1246 str = zval_get_tmp_string((zval *) zv, &tmp_str);
1247
1248 #if HAVE_IF_NAMETOINDEX
1249 ret = if_nametoindex(ZSTR_VAL(str));
1250 if (ret == 0) {
1251 do_from_zval_err(ctx, "no interface with name \"%s\" could be found", ZSTR_VAL(str));
1252 }
1253 #elif defined(SIOCGIFINDEX)
1254 {
1255 struct ifreq ifr;
1256 if (strlcpy(ifr.ifr_name, ZSTR_VAL(str), sizeof(ifr.ifr_name))
1257 >= sizeof(ifr.ifr_name)) {
1258 do_from_zval_err(ctx, "the interface name \"%s\" is too large ", ZSTR_VAL(str));
1259 } else if (ioctl(ctx->sock->bsd_socket, SIOCGIFINDEX, &ifr) < 0) {
1260 if (errno == ENODEV) {
1261 do_from_zval_err(ctx, "no interface with name \"%s\" could be "
1262 "found", ZSTR_VAL(str));
1263 } else {
1264 do_from_zval_err(ctx, "error fetching interface index for "
1265 "interface with name \"%s\" (errno %d)",
1266 ZSTR_VAL(str), errno);
1267 }
1268 } else {
1269 ret = (unsigned)ifr.ifr_ifindex;
1270 }
1271 }
1272 #else
1273 do_from_zval_err(ctx,
1274 "this platform does not support looking up an interface by "
1275 "name, an integer interface index must be supplied instead");
1276 #endif
1277
1278 zend_tmp_string_release(tmp_str);
1279 }
1280
1281 if (!ctx->err.has_error) {
1282 memcpy(uinteger, &ret, sizeof(ret));
1283 }
1284 }
1285
1286 /* CONVERSIONS for struct in6_pktinfo */
1287 #if defined(IPV6_PKTINFO) && HAVE_IPV6
1288 static const field_descriptor descriptors_in6_pktinfo[] = {
1289 {"addr", sizeof("addr"), 1, offsetof(struct in6_pktinfo, ipi6_addr), from_zval_write_sin6_addr, to_zval_read_sin6_addr},
1290 {"ifindex", sizeof("ifindex"), 1, offsetof(struct in6_pktinfo, ipi6_ifindex), from_zval_write_ifindex, to_zval_read_unsigned},
1291 {0}
1292 };
from_zval_write_in6_pktinfo(const zval * container,char * in6_pktinfo_c,ser_context * ctx)1293 void from_zval_write_in6_pktinfo(const zval *container, char *in6_pktinfo_c, ser_context *ctx)
1294 {
1295 from_zval_write_aggregation(container, in6_pktinfo_c, descriptors_in6_pktinfo, ctx);
1296 }
to_zval_read_in6_pktinfo(const char * data,zval * zv,res_context * ctx)1297 void to_zval_read_in6_pktinfo(const char *data, zval *zv, res_context *ctx)
1298 {
1299 array_init_size(zv, 2);
1300
1301 to_zval_read_aggregation(data, zv, descriptors_in6_pktinfo, ctx);
1302 }
1303 #endif
1304
1305 /* CONVERSIONS for struct ucred */
1306 #ifdef SO_PASSCRED
1307 static const field_descriptor descriptors_ucred[] = {
1308 {"pid", sizeof("pid"), 1, offsetof(struct ucred, pid), from_zval_write_pid_t, to_zval_read_pid_t},
1309 {"uid", sizeof("uid"), 1, offsetof(struct ucred, uid), from_zval_write_uid_t, to_zval_read_uid_t},
1310 /* assume the type gid_t is the same as uid_t: */
1311 {"gid", sizeof("gid"), 1, offsetof(struct ucred, gid), from_zval_write_uid_t, to_zval_read_uid_t},
1312 {0}
1313 };
from_zval_write_ucred(const zval * container,char * ucred_c,ser_context * ctx)1314 void from_zval_write_ucred(const zval *container, char *ucred_c, ser_context *ctx)
1315 {
1316 from_zval_write_aggregation(container, ucred_c, descriptors_ucred, ctx);
1317 }
to_zval_read_ucred(const char * data,zval * zv,res_context * ctx)1318 void to_zval_read_ucred(const char *data, zval *zv, res_context *ctx)
1319 {
1320 array_init_size(zv, 3);
1321
1322 to_zval_read_aggregation(data, zv, descriptors_ucred, ctx);
1323 }
1324 #endif
1325
1326 /* CONVERSIONS for SCM_RIGHTS */
1327 #ifdef SCM_RIGHTS
calculate_scm_rights_space(const zval * arr,ser_context * ctx)1328 size_t calculate_scm_rights_space(const zval *arr, ser_context *ctx)
1329 {
1330 int num_elems;
1331
1332 if (Z_TYPE_P(arr) != IS_ARRAY) {
1333 do_from_zval_err(ctx, "%s", "expected an array here");
1334 return (size_t)-1;
1335 }
1336
1337 num_elems = zend_hash_num_elements(Z_ARRVAL_P(arr));
1338 if (num_elems == 0) {
1339 do_from_zval_err(ctx, "%s", "expected at least one element in this array");
1340 return (size_t)-1;
1341 }
1342
1343 return zend_hash_num_elements(Z_ARRVAL_P(arr)) * sizeof(int);
1344 }
from_zval_write_fd_array_aux(zval * elem,unsigned i,void ** args,ser_context * ctx)1345 static void from_zval_write_fd_array_aux(zval *elem, unsigned i, void **args, ser_context *ctx)
1346 {
1347 int *iarr = args[0];
1348
1349 if (Z_TYPE_P(elem) == IS_RESOURCE) {
1350 php_stream *stream;
1351 php_socket *sock;
1352
1353 sock = (php_socket *)zend_fetch_resource_ex(elem, NULL, php_sockets_le_socket());
1354 if (sock) {
1355 iarr[i] = sock->bsd_socket;
1356 return;
1357 }
1358
1359 stream = (php_stream *)zend_fetch_resource2_ex(elem, NULL, php_file_le_stream(), php_file_le_pstream());
1360 if (stream == NULL) {
1361 do_from_zval_err(ctx, "resource is not a stream or a socket");
1362 return;
1363 }
1364
1365 if (php_stream_cast(stream, PHP_STREAM_AS_FD, (void **)&iarr[i - 1],
1366 REPORT_ERRORS) == FAILURE) {
1367 do_from_zval_err(ctx, "cast stream to file descriptor failed");
1368 return;
1369 }
1370 } else {
1371 do_from_zval_err(ctx, "expected a resource variable");
1372 }
1373 }
from_zval_write_fd_array(const zval * arr,char * int_arr,ser_context * ctx)1374 void from_zval_write_fd_array(const zval *arr, char *int_arr, ser_context *ctx)
1375 {
1376 if (Z_TYPE_P(arr) != IS_ARRAY) {
1377 do_from_zval_err(ctx, "%s", "expected an array here");
1378 return;
1379 }
1380
1381 from_array_iterate(arr, &from_zval_write_fd_array_aux, (void**)&int_arr, ctx);
1382 }
to_zval_read_fd_array(const char * data,zval * zv,res_context * ctx)1383 void to_zval_read_fd_array(const char *data, zval *zv, res_context *ctx)
1384 {
1385 size_t *cmsg_len;
1386 int num_elems,
1387 i;
1388 struct cmsghdr *dummy_cmsg = 0;
1389 size_t data_offset;
1390
1391 data_offset = (unsigned char *)CMSG_DATA(dummy_cmsg)
1392 - (unsigned char *)dummy_cmsg;
1393
1394 if ((cmsg_len = zend_hash_str_find_ptr(&ctx->params, KEY_CMSG_LEN, sizeof(KEY_CMSG_LEN) - 1)) == NULL) {
1395 do_to_zval_err(ctx, "could not get value of parameter " KEY_CMSG_LEN);
1396 return;
1397 }
1398
1399 if (*cmsg_len < data_offset) {
1400 do_to_zval_err(ctx, "length of cmsg is smaller than its data member "
1401 "offset (" ZEND_LONG_FMT " vs " ZEND_LONG_FMT ")", (zend_long)*cmsg_len, (zend_long)data_offset);
1402 return;
1403 }
1404 num_elems = (*cmsg_len - data_offset) / sizeof(int);
1405
1406 array_init_size(zv, num_elems);
1407
1408 for (i = 0; i < num_elems; i++) {
1409 zval elem;
1410 int fd;
1411 struct stat statbuf;
1412
1413 fd = *((int *)data + i);
1414
1415 /* determine whether we have a socket */
1416 if (fstat(fd, &statbuf) == -1) {
1417 do_to_zval_err(ctx, "error creating resource for received file "
1418 "descriptor %d: fstat() call failed with errno %d", fd, errno);
1419 return;
1420 }
1421 if (S_ISSOCK(statbuf.st_mode)) {
1422 php_socket *sock = socket_import_file_descriptor(fd);
1423 ZVAL_RES(&elem, zend_register_resource(sock, php_sockets_le_socket()));
1424 } else {
1425 php_stream *stream = php_stream_fopen_from_fd(fd, "rw", NULL);
1426 php_stream_to_zval(stream, &elem);
1427 }
1428
1429 add_next_index_zval(zv, &elem);
1430 }
1431 }
1432 #endif
1433
1434 /* ENTRY POINT for conversions */
free_from_zval_allocation(void * alloc_ptr_ptr)1435 static void free_from_zval_allocation(void *alloc_ptr_ptr)
1436 {
1437 efree(*(void**)alloc_ptr_ptr);
1438 }
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)1439 void *from_zval_run_conversions(const zval *container,
1440 php_socket *sock,
1441 from_zval_write_field *writer,
1442 size_t struct_size,
1443 const char *top_name,
1444 zend_llist **allocations /* out */,
1445 struct err_s *err /* in/out */)
1446 {
1447 ser_context ctx;
1448 char *structure;
1449
1450 *allocations = NULL;
1451
1452 if (err->has_error) {
1453 return NULL;
1454 }
1455
1456 memset(&ctx, 0, sizeof(ctx));
1457 zend_hash_init(&ctx.params, 8, NULL, NULL, 0);
1458 zend_llist_init(&ctx.keys, sizeof(const char *), NULL, 0);
1459 zend_llist_init(&ctx.allocations, sizeof(void *), &free_from_zval_allocation, 0);
1460 ctx.sock = sock;
1461
1462 structure = ecalloc(1, struct_size);
1463
1464 zend_llist_add_element(&ctx.keys, &top_name);
1465 zend_llist_add_element(&ctx.allocations, &structure);
1466
1467 /* main call */
1468 writer(container, structure, &ctx);
1469
1470 if (ctx.err.has_error) {
1471 zend_llist_destroy(&ctx.allocations); /* deallocates structure as well */
1472 structure = NULL;
1473 *err = ctx.err;
1474 } else {
1475 *allocations = emalloc(sizeof **allocations);
1476 **allocations = ctx.allocations;
1477 }
1478
1479 zend_llist_destroy(&ctx.keys);
1480 zend_hash_destroy(&ctx.params);
1481
1482 return structure;
1483 }
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)1484 zval *to_zval_run_conversions(const char *structure,
1485 to_zval_read_field *reader,
1486 const char *top_name,
1487 const struct key_value *key_value_pairs,
1488 struct err_s *err, zval *zv)
1489 {
1490 res_context ctx;
1491 const struct key_value *kv;
1492
1493 if (err->has_error) {
1494 return NULL;
1495 }
1496
1497 memset(&ctx, 0, sizeof(ctx));
1498 zend_llist_init(&ctx.keys, sizeof(const char *), NULL, 0);
1499 zend_llist_add_element(&ctx.keys, &top_name);
1500
1501 zend_hash_init(&ctx.params, 8, NULL, NULL, 0);
1502 for (kv = key_value_pairs; kv->key != NULL; kv++) {
1503 zend_hash_str_update_ptr(&ctx.params, kv->key, kv->key_size - 1, kv->value);
1504 }
1505
1506 ZVAL_NULL(zv);
1507 /* main call */
1508 reader(structure, zv, &ctx);
1509
1510 if (ctx.err.has_error) {
1511 zval_ptr_dtor(zv);
1512 ZVAL_UNDEF(zv);
1513 *err = ctx.err;
1514 }
1515
1516 zend_llist_destroy(&ctx.keys);
1517 zend_hash_destroy(&ctx.params);
1518
1519 return Z_ISUNDEF_P(zv)? NULL : zv;
1520 }
1521