#include #include #include "types.h" #include "proc_parse.h" #include "namespaces.h" #include "timens.h" #include "cr_options.h" #include "protobuf.h" #include "images/timens.pb-c.h" int dump_time_ns(int ns_id) { struct cr_img *img; TimensEntry te = TIMENS_ENTRY__INIT; Timespec b = TIMESPEC__INIT, m = TIMESPEC__INIT; struct timespec ts; int ret; img = open_image(CR_FD_TIMENS, O_DUMP, ns_id); if (!img) return -1; clock_gettime(CLOCK_MONOTONIC, &ts); te.monotonic = &m; te.monotonic->tv_sec = ts.tv_sec; te.monotonic->tv_nsec = ts.tv_nsec; clock_gettime(CLOCK_BOOTTIME, &ts); te.boottime = &b; te.boottime->tv_sec = ts.tv_sec; te.boottime->tv_nsec = ts.tv_nsec; ret = pb_write_one(img, &te, PB_TIMENS); close_image(img); return ret < 0 ? -1 : 0; } static void normalize_timespec(struct timespec *ts) { while (ts->tv_nsec >= NSEC_PER_SEC) { ts->tv_nsec -= NSEC_PER_SEC; ++ts->tv_sec; } while (ts->tv_nsec < 0) { ts->tv_nsec += NSEC_PER_SEC; --ts->tv_sec; } } int prepare_timens(int id) { int exit_code = -1; int ret, fd = -1; struct cr_img *img; TimensEntry *te; struct timespec ts; struct timespec prev_moff = {}, prev_boff = {}; if (opts.unprivileged) return 0; img = open_image(CR_FD_TIMENS, O_RSTR, id); if (!img) return -1; if (id == 0 && empty_image(img)) { pr_warn("Clocks values have not been dumped\n"); close_image(img); return 0; } ret = pb_read_one(img, &te, PB_TIMENS); close_image(img); if (ret < 0) goto err; if (unshare(CLONE_NEWTIME)) { pr_perror("Unable to create a new time namespace"); return -1; } if (parse_timens_offsets(&prev_boff, &prev_moff)) goto err; fd = open_proc_rw(PROC_SELF, "timens_offsets"); if (fd < 0) goto err; clock_gettime(CLOCK_MONOTONIC, &ts); ts.tv_sec = ts.tv_sec - prev_moff.tv_sec; ts.tv_nsec = ts.tv_nsec - prev_moff.tv_nsec; ts.tv_sec = te->monotonic->tv_sec - ts.tv_sec; ts.tv_nsec = te->monotonic->tv_nsec - ts.tv_nsec; normalize_timespec(&ts); pr_debug("timens: monotonic %ld %ld\n", ts.tv_sec, ts.tv_nsec); if (dprintf(fd, "%d %ld %ld\n", CLOCK_MONOTONIC, ts.tv_sec, ts.tv_nsec) < 0) { pr_perror("Unable to set a monotonic clock offset"); goto err; } clock_gettime(CLOCK_BOOTTIME, &ts); ts.tv_sec = ts.tv_sec - prev_boff.tv_sec; ts.tv_nsec = ts.tv_nsec - prev_boff.tv_nsec; ts.tv_sec = te->boottime->tv_sec - ts.tv_sec; ts.tv_nsec = te->boottime->tv_nsec - ts.tv_nsec; normalize_timespec(&ts); pr_debug("timens: boottime %ld %ld\n", ts.tv_sec, ts.tv_nsec); if (dprintf(fd, "%d %ld %ld\n", CLOCK_BOOTTIME, ts.tv_sec, ts.tv_nsec) < 0) { pr_perror("Unable to set a boottime clock offset"); goto err; } timens_entry__free_unpacked(te, NULL); close_safe(&fd); fd = open_proc(PROC_SELF, "ns/time_for_children"); if (fd < 0) { pr_perror("Unable to open ns/time_for_children"); goto err; } if (switch_ns_by_fd(fd, &time_ns_desc, NULL)) goto err; exit_code = 0; err: close_safe(&fd); return exit_code; } struct ns_desc time_ns_desc = NS_DESC_ENTRY(CLONE_NEWTIME, "time"); struct ns_desc time_for_children_ns_desc = NS_DESC_ENTRY(CLONE_NEWTIME, "time_for_children");