]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
lxc: Add Real Time Clock device into allowed devices
authorJulio Faracco <jcfaracco@gmail.com>
Mon, 2 Mar 2020 00:54:12 +0000 (21:54 -0300)
committerMichal Privoznik <mprivozn@redhat.com>
Tue, 17 Mar 2020 18:03:00 +0000 (19:03 +0100)
This commit share host Real Time Clock device (rtc) into LXC containers
to support hardware clock. This should be available setting up a `rtc`
timer under clock section. Since this option is not emulated, it should
be available only for `localtime` clock. This option should be readonly
due to security reasons.

Before:
    root# hwclock --verbose
    hwclock from util-linux 2.32.1
    System Time: 1581877557.598365
    Trying to open: /dev/rtc0
    Trying to open: /dev/rtc
    Trying to open: /dev/misc/rtc
    No usable clock interface found.
    hwclock: Cannot access the Hardware Clock via any known method.

Now:
    root# hwclock
    2020-02-16 18:23:55.374134+00:00
    root# hwclock -w
    hwclock: ioctl(RTC_SET_TIME) to /dev/rtc to set the time failed:
    Permission denied

Signed-off-by: Julio Faracco <jcfaracco@gmail.com>
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
docs/formatdomain.html.in
src/lxc/lxc_cgroup.c
src/lxc/lxc_controller.c

index 594146009de3f556595b29ec22350c2385a77606..180afe4333c6d848b6449c7cb9f1ab4dad9618cd 100644 (file)
             being modified, and can be one of
             "platform" (currently unsupported),
             "hpet" (libxl, xen, qemu), "kvmclock" (qemu),
-            "pit" (qemu), "rtc" (qemu), "tsc" (libxl, qemu -
+            "pit" (qemu), "rtc" (qemu, lxc), "tsc" (libxl, qemu -
             <span class="since">since 3.2.0</span>), "hypervclock"
             (qemu - <span class="since">since 1.2.2</span>) or
             "armvtimer" (qemu - <span class="since">since 6.1.0</span>).
index 952d0214189fa025a67b9435bdb0f7dbe03ce467..06605cb9baadbab9db7e05b6ef1aa4ee319b5bbf 100644 (file)
@@ -333,6 +333,46 @@ static int virLXCCgroupSetupDeviceACL(virDomainDefPtr def,
                              VIR_CGROUP_DEVICE_RWM) < 0)
         return -1;
 
+    VIR_DEBUG("Allowing timers char devices");
+
+    /* Sync'ed with Host clock */
+    for (i = 0; i < def->clock.ntimers; i++) {
+        virDomainTimerDefPtr timer = def->clock.timers[i];
+        const char *dev = NULL;
+
+        /* Check if "present" is set to "no" otherwise enable it. */
+        if (!timer->present)
+            continue;
+
+        switch ((virDomainTimerNameType)timer->name) {
+        case VIR_DOMAIN_TIMER_NAME_PLATFORM:
+        case VIR_DOMAIN_TIMER_NAME_TSC:
+        case VIR_DOMAIN_TIMER_NAME_KVMCLOCK:
+        case VIR_DOMAIN_TIMER_NAME_HYPERVCLOCK:
+        case VIR_DOMAIN_TIMER_NAME_PIT:
+        case VIR_DOMAIN_TIMER_NAME_HPET:
+        case VIR_DOMAIN_TIMER_NAME_ARMVTIMER:
+        case VIR_DOMAIN_TIMER_NAME_LAST:
+            break;
+        case VIR_DOMAIN_TIMER_NAME_RTC:
+            dev = "/dev/rtc0";
+            break;
+        }
+
+        if (!dev)
+            continue;
+
+        if (!virFileExists(dev)) {
+            VIR_DEBUG("Ignoring non-existent device %s", dev);
+            continue;
+        }
+
+        if (virCgroupAllowDevicePath(cgroup, dev,
+                                     VIR_CGROUP_DEVICE_READ,
+                                     false) < 0)
+            return -1;
+    }
+
     VIR_DEBUG("Device whitelist complete");
 
     return 0;
index fa7b9dd0e74e940e29ebe484a198861e9aa2b40d..85986babb8209d099b22959c559efdff122c9d20 100644 (file)
@@ -1530,6 +1530,73 @@ static int virLXCControllerPopulateDevices(virLXCControllerPtr ctrl)
 }
 
 
+static int
+virLXCControllerSetupTimers(virLXCControllerPtr ctrl)
+{
+    virDomainDefPtr def = ctrl->def;
+    size_t i;
+
+    /* Not sync'ed with Host clock */
+    if (def->clock.offset != VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME)
+        return 0;
+
+    for (i = 0; i < def->clock.ntimers; i++) {
+        virDomainTimerDefPtr timer = def->clock.timers[i];
+        g_autofree char *path = NULL;
+        const char *timer_dev = NULL;
+        struct stat sb;
+        dev_t dev;
+
+        /* Check if "present" is set to "no" otherwise enable it. */
+        if (!timer->present)
+            continue;
+
+        switch ((virDomainTimerNameType)timer->name) {
+        case VIR_DOMAIN_TIMER_NAME_PLATFORM:
+        case VIR_DOMAIN_TIMER_NAME_TSC:
+        case VIR_DOMAIN_TIMER_NAME_KVMCLOCK:
+        case VIR_DOMAIN_TIMER_NAME_HYPERVCLOCK:
+        case VIR_DOMAIN_TIMER_NAME_PIT:
+        case VIR_DOMAIN_TIMER_NAME_HPET:
+        case VIR_DOMAIN_TIMER_NAME_ARMVTIMER:
+        case VIR_DOMAIN_TIMER_NAME_LAST:
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           _("unsupported timer type (name) '%s'"),
+                           virDomainTimerNameTypeToString(timer->name));
+            return -1;
+        case VIR_DOMAIN_TIMER_NAME_RTC:
+            timer_dev = "/dev/rtc0";
+            path = g_strdup_printf("/%s/%s.dev/%s", LXC_STATE_DIR,
+                                   def->name, "/rtc");
+            break;
+        }
+
+        if (!timer_dev)
+            continue;
+
+        if (stat(timer_dev, &sb) < 0) {
+            virReportSystemError(errno, _("Unable to access %s"),
+                                 timer_dev);
+            return -1;
+        }
+
+        dev = makedev(major(sb.st_rdev), minor(sb.st_rdev));
+        if (mknod(path, S_IFCHR, dev) < 0 ||
+            chmod(path, sb.st_mode)) {
+            virReportSystemError(errno,
+                                 _("Failed to make device %s"),
+                                 path);
+            return -1;
+        }
+
+        if (lxcContainerChown(def, path) < 0)
+            return -1;
+    }
+
+    return 0;
+}
+
+
 static int
 virLXCControllerSetupHostdevSubsysUSB(virDomainDefPtr vmDef,
                                       virDomainHostdevDefPtr def,
@@ -2321,6 +2388,9 @@ virLXCControllerRun(virLXCControllerPtr ctrl)
     if (virLXCControllerPopulateDevices(ctrl) < 0)
         goto cleanup;
 
+    if (virLXCControllerSetupTimers(ctrl) < 0)
+        goto cleanup;
+
     if (virLXCControllerSetupAllDisks(ctrl) < 0)
         goto cleanup;