lxc: Add Real Time Clock device into allowed devices

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>
This commit is contained in:
Julio Faracco 2020-03-01 21:54:12 -03:00 committed by Michal Privoznik
parent cab3622119
commit 9132badf27
3 changed files with 111 additions and 1 deletions

View File

@ -2465,7 +2465,7 @@
being modified, and can be one of being modified, and can be one of
"platform" (currently unsupported), "platform" (currently unsupported),
"hpet" (libxl, xen, qemu), "kvmclock" (qemu), "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" <span class="since">since 3.2.0</span>), "hypervclock"
(qemu - <span class="since">since 1.2.2</span>) or (qemu - <span class="since">since 1.2.2</span>) or
"armvtimer" (qemu - <span class="since">since 6.1.0</span>). "armvtimer" (qemu - <span class="since">since 6.1.0</span>).

View File

@ -333,6 +333,46 @@ static int virLXCCgroupSetupDeviceACL(virDomainDefPtr def,
VIR_CGROUP_DEVICE_RWM) < 0) VIR_CGROUP_DEVICE_RWM) < 0)
return -1; 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"); VIR_DEBUG("Device whitelist complete");
return 0; return 0;

View 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 static int
virLXCControllerSetupHostdevSubsysUSB(virDomainDefPtr vmDef, virLXCControllerSetupHostdevSubsysUSB(virDomainDefPtr vmDef,
virDomainHostdevDefPtr def, virDomainHostdevDefPtr def,
@ -2321,6 +2388,9 @@ virLXCControllerRun(virLXCControllerPtr ctrl)
if (virLXCControllerPopulateDevices(ctrl) < 0) if (virLXCControllerPopulateDevices(ctrl) < 0)
goto cleanup; goto cleanup;
if (virLXCControllerSetupTimers(ctrl) < 0)
goto cleanup;
if (virLXCControllerSetupAllDisks(ctrl) < 0) if (virLXCControllerSetupAllDisks(ctrl) < 0)
goto cleanup; goto cleanup;