From 7a3000f7ba548cf7d74ac77cc63fe8de228a669e Mon Sep 17 00:00:00 2001 From: J William Piggott Date: Sat, 4 Mar 2017 11:04:10 -0500 Subject: hwclock: use parse_date function * hwclock.c: replace interpret_date_string() with parse_date(). Eliminates shell injection vulnerability from popen() date(1). Removes system dependency on date(1). Reduction in hwclock execution time. Significant cleanup of hwclock.c code. * Bug fix for "hwclock --predict --date 'bad_date'" printing: hwclock: No usable set-to time. Cannot set clock. The message now matches date(1) for an invalid --date argument. Signed-off-by: J William Piggott --- sys-utils/hwclock.c | 104 +++------------------------------------------------- 1 file changed, 5 insertions(+), 99 deletions(-) (limited to 'sys-utils/hwclock.c') diff --git a/sys-utils/hwclock.c b/sys-utils/hwclock.c index 21d1304e1..21559cf41 100644 --- a/sys-utils/hwclock.c +++ b/sys-utils/hwclock.c @@ -638,100 +638,6 @@ display_time(const bool hclock_valid, struct timeval hwctime) } } -/* - * Interpret the value of the --date option, which is something like - * "13:05:01". In fact, it can be any of the myriad ASCII strings that - * specify a time which the "date" program can understand. The date option - * value in question is our "dateopt" argument. - * - * The specified time is in the local time zone. - * - * Our output, "*time_p", is a seconds-into-epoch time. - * - * We use the "date" program to interpret the date string. "date" must be - * runnable by issuing the command "date" to the /bin/sh shell. That means - * in must be in the current PATH. - * - * If anything goes wrong (and many things can), we return code 10 - * and arbitrary *time_p. Otherwise, return code is 0 and *time_p is valid. - */ -static int interpret_date_string(const struct hwclock_control *ctl, - time_t *const time_p) -{ - FILE *date_child_fp = NULL; - char *date_command = NULL; - char *date_resp = NULL; - size_t len = 0; - const char magic[] = "seconds-into-epoch="; - int retcode = 1; - long seconds_since_epoch; - - if (!ctl->date_opt) { - warnx(_("No --date option specified.")); - return retcode; - } - - /* Quotes in date_opt would ruin the date command we construct. */ - if (strchr(ctl->date_opt, '"') != NULL || - strchr(ctl->date_opt, '`') != NULL || - strchr(ctl->date_opt, '$') != NULL) { - warnx(_ - ("The value of the --date option is not a valid date.\n" - "In particular, it contains illegal character(s).")); - return retcode; - } - - xasprintf(&date_command, "date --date=\"%s\" +%s%%s", - ctl->date_opt, magic); - if (ctl->debug) - printf(_("Issuing date command: %s\n"), date_command); - - date_child_fp = popen(date_command, "r"); - if (date_child_fp == NULL) { - warn(_("Unable to run 'date' program in /bin/sh shell. " - "popen() failed")); - goto out; - } - - if (getline(&date_resp, &len, date_child_fp) < 0) { - warn(_("getline() failed")); - goto out; - } - if (ctl->debug) - printf(_("response from date command = %s\n"), date_resp); - if (strncmp(date_resp, magic, sizeof(magic) - 1) != 0) { - warnx(_("The date command issued by %s returned " - "unexpected results.\n" - "The command was:\n %s\n" - "The response was:\n %s"), - program_invocation_short_name, date_command, date_resp); - goto out; - } - - if (sscanf(date_resp + sizeof(magic) - 1, "%ld", &seconds_since_epoch) < 1) { - warnx(_("The date command issued by %s returned " - "something other than an integer where the " - "converted time value was expected.\n" - "The command was:\n %s\n" - "The response was:\n %s\n"), - program_invocation_short_name, date_command, date_resp); - } else { - retcode = 0; - *time_p = seconds_since_epoch; - if (ctl->debug) - printf(_("date string %s equates to " - "%ld seconds since 1969.\n"), - ctl->date_opt, *time_p); - } - out: - free(date_command); - free(date_resp); - if (date_child_fp) - pclose(date_child_fp); - - return retcode; -} - /* * Set the System Clock to time 'newtime'. * @@ -1460,6 +1366,7 @@ int main(int argc, char **argv) struct hwclock_control ctl = { NULL }; struct timeval startup_time; struct adjtime adjtime = { 0 }; + struct timespec when = { 0 }; /* * The time we started up, in seconds into the epoch, including * fractions. @@ -1699,11 +1606,10 @@ int main(int argc, char **argv) #endif if (ctl.set || ctl.predict) { - rc = interpret_date_string(&ctl, &set_time); - /* (time-consuming) */ - if (rc != 0) { - warnx(_("No usable set-to time. " - "Cannot set clock.")); + if (parse_date(&when, ctl.date_opt, NULL)) + set_time = when.tv_sec; + else { + warnx(_("invalid date '%s'"), ctl.date_opt); hwclock_exit(&ctl, EX_USAGE); } } -- cgit v1.2.3-55-g7522