On 2/13/20 2:41 PM, Stephen Smalley wrote:
An example of a sample program and policy will follow in a follow-up to this patch to demonstrate the effect on userfaultfd and kvm.
Attached are example test programs and policies to demonstrate the change in behavior before and after this RFC patch for userfaultfd and kvm. The test policies can be edited to selectively allow specific permissions for testing various scenarios, but with the defaults in them, one should see the following behavior:
sudo semodule -i kvm.cil userfaultfd.cil make kvm userfaultfd Before:(no labeling/access control applied by SELinux to userfaultfd files or to anon inodes created by kvm)
$ ./userfaultfd api: 170 features: 510 ioctls: 9223372036854775811 read: Resource temporarily unavailable $ ./kvm api version: 12 created vm created vcpu rax: 0 rbx: 0 rcx: 0 rdx: 1536 rdi: 0 rsi: 0 rsp: 0 rbp: 0 r8: 0 r9: 0 r10: 0 r11: 0 r12: 0 r13: 0 r14: 0 r15: 0 rip: 65520 rflags: 2 created device checked device attr After: (SELinux ioctl whitelisting used to selectively deny access) ./userfaultfd UFFDIO_API: Permission denied $ ./kvm api version: 12 created vm created vcpu KVM_GET_REGS: Permission denied
Attachment:
kvm.cil
Description: application/vnd.ms-artgalry
Attachment:
userfaultfd.cil
Description: application/vnd.ms-artgalry
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <sys/ioctl.h> #include <linux/kvm.h> void print_regs(const struct kvm_regs *regs) { printf("rax: %llu\n", regs->rax); printf("rbx: %llu\n", regs->rbx); printf("rcx: %llu\n", regs->rcx); printf("rdx: %llu\n", regs->rdx); printf("rdi: %llu\n", regs->rdi); printf("rsi: %llu\n", regs->rsi); printf("rsp: %llu\n", regs->rsp); printf("rbp: %llu\n", regs->rbp); printf("r8: %llu\n", regs->r8); printf("r9: %llu\n", regs->r9); printf("r10: %llu\n", regs->r10); printf("r11: %llu\n", regs->r11); printf("r12: %llu\n", regs->r12); printf("r13: %llu\n", regs->r13); printf("r14: %llu\n", regs->r14); printf("r15: %llu\n", regs->r15); printf("rip: %llu\n", regs->rip); printf("rflags: %llu\n", regs->rflags); printf("\n"); } void print_device_attr(const struct kvm_device_attr *dev_attr) { printf("flags: %u\n", dev_attr->flags); printf("group: %u\n", dev_attr->group); printf("attr: %llu\n", dev_attr->attr); printf("addr: %llu\n", dev_attr->addr); printf("\n"); } int main(void) { int fd = open("/dev/kvm", O_RDWR); if (fd < 0) { perror("/dev/kvm"); return -1; } int ret = ioctl(fd, KVM_GET_API_VERSION, 0); if (ret < 0) { perror("KVM_GET_API_VERSION"); return -1; } printf("api version: %d\n\n", ret); int vmfd = ioctl(fd, KVM_CREATE_VM, 0); if (vmfd < 0) { perror("KVM_CREATE_VM"); return -1; } printf("created vm\n\n"); int vcpufd = ioctl(vmfd, KVM_CREATE_VCPU, 0); if (vcpufd < 0) { perror("KVM_CREATE_VCPU"); return -1; } printf("created vcpu\n\n"); struct kvm_regs regs; if (ioctl(vcpufd, KVM_GET_REGS, ®s) < 0) { perror("KVM_GET_REGS"); return -1; } print_regs(®s); struct kvm_create_device dev = {0}; dev.type = KVM_DEV_TYPE_VFIO; if (ioctl(vmfd, KVM_CREATE_DEVICE, &dev) < 0) { perror("KVM_CREATE_DEVICE"); return -1; } printf("created device\n\n"); struct kvm_device_attr dev_attr = {0}; dev_attr.group = KVM_DEV_VFIO_GROUP; dev_attr.attr = KVM_DEV_VFIO_GROUP_ADD; if (ioctl(dev.fd, KVM_HAS_DEVICE_ATTR, &dev_attr) < 0) { perror("KVM_HAS_DEVICE_ATTR"); return -1; } printf("checked device attr\n\n"); return 0; }
#include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <sys/types.h> #include <sys/ioctl.h> #include <sys/syscall.h> #include <linux/userfaultfd.h> void print_api(const struct uffdio_api *api) { printf("api: %llu\n", api->api); printf("features: %llu\n", api->features); printf("ioctls: %llu\n", api->ioctls); printf("\n"); } int main(void) { long uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK); if (uffd < 0) { perror("syscall(userfaultfd)"); return -1; } struct uffdio_api api = {0}; api.api = UFFD_API; if (ioctl(uffd, UFFDIO_API, &api) < 0) { perror("UFFDIO_API"); return -1; } print_api(&api); struct uffd_msg msg = {0}; ssize_t count = read(uffd, &msg, sizeof(msg)); if (count < 0) { perror("read"); return -1; } else if (count == 0) { printf("read EOF\n\n"); } printf("read uffd\n\n"); return 0; }