Unlike the other tests, this is not standalone. It requires poking at a live system, making it unweildly to use.
It hasn't been touched in 7 years, despite changes in libraries and kernel devices using the deprivilege infrastructure. Signed-off-by: Andrew Cooper <andrew.coop...@citrix.com> --- CC: Anthony PERARD <anthony.per...@vates.tech> CC: Stefano Stabellini <sstabell...@kernel.org> CC: Marek Marczykowski-Górecki <marma...@invisiblethingslab.com> --- .gitignore | 1 - tools/tests/Makefile | 1 - tools/tests/depriv/Makefile | 52 --- tools/tests/depriv/depriv-fd-checker.c | 436 ------------------------- 4 files changed, 490 deletions(-) delete mode 100644 tools/tests/depriv/Makefile delete mode 100644 tools/tests/depriv/depriv-fd-checker.c diff --git a/.gitignore b/.gitignore index 53f5df000383..4a4e20680464 100644 --- a/.gitignore +++ b/.gitignore @@ -165,7 +165,6 @@ tools/misc/xencov tools/pkg-config/* tools/qemu-xen-build tools/xentrace/xenalyze -tools/tests/depriv/depriv-fd-checker tools/tests/x86_emulator/*.bin tools/tests/x86_emulator/*.tmp tools/tests/x86_emulator/32/x86_emulate diff --git a/tools/tests/Makefile b/tools/tests/Makefile index 3e60ab6b268d..36928676a666 100644 --- a/tools/tests/Makefile +++ b/tools/tests/Makefile @@ -9,7 +9,6 @@ ifneq ($(clang),y) SUBDIRS-$(CONFIG_X86) += x86_emulator endif SUBDIRS-y += xenstore -SUBDIRS-y += depriv SUBDIRS-y += rangeset SUBDIRS-y += vpci SUBDIRS-y += paging-mempool diff --git a/tools/tests/depriv/Makefile b/tools/tests/depriv/Makefile deleted file mode 100644 index 5404a12f4780..000000000000 --- a/tools/tests/depriv/Makefile +++ /dev/null @@ -1,52 +0,0 @@ -XEN_ROOT=$(CURDIR)/../../.. -include $(XEN_ROOT)/tools/Rules.mk - -CFLAGS += $(CFLAGS_xeninclude) -CFLAGS += $(CFLAGS_libxenctrl) -CFLAGS += $(CFLAGS_libxencall) -CFLAGS += $(CFLAGS_libxenevtchn) -CFLAGS += $(CFLAGS_libxengnttab) -CFLAGS += $(CFLAGS_libxenforeignmemory) -CFLAGS += $(CFLAGS_libxendevicemodel) -CFLAGS += $(CFLAGS_libxentoolcore) -CFLAGS += $(CFLAGS_libxentoollog) - -LDLIBS += $(LDLIBS_xeninclude) -LDLIBS += $(LDLIBS_libxenctrl) -LDLIBS += $(LDLIBS_libxencall) -LDLIBS += $(LDLIBS_libxenevtchn) -LDLIBS += $(LDLIBS_libxengnttab) -LDLIBS += $(LDLIBS_libxenforeignmemory) -LDLIBS += $(LDLIBS_libxendevicemodel) -LDLIBS += $(LDLIBS_libxentoolcore) -LDLIBS += $(LDLIBS_libxentoollog) - -INSTALL_PRIVBIN-y += depriv-fd-checker -INSTALL_PRIVBIN := $(INSTALL_PRIVBIN-y) -TARGETS += $(INSTALL_PRIVBIN) - -.PHONY: all -all: build - -.PHONY: build -build: $(TARGETS) - -.PHONY: clean -clean: - $(RM) *.o $(TARGETS) *~ $(DEPS_RM) - -.PHONY: distclean -distclean: clean - -depriv-fd-checker: depriv-fd-checker.o - $(CC) $(LDFLAGS) -o $@ $< $(LDLIBS) $(APPEND_LDFLAGS) - -install: all - $(INSTALL_DIR) $(DESTDIR)$(LIBEXEC_BIN) - $(INSTALL_PROG) $(INSTALL_PRIVBIN) $(DESTDIR)$(LIBEXEC_BIN) - -.PHONY: uninstall -uninstall: - rm -f $(addprefix $(DESTDIR)$(LIBEXEC_BIN)/, $(INSTALL_PRIVBIN)) - --include $(DEPS_INCLUDE) diff --git a/tools/tests/depriv/depriv-fd-checker.c b/tools/tests/depriv/depriv-fd-checker.c deleted file mode 100644 index 98a27a03d543..000000000000 --- a/tools/tests/depriv/depriv-fd-checker.c +++ /dev/null @@ -1,436 +0,0 @@ -/* - * depriv-fd-checker - * - * utility to check whether file descriptor(s) are deprivileged - * - * usage: - * .../depriv-fd-checker CLASS FD X-INFO [CLASS FD X-INFO...] - * - * CLASS is one of: - * privcmd gntdev evtchn FD should be appropriate Xen control fd - * readonly FD is expected to be readonly - * appendonly FD is expected to be append write only - # tun FD is expected to be an open tun device - * - * In each case FD is probably a reference to an open-file stolen - * from another process, eg by the use of fishdescriptor. - * - * X-INFO is simply appended to the discursive reportage. - * - * It is an error if depriv-fd-checker cannot open the control - * facilities itself, or something goes wrong with checking, or an FD - * is entirely the wrong kind for the specified CLASS. Otherwise: - * - * depriv-fd-checker will perhaps print, for each triplet: - * CLASS checking FD INFORMATION... X-INFO - * and in any case print, for each triplet, exactly one of: - * CLASS pass|fail FD INFORMATION... X-INFO - * tun maybe FD IFNAME X-INFO - * - * "pass" means that the descriptor was restricted as expected. - * "fail" means that the descriptor was unrestricted. - * "maybe" means that further information is printed, as detailed above, - * and the caller should check that it is as expected - */ -/* - * Copyright (C)2018 Citrix Systems R&D - * - * This program 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; version 2.1 of the - * License. - * - * This library 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 library; If not, see - * <http://www.gnu.org/licenses/>. - */ - -#include <stdlib.h> -#include <errno.h> -#include <string.h> -#include <stdio.h> -#include <assert.h> -#include <string.h> -#include <unistd.h> -#include <fcntl.h> -#include <poll.h> - -#include <err.h> - -#include <xenctrl.h> -#include <xencall.h> -#include <xengnttab.h> -#include <xenevtchn.h> - -/* - * Every class needs setup. setup is called once per class at program - * startup. - * - * Then it can have - * open test getfd close - * In which case the core code will for every fd - * open test getfd dup2 test close - * And test should call blocked or succeeded and then immediately - * return, or error out - * - * Or it can have - * check - * which should call report, or error out - * - * Errors: use trouble for simple syscall errors. Or use err or errx - * and maybe print fd_desc and test_which, according to the comments - * in struct classinfo. - */ - -static xentoollog_logger *logger; - -static int object_fd; -static const char *classname; -static const char *fd_desc; -static const char *test_which; - -static const char *test_wh_unrest = "test (unrestricted)"; -static const char *test_wh_rest = "test (restricted)"; - - -static void trouble(const char *what) __attribute__((noreturn)); -static void trouble(const char *what) { - fprintf(stderr, - "trouble: %s %s %d (%s) %s: %s\n", - classname, test_which, object_fd, fd_desc, what, strerror(errno)); - exit(-1); -} - -static void report(const char *pass_or_fail, const char *what, - const char *notes) { - printf("%s %s %d %s (%s) %s\n", - classname, pass_or_fail, - object_fd, what, notes, fd_desc); - if (ferror(stdout) || fflush(stdout)) err(16,"stdout"); -} - -static void succeeded(const char *what) { - if (test_which == test_wh_unrest) { - /* ok */ - test_which = 0; - } else if (test_which == test_wh_rest) { - report("fail",what,"unexpectedly succeeded"); - test_which = 0; - } else { - abort(); - } -} - -static void blocked(const char *what) { - if (test_which == test_wh_rest) { - /* yay */ - report("pass", what,"blocked"); - test_which = 0; - } else if (test_which == test_wh_unrest) { - err(4,"test blocked on unrestricted fd: %s {%s}",what,test_which); - } else { - abort(); - } -} - -/* privcmd */ - -static xc_interface *xch; -static void setup_privcmd(void) { } -static void open_privcmd(void) { - xch = xc_interface_open(logger,0,0); - if (!xch) trouble("xc_interface_open"); -} -static void test_privcmd(void) { - int r = xc_get_online_cpus(xch); - if (r>0) - succeeded("xc_get_online_cpus"); - else if (r==0) - errx(-1,"xc_get_online_cpus{%s, %s}=0", test_which, fd_desc); - else if (errno==EPERM || errno==EACCES) - blocked("xc_get_online_cpus"); - else - trouble("xc_get_online_cpus"); -} -static int getfd_privcmd(void) { - return xencall_fd(xc_interface_xcall_handle(xch)); -} -static void close_privcmd(void) { - xc_interface_close(xch); -} - -/* gntdev */ - -static xengntshr_handle *xgs; -static uint32_t gntshr_gref; -static xengnttab_handle *xgt; -static void setup_gntdev(void) { - void *r; - xgs = xengntshr_open(logger,0); - if (!xgs) trouble("xengntshr_open"); - r = xengntshr_share_pages(xgs, 0, 1, &gntshr_gref, 1); - if (!r || r==(void*)-1) trouble("xengntshr_share_pages"); - memset(r, 0x55, XC_PAGE_SIZE); -} -static void open_gntdev(void) { - xgt = xengnttab_open(logger,0); - if (!xgt) trouble("xengnttab_open"); -} -static void test_gntdev(void) { - char mybuf[XC_PAGE_SIZE]; - memset(mybuf, 0xaa, XC_PAGE_SIZE); - xengnttab_grant_copy_segment_t seg; - seg.source.foreign.ref = gntshr_gref; - seg.source.foreign.offset = 0; - seg.source.foreign.domid = 0; - seg.dest.virt = mybuf; - seg.len = 1; - seg.flags = GNTCOPY_source_gref; - for (;;) { - seg.status = 0; - int r = xengnttab_grant_copy(xgt,1,&seg); - if (r<0) { - if (errno==EPERM || errno==EACCES || errno==ENOTTY) - blocked("xengnttab_grant_copy"); - else - trouble("xengnttab_grant_copy"); - } else if (r==0) { - if (seg.status==GNTST_okay) - succeeded("xengnttab_grant_copy okay"); - else if (seg.status==GNTST_eagain) - continue; - else errx(-1,"xengnttab_grant_copy=%d {%s, %s} but .status=%d", - r, test_which, fd_desc,(int)seg.status); - } else { - errx(-1,"xengnttab_grant_copy=%d {%s, %s}", - r, test_which, fd_desc); - } - break; - } -} -static int getfd_gntdev(void) { - return xengnttab_fd(xgt); -} -static void close_gntdev(void) { - xengnttab_close(xgt); -} - -/* evtchn */ - -static xenevtchn_handle *xce_recip, *xce; -static void setup_evtchn(void) { - xce_recip = xenevtchn_open(logger, 0); - if (!xce_recip) err(-1,"xenevtchn_open (donor)"); -} -static void open_evtchn(void) { - xce = xenevtchn_open(logger, 0); - if (!xce) err(-1,"xenevtchn_open"); -} -static void test_evtchn(void) { - xenevtchn_port_or_error_t - recip_port=-1, test_unbound_port=-1, test_send_port=-1; - - recip_port = xenevtchn_bind_unbound_port(xce_recip, 0); - if (recip_port < 0) trouble("xenevtchn_bind_unbound_port"); - - test_unbound_port = xenevtchn_bind_unbound_port(xce, 0); - if (test_unbound_port >= 0) { - succeeded("xenevtchn_bind_unbound_port"); - goto out; - } - - test_send_port = xenevtchn_bind_interdomain(xce, 0, recip_port); - /* bind_interdomain marks the channel pending */ - struct pollfd pfd; - for (;;) { - pfd.fd = xenevtchn_fd(xce_recip); - pfd.events = POLLIN; - pfd.revents = 0; - int r = poll(&pfd,1,0); - if (r>=0) break; - if (errno!=EINTR) err(-1,"poll(xce_recip)"); - } - if (pfd.revents & POLLIN) { - xenevtchn_port_or_error_t p3 = xenevtchn_pending(xce_recip); - if (p3 < 0) err(-1,"xenevtchn_pending(check)"); - if (p3 != recip_port) - errx(-1,"xenevtchn_pending=%d expected %d",p3,recip_port); - xenevtchn_unmask(xce_recip, recip_port); - } - - if (test_send_port>=0 && (pfd.revents & POLLIN)) { - succeeded("xenevtchn_bind_interdomain/poll"); - /* we make no attempt to undo what we did to this stolen fd; - * the rightful owner will see a spurious event on test_send_port */ - } else if (test_send_port==-1 && !(pfd.revents & POLLIN) && - (errno==EPERM || errno==EACCES || errno==ENOTTY)) { - blocked("xenevtchn_notify"); - } else { - err(-1,"%s %s xenevtchn_bind_interdomain=%d .revents=0x%x", - test_which, fd_desc, test_send_port, pfd.revents); - } - - out: - if (recip_port > 0) xenevtchn_unbind(xce, recip_port); - if (test_unbound_port > 0) xenevtchn_unbind(xce, test_unbound_port); - if (test_send_port > 0) xenevtchn_unbind(xce, test_send_port); -} -static int getfd_evtchn(void) { - return xenevtchn_fd(xce); -} -static void close_evtchn(void) { - xenevtchn_close(xce); -} - -/* fcntl */ - -#define CHECK_FCNTL(openmode) \ - int r = fcntl(object_fd, F_GETFL); \ - if (r < 0) trouble("fcntl F_GETFL"); \ - int m = r & (O_RDONLY | O_WRONLY | O_RDWR); \ - \ - char mbuf[100 + 30*3]; \ - snprintf(mbuf,sizeof(mbuf), \ - "F_GETFL=%#o m=%#o " #openmode "=%#o", \ - r,m,(int)openmode); \ - \ - if (m != openmode) { \ - report("fail", #openmode, mbuf); \ - return; \ - } - -/* readonly */ - -static void setup_readonly(void) { } -static void check_readonly(void) { - CHECK_FCNTL(O_RDONLY); - report("pass", "fcntl", mbuf); -} - -/* appendonly */ - -static void setup_appendonly(void) { } -static void check_appendonly(void) { - CHECK_FCNTL(O_WRONLY); - if (!(r & O_APPEND)) { - report("fail", "O_APPEND", mbuf); - return; - } - report("pass", "fcntl", mbuf); -} - -#if defined(__linux__) -#include <sys/ioctl.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <linux/if.h> -#include <linux/if_tun.h> -#ifndef TUNGETIFF -#define TUNGETIFF _IOR('T', 210, unsigned int) -#endif - -/* linux tun */ - -static void setup_tun(void) { } -static void check_tun(void) { - struct ifreq ifr; - int r; - - memset(&ifr,0,sizeof(ifr)); - r = ioctl(object_fd, TUNGETIFF, (void*)&ifr); - if (r<0) trouble("TUNGETIFF"); - printf("tun maybe %d %.*s %s\n", object_fd, - (int)IFNAMSIZ, ifr.ifr_ifrn.ifrn_name, - fd_desc); -} - -#define PLATFORM_CLASSES \ - DEFCHECK(tun), - -#else /* !defined(__linux__) */ -#define PLATFORM_CLASSES /* empty */ -#endif - -/* class table and main program */ - -#define DEFCLASS(cl) \ - { #cl, setup_##cl, 0, open_##cl, test_##cl, getfd_##cl, close_##cl } -#define DEFCHECK(meth) \ - { #meth, setup_##meth, check_##meth } - -static const struct classinfo { - const char *name; /* errors: print fd_desc test_which */ - void (*setup)(void); /* best not best not */ - void (*check)(void); /* must may */ - void (*open)(void); /* must may */ - void (*test)(void); /* must must */ - int (*getfd)(void); /* must may */ - void (*close)(void); /* must may */ -} classinfos[] = { - DEFCLASS(privcmd), - DEFCLASS(gntdev), - DEFCLASS(evtchn), - DEFCHECK(readonly), - DEFCHECK(appendonly), - PLATFORM_CLASSES - { 0 } -}; - -int main(int argc, char **argv) { - const struct classinfo *cli; - int r; - - argv++; - - logger = (xentoollog_logger*)xtl_createlogger_stdiostream - (stderr, XTL_NOTICE, XTL_STDIOSTREAM_HIDE_PROGRESS); - - fd_desc = "setup"; - test_which = "setup"; - for (cli = classinfos; cli->name; cli++) - cli->setup(); - - while ((classname = *argv++)) { - if (!*argv) errx(8,"need fd after class"); - object_fd = atoi(*argv++); - - fd_desc = *argv++; - if (!fd_desc) errx(8,"need info after fd"); - - for (cli = classinfos; cli->name; cli++) - if (!strcmp(cli->name, classname)) - goto found; - report("fail","unknown class",""); - continue; - - found: - if (cli->check) { - report("checking","check","in progress"); - test_which = "check"; - cli->check(); - } else { - test_which = "open"; - report("checking","dup-hack","in progress"); - cli->open(); - - test_which = test_wh_unrest; cli->test(); - assert(!test_which); - - test_which = "getfd"; int intern_fd = cli->getfd(); - r = dup2(object_fd, intern_fd); - if (r != intern_fd) err(-1, "dup2"); - - test_which = test_wh_rest; cli->test(); - assert(!test_which); - - test_which = "close"; cli->close(); - } - } - - return 0; -} -- 2.39.5