/* Copyright (C) 2019 Intel Corporation This file is part of Graphene Library OS. Graphene Library OS is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Graphene Library OS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ /* * shim_eventfd.c * * Implementation of system calls "eventfd" and "eventfd2". Since eventfd emulation currently relies * on the host, these system calls are disallowed by default due to security concerns. To use them, * they must be explicitly allowed through the "sys.allow_insecure_eventfd" manifest key. */ #include #include #include #include #include #include #include #include #include static int create_eventfd(PAL_HANDLE* efd, unsigned count, int flags) { if (!root_config) { /* eventfd must be explicitly allowed in manifest; error out if no manifest found */ return -ENOSYS; } char eventfd_cfg[2]; ssize_t len = get_config(root_config, "sys.allow_insecure_eventfd", eventfd_cfg, sizeof(eventfd_cfg)); if (len != 1 || eventfd_cfg[0] != '1') { /* eventfd is not explicitly allowed in manifest */ return -ENOSYS; } PAL_HANDLE hdl = NULL; int pal_flags = 0; pal_flags |= flags & EFD_NONBLOCK ? PAL_OPTION_NONBLOCK : 0; pal_flags |= flags & EFD_CLOEXEC ? PAL_OPTION_CLOEXEC : 0; pal_flags |= flags & EFD_SEMAPHORE ? PAL_OPTION_EFD_SEMAPHORE : 0; /* eventfd() requires count (aka initval) but PAL's DkStreamOpen() doesn't have such an * argument. Using create arg as a work-around (note: initval is uint32 but create is int32). */ if (!(hdl = DkStreamOpen(URI_PREFIX_EVENTFD, 0, 0, count, pal_flags))) { debug("eventfd open failure\n"); return -PAL_ERRNO; } *efd = hdl; return 0; } int shim_do_eventfd2(unsigned int count, int flags) { int ret = 0; struct shim_handle* hdl = get_new_handle(); if (!hdl) { ret = -ENOMEM; goto out; } hdl->type = TYPE_EVENTFD; set_handle_fs(hdl, &eventfd_builtin_fs); hdl->flags = O_RDWR; hdl->acc_mode = MAY_READ | MAY_WRITE; if ((ret = create_eventfd(&hdl->pal_handle, count, flags)) < 0) goto out; flags = flags & EFD_CLOEXEC ? FD_CLOEXEC : 0; /* get_new_handle() above increments hdl's refcount. Followed by another increment inside * set_new_fd_handle. So we need to put_handle() afterwards. */ int vfd = set_new_fd_handle(hdl, flags, NULL); ret = vfd; out: if (hdl) put_handle(hdl); return ret; } int shim_do_eventfd(unsigned int count) { return shim_do_eventfd2(count, 0); }