static void do_os_wrappers_dupfd_cloexec(int n) { int base_fd; int fd; int nr_fds; nr_fds = count_open_fds(); base_fd = socket(PF_LOCAL, SOCK_STREAM, 0); assert(base_fd >= 0); fd = wl_os_dupfd_cloexec(base_fd, 13); assert(fd >= 13); close(base_fd); /* * Must have 4 calls if falling back, but must also allow * falling back without a forced fallback. */ assert(wrapped_calls_fcntl > n); exec_fd_leak_check(nr_fds); }
struct wl_closure * wl_closure_marshal(struct wl_object *sender, uint32_t opcode, union wl_argument *args, const struct wl_message *message) { struct wl_closure *closure; struct wl_object *object; int i, count, fd, dup_fd; const char *signature; struct argument_details arg; count = arg_count_for_signature(message->signature); if (count > WL_CLOSURE_MAX_ARGS) { wl_log("too many args (%d)\n", count); errno = EINVAL; return NULL; } closure = malloc(sizeof *closure); if (closure == NULL) { errno = ENOMEM; return NULL; } memcpy(closure->args, args, count * sizeof *args); signature = message->signature; for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); switch (arg.type) { case 'f': case 'u': case 'i': break; case 's': if (!arg.nullable && args[i].s == NULL) goto err_null; break; case 'o': if (!arg.nullable && args[i].o == NULL) goto err_null; break; case 'n': object = args[i].o; if (!arg.nullable && object == NULL) goto err_null; closure->args[i].n = object ? object->id : 0; break; case 'a': if (!arg.nullable && args[i].a == NULL) goto err_null; break; case 'h': fd = args[i].h; dup_fd = wl_os_dupfd_cloexec(fd, 0); if (dup_fd < 0) wl_abort("dup failed: %s\n", strerror(errno)); closure->args[i].h = dup_fd; break; default: wl_abort("unhandled format code: '%c'\n", arg.type); break; } } closure->sender_id = sender->id; closure->opcode = opcode; closure->message = message; closure->count = count; return closure; err_null: wl_closure_destroy(closure); wl_log("error marshalling arguments for %s (signature %s): " "null value passed for arg %i\n", message->name, message->signature, i); errno = EINVAL; return NULL; }
struct wl_closure * wl_closure_vmarshal(struct wl_object *sender, uint32_t opcode, va_list ap, const struct wl_message *message) { struct wl_closure *closure; struct wl_object **objectp, *object; uint32_t length, aligned, *p, *start, size, *end; int dup_fd; struct wl_array **arrayp, *array; const char **sp, *s; const char *signature = message->signature; struct argument_details arg; char *extra; int i, count, fd, extra_size, *fd_ptr; /* FIXME: Match old fixed allocation for now */ closure = malloc(sizeof *closure + 1024); if (closure == NULL) return NULL; extra_size = wl_message_size_extra(message); count = arg_count_for_signature(signature) + 2; extra = (char *) closure->buffer; start = &closure->buffer[DIV_ROUNDUP(extra_size, sizeof *p)]; end = &closure->buffer[256]; p = &start[2]; closure->types[0] = &ffi_type_pointer; closure->types[1] = &ffi_type_pointer; for (i = 2; i < count; i++) { signature = get_next_argument(signature, &arg); switch (arg.type) { case 'f': closure->types[i] = &ffi_type_sint32; closure->args[i] = p; if (end - p < 1) goto err; *p++ = va_arg(ap, wl_fixed_t); break; case 'u': closure->types[i] = &ffi_type_uint32; closure->args[i] = p; if (end - p < 1) goto err; *p++ = va_arg(ap, uint32_t); break; case 'i': closure->types[i] = &ffi_type_sint32; closure->args[i] = p; if (end - p < 1) goto err; *p++ = va_arg(ap, int32_t); break; case 's': closure->types[i] = &ffi_type_pointer; closure->args[i] = extra; sp = (const char **) extra; extra += sizeof *sp; s = va_arg(ap, const char *); if (!arg.nullable && s == NULL) goto err_null; length = s ? strlen(s) + 1: 0; aligned = (length + 3) & ~3; if (p + aligned / sizeof *p + 1 > end) goto err; *p++ = length; if (length > 0) *sp = (const char *) p; else *sp = NULL; memcpy(p, s, length); memset((char *) p + length, 0, aligned - length); p += aligned / sizeof *p; break; case 'o': closure->types[i] = &ffi_type_pointer; closure->args[i] = extra; objectp = (struct wl_object **) extra; extra += sizeof *objectp; object = va_arg(ap, struct wl_object *); if (!arg.nullable && object == NULL) goto err_null; *objectp = object; if (end - p < 1) goto err; *p++ = object ? object->id : 0; break; case 'n': closure->types[i] = &ffi_type_uint32; closure->args[i] = p; object = va_arg(ap, struct wl_object *); if (end - p < 1) goto err; if (!arg.nullable && object == NULL) goto err_null; *p++ = object ? object->id : 0; break; case 'a': closure->types[i] = &ffi_type_pointer; closure->args[i] = extra; arrayp = (struct wl_array **) extra; extra += sizeof *arrayp; *arrayp = (struct wl_array *) extra; extra += sizeof **arrayp; array = va_arg(ap, struct wl_array *); if (!arg.nullable && array == NULL) goto err_null; if (array == NULL || array->size == 0) { if (end - p < 1) goto err; *p++ = 0; break; } if (p + DIV_ROUNDUP(array->size, sizeof *p) + 1 > end) goto err; *p++ = array->size; memcpy(p, array->data, array->size); (*arrayp)->size = array->size; (*arrayp)->alloc = array->alloc; (*arrayp)->data = p; p += DIV_ROUNDUP(array->size, sizeof *p); break; case 'h': closure->types[i] = &ffi_type_sint; closure->args[i] = extra; fd_ptr = (int *) extra; extra += sizeof *fd_ptr; fd = va_arg(ap, int); dup_fd = wl_os_dupfd_cloexec(fd, 0); if (dup_fd < 0) { fprintf(stderr, "dup failed: %m"); abort(); } *fd_ptr = dup_fd; break; default: fprintf(stderr, "unhandled format code: '%c'\n", arg.type); assert(0); break; } } size = (p - start) * sizeof *p; start[0] = sender->id; start[1] = opcode | (size << 16); closure->start = start; closure->message = message; closure->count = count; ffi_prep_cif(&closure->cif, FFI_DEFAULT_ABI, closure->count, &ffi_type_void, closure->types); return closure; err: printf("request too big to marshal, maximum size is %zu\n", sizeof closure->buffer); errno = ENOMEM; return NULL; err_null: free(closure); wl_log("error marshalling arguments for %s:%i.%s (signature %s): " "null value passed for arg %i\n", sender->interface->name, sender->id, message->name, message->signature, i); errno = EINVAL; return NULL; }