Check strftime(3) return value in all cases.

Old versions of strftime(3) didn't guarantee to NUL-terminate the buffer
so we explicitly clear the last byte of the buffer and check it.
This commit is contained in:
Todd C. Miller
2021-09-17 14:01:28 -06:00
parent 698481492c
commit 55171df5e5
10 changed files with 105 additions and 47 deletions

View File

@@ -427,7 +427,7 @@ send_mail(const struct eventlog *evlog, const char *fmt, ...)
struct tm gmt;
time_t now;
FILE *mail;
int fd, pfd[2], status;
int fd, len, pfd[2], status;
pid_t pid, rv;
struct stat sb;
va_list ap;
@@ -568,7 +568,18 @@ send_mail(const struct eventlog *evlog, const char *fmt, ...)
(void) fprintf(mail, "\nContent-Type: text/plain; charset=\"%s\"\nContent-Transfer-Encoding: 8bit", nl_langinfo(CODESET));
#endif /* HAVE_NL_LANGINFO && CODESET */
strftime(timebuf, sizeof(timebuf), timefmt, &gmt);
timebuf[sizeof(timebuf) - 1] = '\0';
len = strftime(timebuf, sizeof(timebuf), timefmt, &gmt);
if (len == 0 || timebuf[sizeof(timebuf) - 1] != '\0') {
sudo_debug_printf(SUDO_DEBUG_INFO|SUDO_DEBUG_ERROR,
"strftime() failed to format time: %s", timefmt);
/* Fall back to default time format string. */
timebuf[sizeof(timebuf) - 1] = '\0';
len = strftime(timebuf, sizeof(timebuf), "%h %e %T", &gmt);
if (len == 0 || timebuf[sizeof(timebuf) - 1] != '\0') {
timebuf[0] = '\0'; /* give up */
}
}
if (evlog != NULL) {
(void) fprintf(mail, "\n\n%s : %s : %s : ", evlog->submithost, timebuf,
evlog->submituser);
@@ -599,6 +610,7 @@ json_add_timestamp(struct json_container *json, const char *name,
const struct timespec *ts, bool format_timestamp)
{
struct json_value json_value;
int len;
debug_decl(json_add_timestamp, SUDO_DEBUG_PLUGIN);
if (!sudo_json_open_object(json, name))
@@ -622,19 +634,25 @@ json_add_timestamp(struct json_container *json, const char *name,
struct tm gmt;
if (gmtime_r(&secs, &gmt) != NULL) {
strftime(timebuf, sizeof(timebuf), "%Y%m%d%H%M%SZ", &gmt);
timebuf[sizeof(timebuf) - 1] = '\0';
len = strftime(timebuf, sizeof(timebuf), "%Y%m%d%H%M%SZ", &gmt);
if (len != 0 && timebuf[sizeof(timebuf) - 1] == '\0') {
json_value.type = JSON_STRING;
json_value.u.string = timebuf; // -V507
if (!sudo_json_add_value(json, "iso8601", &json_value))
goto oom;
}
strftime(timebuf, sizeof(timebuf), timefmt, &gmt);
timebuf[sizeof(timebuf) - 1] = '\0';
len = strftime(timebuf, sizeof(timebuf), timefmt, &gmt);
if (len != 0 && timebuf[sizeof(timebuf) - 1] == '\0') {
json_value.type = JSON_STRING;
json_value.u.string = timebuf; // -V507
if (!sudo_json_add_value(json, "localtime", &json_value))
goto oom;
}
}
}
if (!sudo_json_close_object(json))
goto oom;

View File

@@ -128,11 +128,12 @@ static struct iolog_path_escape path_escapes[] = {
static int
do_check(char *dir_in, char *file_in, char *tdir_out, char *tfile_out)
{
char dir[PATH_MAX], dir_out[PATH_MAX];
char file[PATH_MAX], file_out[PATH_MAX];
char dir[PATH_MAX], dir_out[PATH_MAX] = "";
char file[PATH_MAX], file_out[PATH_MAX] = "";
int error = 0;
struct tm tm;
time_t now;
int error = 0;
int len;
/*
* Expand any strftime(3) escapes
@@ -141,8 +142,16 @@ do_check(char *dir_in, char *file_in, char *tdir_out, char *tfile_out)
time(&now);
if (localtime_r(&now, &tm) == NULL)
sudo_fatal("localtime_r");
strftime(dir_out, sizeof(dir_out), tdir_out, &tm);
strftime(file_out, sizeof(file_out), tfile_out, &tm);
if (tdir_out[0] != '\0') {
len = strftime(dir_out, sizeof(dir_out), tdir_out, &tm);
if (len == 0 || dir_out[sizeof(dir_out) - 1] != '\0')
sudo_fatalx("dir_out: strftime overflow");
}
if (tfile_out[0] != '\0') {
len = strftime(file_out, sizeof(file_out), tfile_out, &tm);
if (len == 0 || file_out[sizeof(file_out) - 1] != '\0')
sudo_fatalx("file_out: strftime overflow");
}
if (!expand_iolog_path(dir_in, dir, sizeof(dir), &path_escapes[1], NULL))
sudo_fatalx("unable to expand I/O log dir");

View File

@@ -620,8 +620,9 @@ sudo_debug_write2_v1(int fd, const char *func, const char *file, int lineno,
struct tm tm;
size_t tlen;
if (localtime_r(&now, &tm) != NULL) {
timebuf[sizeof(timebuf) - 1] = '\0';
tlen = strftime(timebuf, sizeof(timebuf), "%b %e %H:%M:%S", &tm);
if (tlen == 0) {
if (tlen == 0 || timebuf[sizeof(timebuf) - 1] != '\0') {
/* contents are undefined on error */
timebuf[0] = '\0';
} else {

View File

@@ -342,6 +342,7 @@ add_timestamp(struct json_container *json, struct timespec *ts)
time_t secs = ts->tv_sec;
char timebuf[1024];
struct tm gmt;
int len;
debug_decl(add_timestamp, SUDO_DEBUG_PLUGIN);
if (gmtime_r(&secs, &gmt) == NULL)
@@ -357,15 +358,21 @@ add_timestamp(struct json_container *json, struct timespec *ts)
json_value.u.number = ts->tv_nsec;
sudo_json_add_value(json, "nanoseconds", &json_value);
strftime(timebuf, sizeof(timebuf), "%Y%m%d%H%M%SZ", &gmt);
timebuf[sizeof(timebuf) - 1] = '\0';
len = strftime(timebuf, sizeof(timebuf), "%Y%m%d%H%M%SZ", &gmt);
if (len != 0 && timebuf[sizeof(timebuf) - 1] == '\0'){
json_value.type = JSON_STRING;
json_value.u.string = timebuf;
sudo_json_add_value(json, "iso8601", &json_value);
}
strftime(timebuf, sizeof(timebuf), "%a %b %e %H:%M:%S %Z %Y", &gmt);
timebuf[sizeof(timebuf) - 1] = '\0';
len = strftime(timebuf, sizeof(timebuf), "%a %b %e %H:%M:%S %Z %Y", &gmt);
if (len != 0 && timebuf[sizeof(timebuf) - 1] == '\0'){
json_value.type = JSON_STRING;
json_value.u.string = timebuf;
sudo_json_add_value(json, "localtime", &json_value);
}
sudo_json_close_object(json);

View File

@@ -593,12 +593,13 @@ print_cmndspec_json(struct json_container *jsonc,
struct sudoers_parse_tree *parse_tree, struct cmndspec *cs,
struct cmndspec **nextp, struct defaults_list *options, bool expand_aliases)
{
char timebuf[sizeof("20120727121554Z")];
struct cmndspec *next = *nextp;
struct json_value value;
struct defaults *def;
struct member *m;
struct tm gmt;
char timebuf[sizeof("20120727121554Z")];
int len;
debug_decl(print_cmndspec_json, SUDOERS_DEBUG_UTIL);
/* Open Cmnd_Spec object. */
@@ -650,7 +651,9 @@ print_cmndspec_json(struct json_container *jsonc,
if (gmtime_r(&cs->notbefore, &gmt) == NULL) {
sudo_warn("%s", U_("unable to get GMT time"));
} else {
if (strftime(timebuf, sizeof(timebuf), "%Y%m%d%H%M%SZ", &gmt) == 0) {
timebuf[sizeof(timebuf) - 1] = '\0';
len = strftime(timebuf, sizeof(timebuf), "%Y%m%d%H%M%SZ", &gmt);
if (len == 0 || timebuf[sizeof(timebuf) - 1] != '\0') {
sudo_warnx("%s", U_("unable to format timestamp"));
} else {
value.type = JSON_STRING;
@@ -663,7 +666,9 @@ print_cmndspec_json(struct json_container *jsonc,
if (gmtime_r(&cs->notafter, &gmt) == NULL) {
sudo_warn("%s", U_("unable to get GMT time"));
} else {
if (strftime(timebuf, sizeof(timebuf), "%Y%m%d%H%M%SZ", &gmt) == 0) {
timebuf[sizeof(timebuf) - 1] = '\0';
len = strftime(timebuf, sizeof(timebuf), "%Y%m%d%H%M%SZ", &gmt);
if (len == 0 || timebuf[sizeof(timebuf) - 1] != '\0') {
sudo_warnx("%s", U_("unable to format timestamp"));
} else {
value.type = JSON_STRING;

View File

@@ -316,12 +316,13 @@ static void
print_cmndspec_ldif(FILE *fp, struct sudoers_parse_tree *parse_tree,
struct cmndspec *cs, struct cmndspec **nextp, struct defaults_list *options)
{
char timebuf[sizeof("20120727121554Z")];
struct cmndspec *next = *nextp;
struct member *m;
struct tm gmt;
char *attr_val;
bool last_one;
char timebuf[sizeof("20120727121554Z")];
int len;
debug_decl(print_cmndspec_ldif, SUDOERS_DEBUG_UTIL);
/* Print runasuserlist as sudoRunAsUser attributes */
@@ -345,7 +346,9 @@ print_cmndspec_ldif(FILE *fp, struct sudoers_parse_tree *parse_tree,
if (gmtime_r(&cs->notbefore, &gmt) == NULL) {
sudo_warn("%s", U_("unable to get GMT time"));
} else {
if (strftime(timebuf, sizeof(timebuf), "%Y%m%d%H%M%SZ", &gmt) == 0) {
timebuf[sizeof(timebuf) - 1] = '\0';
len = strftime(timebuf, sizeof(timebuf), "%Y%m%d%H%M%SZ", &gmt);
if (len == 0 || timebuf[sizeof(timebuf) - 1] != '\0') {
sudo_warnx("%s", U_("unable to format timestamp"));
} else {
print_attribute_ldif(fp, "sudoNotBefore", timebuf);
@@ -356,7 +359,9 @@ print_cmndspec_ldif(FILE *fp, struct sudoers_parse_tree *parse_tree,
if (gmtime_r(&cs->notafter, &gmt) == NULL) {
sudo_warn("%s", U_("unable to get GMT time"));
} else {
if (strftime(timebuf, sizeof(timebuf), "%Y%m%d%H%M%SZ", &gmt) == 0) {
timebuf[sizeof(timebuf) - 1] = '\0';
len = strftime(timebuf, sizeof(timebuf), "%Y%m%d%H%M%SZ", &gmt);
if (len == 0 || timebuf[sizeof(timebuf) - 1] != '\0') {
sudo_warnx("%s", U_("unable to format timestamp"));
} else {
print_attribute_ldif(fp, "sudoNotAfter", timebuf);

View File

@@ -240,18 +240,20 @@ sudoers_format_cmndspec(struct sudo_lbuf *lbuf,
sudo_lbuf_append(lbuf, "TIMEOUT=%s ", numbuf);
}
if (cs->notbefore != UNSPEC && FIELD_CHANGED(prev_cs, cs, notbefore)) {
char buf[sizeof("CCYYMMDDHHMMSSZ")];
char buf[sizeof("CCYYMMDDHHMMSSZ")] = "";
struct tm gmt;
if (gmtime_r(&cs->notbefore, &gmt) != NULL) {
if (strftime(buf, sizeof(buf), "%Y%m%d%H%M%SZ", &gmt) != 0)
int len = strftime(buf, sizeof(buf), "%Y%m%d%H%M%SZ", &gmt);
if (len != 0 && buf[sizeof(buf) - 1] == '\0')
sudo_lbuf_append(lbuf, "NOTBEFORE=%s ", buf);
}
}
if (cs->notafter != UNSPEC && FIELD_CHANGED(prev_cs, cs, notafter)) {
char buf[sizeof("CCYYMMDDHHMMSSZ")];
char buf[sizeof("CCYYMMDDHHMMSSZ")] = "";
struct tm gmt;
if (gmtime_r(&cs->notafter, &gmt) != NULL) {
if (strftime(buf, sizeof(buf), "%Y%m%d%H%M%SZ", &gmt) != 0)
int len = strftime(buf, sizeof(buf), "%Y%m%d%H%M%SZ", &gmt);
if (len != 0 && buf[sizeof(buf) - 1] == '\0')
sudo_lbuf_append(lbuf, "NOTAFTER=%s ", buf);
}
}

View File

@@ -491,10 +491,11 @@ done:
static bool
sudo_ldap_timefilter(char *buffer, size_t buffersize)
{
char timebuffer[sizeof("20120727121554.0Z")];
bool ret = false;
struct tm gmt;
time_t now;
char timebuffer[sizeof("20120727121554.0Z")];
int len = -1;
int len;
debug_decl(sudo_ldap_timefilter, SUDOERS_DEBUG_LDAP);
/* Make sure we have a formatted timestamp for __now__. */
@@ -505,7 +506,9 @@ sudo_ldap_timefilter(char *buffer, size_t buffersize)
}
/* Format the timestamp according to the RFC. */
if (strftime(timebuffer, sizeof(timebuffer), "%Y%m%d%H%M%S.0Z", &gmt) == 0) {
timebuffer[sizeof(timebuffer) - 1] = '\0';
len = strftime(timebuffer, sizeof(timebuffer), "%Y%m%d%H%M%S.0Z", &gmt);
if (len == 0 || timebuffer[sizeof(timebuffer) - 1] != '\0') {
sudo_warnx("%s", U_("unable to format timestamp"));
goto done;
}
@@ -516,11 +519,13 @@ sudo_ldap_timefilter(char *buffer, size_t buffersize)
if (len < 0 || (size_t)len >= buffersize) {
sudo_warnx(U_("internal error, %s overflow"), __func__);
errno = EOVERFLOW;
len = -1;
goto done;
}
ret = true;
done:
debug_return_bool(len != -1);
debug_return_bool(ret);
}
/*

View File

@@ -621,18 +621,22 @@ display_priv_long(struct sudoers_parse_tree *parse_tree, struct passwd *pw,
sudo_lbuf_append(lbuf, " Timeout: %s\n", numbuf);
}
if (cs->notbefore != UNSPEC) {
char buf[sizeof("CCYYMMDDHHMMSSZ")];
char buf[sizeof("CCYYMMDDHHMMSSZ")] = "";
struct tm gmt;
int len;
if (gmtime_r(&cs->notbefore, &gmt) != NULL) {
if (strftime(buf, sizeof(buf), "%Y%m%d%H%M%SZ", &gmt) != 0)
len = strftime(buf, sizeof(buf), "%Y%m%d%H%M%SZ", &gmt);
if (len != 0 && buf[sizeof(buf) - 1] == '\0')
sudo_lbuf_append(lbuf, " NotBefore: %s\n", buf);
}
}
if (cs->notafter != UNSPEC) {
char buf[sizeof("CCYYMMDDHHMMSSZ")];
char buf[sizeof("CCYYMMDDHHMMSSZ")] = "";
struct tm gmt;
int len;
if (gmtime_r(&cs->notafter, &gmt) != NULL) {
if (strftime(buf, sizeof(buf), "%Y%m%d%H%M%SZ", &gmt) != 0)
len = strftime(buf, sizeof(buf), "%Y%m%d%H%M%SZ", &gmt);
if (len != 0 && buf[sizeof(buf) - 1] == '\0')
sudo_lbuf_append(lbuf, " NotAfter: %s\n", buf);
}
}

View File

@@ -38,12 +38,14 @@ get_timestr(time_t tstamp, int log_year)
{
static char buf[128];
struct tm tm;
int len;
if (localtime_r(&tstamp, &tm) != NULL) {
/* strftime() does not guarantee to NUL-terminate so we must check. */
buf[sizeof(buf) - 1] = '\0';
if (strftime(buf, sizeof(buf), log_year ? "%h %e %T %Y" : "%h %e %T",
&tm) != 0 && buf[sizeof(buf) - 1] == '\0')
len = strftime(buf, sizeof(buf), log_year ? "%h %e %T %Y" : "%h %e %T",
&tm);
if (len != 0 && buf[sizeof(buf) - 1] == '\0')
return buf;
}
return NULL;