[PATCH 1/4] lxc: Add Real Time Clock device into allowed devices

Daniel Henrique Barboza danielhb413 at gmail.com
Wed Feb 19 12:01:36 UTC 2020



On 2/16/20 2:11 PM, Julio Faracco wrote:
> 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 at gmail.com>
> ---
>   docs/formatdomain.html.in |  2 +-
>   src/lxc/lxc_cgroup.c      | 36 +++++++++++++++++++
>   src/lxc/lxc_controller.c  | 73 +++++++++++++++++++++++++++++++++++++++
>   3 files changed, 110 insertions(+), 1 deletion(-)
> 
> diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
> index 1a31eda154..b045314917 100644
> --- a/docs/formatdomain.html.in
> +++ b/docs/formatdomain.html.in
> @@ -2465,7 +2465,7 @@
>               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>).
> diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c
> index 7f3701593a..752cb4b047 100644
> --- a/src/lxc/lxc_cgroup.c
> +++ b/src/lxc/lxc_cgroup.c
> @@ -410,6 +410,42 @@ static int virLXCCgroupSetupDeviceACL(virDomainDefPtr def,
>                                VIR_CGROUP_DEVICE_RWM) < 0)
>           return -1;
>   
> +    VIR_DEBUG("Allowing timers char devices");
> +
> +    /* Sync'ed with Host clock */
> +    if (def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME) {
> +        for (i = 0; i < def->clock.ntimers; i++) {
> +            virDomainTimerDefPtr timer = def->clock.timers[i];
> +
> +            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:
> +                if (!timer->present)
> +                    break;
> +
> +                if (virFileExists("/dev/rtc")) {
> +                    if (virCgroupAllowDevicePath(cgroup, "/dev/rtc",
> +                                                 VIR_CGROUP_DEVICE_READ,
> +                                                 false) < 0)
> +                        return -1;
> +                } else {
> +                    VIR_DEBUG("Ignoring non-existent device /dev/rtc");
> +                }
> +                break;
> +            }
> +        }
> +    } else {
> +        VIR_DEBUG("Ignoring non-localtime clock");
> +    }
> +
>       VIR_DEBUG("Device whitelist complete");
>   
>       return 0;
> diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c
> index c3dec0859c..528f2fabf1 100644
> --- a/src/lxc/lxc_controller.c
> +++ b/src/lxc/lxc_controller.c
> @@ -1550,6 +1550,76 @@ static int virLXCControllerPopulateDevices(virLXCControllerPtr ctrl)
>   }
>   
>   
> +static int
> +virLXCControllerSetupTimers(virLXCControllerPtr ctrl)
> +{
> +    int ret = -1;
> +    char *path = NULL;


You can use g_autofree with this path variable to avoid the need for a VIR_FREE()
call and the 'cleanup' label. The 'ret' variable becomes unneeded after that as
well since you can just return -1 on error.






> +    size_t i;
> +    struct stat sb;
> +    virDomainDefPtr def = ctrl->def;
> +
> +    /* 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++) {
> +        dev_t dev;
> +        virDomainTimerDefPtr timer = def->clock.timers[i];
> +
> +        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:
> +            if (!timer->present)
> +                break;
> +
> +            if (stat("/dev/rtc", &sb) < 0) {
> +                if (errno == EACCES)
> +                    goto cleanup;
> +
> +                virReportSystemError(errno,
> +                                     _("Path '%s' is not accessible"),
> +                                     path);
> +                goto cleanup;
> +            }
> +
> +            path = g_strdup_printf("/%s/%s.dev/%s", LXC_STATE_DIR,
> +                                   ctrl->def->name, "/rtc");
> +
> +            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);
> +                goto cleanup;
> +            }
> +
> +            if (lxcContainerChown(ctrl->def, path) < 0)
> +                goto cleanup;
> +            break;
> +        }
> +    }
> +
> +    ret = 0;
> + cleanup:
> +    VIR_FREE(path);
> +    return ret;
> +
> +}
> +
> +
>   static int
>   virLXCControllerSetupHostdevSubsysUSB(virDomainDefPtr vmDef,
>                                         virDomainHostdevDefPtr def,
> @@ -2352,6 +2422,9 @@ virLXCControllerRun(virLXCControllerPtr ctrl)
>       if (virLXCControllerPopulateDevices(ctrl) < 0)
>           goto cleanup;
>   
> +    if (virLXCControllerSetupTimers(ctrl) < 0)
> +        goto cleanup;
> +
>       if (virLXCControllerSetupAllDisks(ctrl) < 0)
>           goto cleanup;
>   
> 




More information about the libvir-list mailing list