提交 8783fb94 编写于 作者: A antirez

Security: update Lua struct package for security.

During an auditing Apple found that the "struct" Lua package
we ship with Redis (http://www.inf.puc-rio.br/~roberto/struct/) contains
a security problem. A bound-checking statement fails because of integer
overflow. The bug exists since we initially integrated this package with
Lua, when scripting was introduced, so every version of Redis with
EVAL/EVALSHA capabilities exposed is affected.

Instead of just fixing the bug, the library was updated to the latest
version shipped by the author.
上级 8cb9344b
/* /*
** {====================================================== ** {======================================================
** Library for packing/unpacking structures. ** Library for packing/unpacking structures.
** $Id: struct.c,v 1.4 2012/07/04 18:54:29 roberto Exp $ ** $Id: struct.c,v 1.7 2018/05/11 22:04:31 roberto Exp $
** See Copyright Notice at the end of this file ** See Copyright Notice at the end of this file
** ======================================================= ** =======================================================
*/ */
...@@ -15,8 +15,8 @@ ...@@ -15,8 +15,8 @@
** h/H - signed/unsigned short ** h/H - signed/unsigned short
** l/L - signed/unsigned long ** l/L - signed/unsigned long
** T - size_t ** T - size_t
** i/In - signed/unsigned integer with size `n' (default is size of int) ** i/In - signed/unsigned integer with size 'n' (default is size of int)
** cn - sequence of `n' chars (from/to a string); when packing, n==0 means ** cn - sequence of 'n' chars (from/to a string); when packing, n==0 means
the whole string; when unpacking, n==0 means use the previous the whole string; when unpacking, n==0 means use the previous
read number as the string length read number as the string length
** s - zero-terminated string ** s - zero-terminated string
...@@ -89,14 +89,12 @@ typedef struct Header { ...@@ -89,14 +89,12 @@ typedef struct Header {
} Header; } Header;
static int getnum (lua_State *L, const char **fmt, int df) { static int getnum (const char **fmt, int df) {
if (!isdigit(**fmt)) /* no number? */ if (!isdigit(**fmt)) /* no number? */
return df; /* return default value */ return df; /* return default value */
else { else {
int a = 0; int a = 0;
do { do {
if (a > (INT_MAX / 10) || a * 10 > (INT_MAX - (**fmt - '0')))
luaL_error(L, "integral size overflow");
a = a*10 + *((*fmt)++) - '0'; a = a*10 + *((*fmt)++) - '0';
} while (isdigit(**fmt)); } while (isdigit(**fmt));
return a; return a;
...@@ -117,9 +115,9 @@ static size_t optsize (lua_State *L, char opt, const char **fmt) { ...@@ -117,9 +115,9 @@ static size_t optsize (lua_State *L, char opt, const char **fmt) {
case 'f': return sizeof(float); case 'f': return sizeof(float);
case 'd': return sizeof(double); case 'd': return sizeof(double);
case 'x': return 1; case 'x': return 1;
case 'c': return getnum(L, fmt, 1); case 'c': return getnum(fmt, 1);
case 'i': case 'I': { case 'i': case 'I': {
int sz = getnum(L, fmt, sizeof(int)); int sz = getnum(fmt, sizeof(int));
if (sz > MAXINTSIZE) if (sz > MAXINTSIZE)
luaL_error(L, "integral size %d is larger than limit of %d", luaL_error(L, "integral size %d is larger than limit of %d",
sz, MAXINTSIZE); sz, MAXINTSIZE);
...@@ -152,7 +150,7 @@ static void controloptions (lua_State *L, int opt, const char **fmt, ...@@ -152,7 +150,7 @@ static void controloptions (lua_State *L, int opt, const char **fmt,
case '>': h->endian = BIG; return; case '>': h->endian = BIG; return;
case '<': h->endian = LITTLE; return; case '<': h->endian = LITTLE; return;
case '!': { case '!': {
int a = getnum(L, fmt, MAXALIGN); int a = getnum(fmt, MAXALIGN);
if (!isp2(a)) if (!isp2(a))
luaL_error(L, "alignment %d is not a power of 2", a); luaL_error(L, "alignment %d is not a power of 2", a);
h->align = a; h->align = a;
...@@ -296,20 +294,21 @@ static int b_unpack (lua_State *L) { ...@@ -296,20 +294,21 @@ static int b_unpack (lua_State *L) {
size_t ld; size_t ld;
const char *data = luaL_checklstring(L, 2, &ld); const char *data = luaL_checklstring(L, 2, &ld);
size_t pos = luaL_optinteger(L, 3, 1) - 1; size_t pos = luaL_optinteger(L, 3, 1) - 1;
int n = 0; /* number of results */
defaultoptions(&h); defaultoptions(&h);
lua_settop(L, 2);
while (*fmt) { while (*fmt) {
int opt = *fmt++; int opt = *fmt++;
size_t size = optsize(L, opt, &fmt); size_t size = optsize(L, opt, &fmt);
pos += gettoalign(pos, &h, opt, size); pos += gettoalign(pos, &h, opt, size);
luaL_argcheck(L, pos+size <= ld, 2, "data string too short"); luaL_argcheck(L, pos+size <= ld, 2, "data string too short");
luaL_checkstack(L, 1, "too many results"); /* stack space for item + next position */
luaL_checkstack(L, 2, "too many results");
switch (opt) { switch (opt) {
case 'b': case 'B': case 'h': case 'H': case 'b': case 'B': case 'h': case 'H':
case 'l': case 'L': case 'T': case 'i': case 'I': { /* integer types */ case 'l': case 'L': case 'T': case 'i': case 'I': { /* integer types */
int issigned = islower(opt); int issigned = islower(opt);
lua_Number res = getinteger(data+pos, h.endian, issigned, size); lua_Number res = getinteger(data+pos, h.endian, issigned, size);
lua_pushnumber(L, res); lua_pushnumber(L, res); n++;
break; break;
} }
case 'x': { case 'x': {
...@@ -319,25 +318,26 @@ static int b_unpack (lua_State *L) { ...@@ -319,25 +318,26 @@ static int b_unpack (lua_State *L) {
float f; float f;
memcpy(&f, data+pos, size); memcpy(&f, data+pos, size);
correctbytes((char *)&f, sizeof(f), h.endian); correctbytes((char *)&f, sizeof(f), h.endian);
lua_pushnumber(L, f); lua_pushnumber(L, f); n++;
break; break;
} }
case 'd': { case 'd': {
double d; double d;
memcpy(&d, data+pos, size); memcpy(&d, data+pos, size);
correctbytes((char *)&d, sizeof(d), h.endian); correctbytes((char *)&d, sizeof(d), h.endian);
lua_pushnumber(L, d); lua_pushnumber(L, d); n++;
break; break;
} }
case 'c': { case 'c': {
if (size == 0) { if (size == 0) {
if (!lua_isnumber(L, -1)) if (n == 0 || !lua_isnumber(L, -1))
luaL_error(L, "format `c0' needs a previous size"); luaL_error(L, "format 'c0' needs a previous size");
size = lua_tonumber(L, -1); size = lua_tonumber(L, -1);
lua_pop(L, 1); lua_pop(L, 1); n--;
luaL_argcheck(L, pos+size <= ld, 2, "data string too short"); luaL_argcheck(L, size <= ld && pos <= ld - size,
2, "data string too short");
} }
lua_pushlstring(L, data+pos, size); lua_pushlstring(L, data+pos, size); n++;
break; break;
} }
case 's': { case 's': {
...@@ -345,15 +345,15 @@ static int b_unpack (lua_State *L) { ...@@ -345,15 +345,15 @@ static int b_unpack (lua_State *L) {
if (e == NULL) if (e == NULL)
luaL_error(L, "unfinished string in data"); luaL_error(L, "unfinished string in data");
size = (e - (data+pos)) + 1; size = (e - (data+pos)) + 1;
lua_pushlstring(L, data+pos, size - 1); lua_pushlstring(L, data+pos, size - 1); n++;
break; break;
} }
default: controloptions(L, opt, &fmt, &h); default: controloptions(L, opt, &fmt, &h);
} }
pos += size; pos += size;
} }
lua_pushinteger(L, pos + 1); lua_pushinteger(L, pos + 1); /* next position */
return lua_gettop(L) - 2; return n + 1;
} }
...@@ -399,7 +399,7 @@ LUALIB_API int luaopen_struct (lua_State *L) { ...@@ -399,7 +399,7 @@ LUALIB_API int luaopen_struct (lua_State *L) {
/****************************************************************************** /******************************************************************************
* Copyright (C) 2010-2012 Lua.org, PUC-Rio. All rights reserved. * Copyright (C) 2010-2018 Lua.org, PUC-Rio. All rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册