From de96e26afc690957a1b14380ea589c10b9b9e162 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Mon, 18 Jul 2016 14:58:58 -0300 Subject: [PATCH] bug: 'checkoption' could read past end of string + 'os.date' can handle embedded zeros --- loslib.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/loslib.c b/loslib.c index 4563d2e0..dd2bb378 100644 --- a/loslib.c +++ b/loslib.c @@ -1,5 +1,5 @@ /* -** $Id: loslib.c,v 1.63 2016/02/09 12:16:11 roberto Exp roberto $ +** $Id: loslib.c,v 1.64 2016/04/18 13:06:55 roberto Exp $ ** Standard Operating System library ** See Copyright Notice in lua.h */ @@ -30,16 +30,16 @@ */ #if !defined(LUA_STRFTIMEOPTIONS) /* { */ -/* options for ANSI C 89 */ +/* options for ANSI C 89 (only 1-char options) */ #define L_STRFTIMEC89 "aAbBcdHIjmMpSUwWxXyYZ%" /* options for ISO C 99 and POSIX */ #define L_STRFTIMEC99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \ - "||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" + "||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */ /* options for Windows */ #define L_STRFTIMEWIN "aAbBcdHIjmMpSUwWxXyYzZ%" \ - "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" + "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */ #if defined(LUA_USE_WINDOWS) #define LUA_STRFTIMEOPTIONS L_STRFTIMEWIN @@ -257,12 +257,13 @@ static int getfield (lua_State *L, const char *key, int d, int delta) { } -static const char *checkoption (lua_State *L, const char *conv, char *buff) { - const char *option; - int oplen = 1; - for (option = LUA_STRFTIMEOPTIONS; *option != '\0'; option += oplen) { +static const char *checkoption (lua_State *L, const char *conv, + ptrdiff_t convlen, char *buff) { + const char *option = LUA_STRFTIMEOPTIONS; + int oplen = 1; /* length of options being checked */ + for (; *option != '\0' && oplen <= convlen; option += oplen) { if (*option == '|') /* next block? */ - oplen++; /* next length */ + oplen++; /* will check options with next length (+1) */ else if (memcmp(conv, option, oplen) == 0) { /* match? */ memcpy(buff, conv, oplen); /* copy valid option to buffer */ buff[oplen] = '\0'; @@ -280,8 +281,10 @@ static const char *checkoption (lua_State *L, const char *conv, char *buff) { static int os_date (lua_State *L) { - const char *s = luaL_optstring(L, 1, "%c"); + size_t slen; + const char *s = luaL_optlstring(L, 1, "%c", &slen); time_t t = luaL_opt(L, l_checktime, 2, time(NULL)); + const char *se = s + slen; /* 's' end */ struct tm tmr, *stm; if (*s == '!') { /* UTC? */ stm = l_gmtime(&t, &tmr); @@ -300,13 +303,14 @@ static int os_date (lua_State *L) { luaL_Buffer b; cc[0] = '%'; luaL_buffinit(L, &b); - while (*s) { + while (s < se) { if (*s != '%') /* not a conversion specifier? */ luaL_addchar(&b, *s++); else { size_t reslen; char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT); - s = checkoption(L, s + 1, cc + 1); /* copy specifier to 'cc' */ + s++; /* skip '%' */ + s = checkoption(L, s, se - s, cc + 1); /* copy specifier to 'cc' */ reslen = strftime(buff, SIZETIMEFMT, cc, stm); luaL_addsize(&b, reslen); }