Skip to content

Commit a676f31

Browse files
author
Felipe Zimmerle
committed
Initial support for Lua script engine
1 parent 1866a3a commit a676f31

19 files changed

+1271
-60
lines changed

CHANGES

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
v3.0.????? - ?
33
---------------------------
44

5+
- Adds initial support for Lua engine.
6+
[Issue #994 - @zimmerle]
57
- Adds support for @inspectFile operator.
68
[Issue #999 - @zimmerle, @victorhora]
79
- Adds support for RESOURCE variable collection.

src/Makefile.am

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ noinst_HEADERS = \
7979

8080

8181
ENGINES = \
82-
engines/lua.cc
82+
engine/lua.cc
8383

8484

8585
VARIABLES = \

src/engine/lua.cc

Lines changed: 377 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,377 @@
1+
/*
2+
* ModSecurity, http://www.modsecurity.org/
3+
* Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
4+
*
5+
* You may not use this file except in compliance with
6+
* the License. You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* If any of the files related to licensing are missing or if you have any
11+
* other questions related to licensing please contact Trustwave Holdings, Inc.
12+
* directly using the email address security@modsecurity.org.
13+
*
14+
*/
15+
16+
17+
#include "modsecurity/modsecurity.h"
18+
#include "src/engine/lua.h"
19+
#include "src/utils/string.h"
20+
#include "src/macro_expansion.h"
21+
#include "modsecurity/transaction.h"
22+
#include "modsecurity/collection/variable.h"
23+
#include "src/variables/variable.h"
24+
#include "src/variables/highest_severity.h"
25+
#include "src/utils/string.h"
26+
#include "src/actions/transformations/transformation.h"
27+
28+
#include <vector>
29+
#include <string>
30+
#include <algorithm>
31+
#include <sstream>
32+
#include <iterator>
33+
#include <iostream>
34+
35+
#include <stdio.h>
36+
#include <string.h>
37+
38+
39+
namespace modsecurity {
40+
namespace engine {
41+
42+
43+
bool Lua::isCompatible(std::string script, Lua *l, std::string *error) {
44+
std::string lua(".lua");
45+
std::string err;
46+
47+
if (!(script.size() >= lua.size() &&
48+
script.compare(script.size() - lua.size(), lua.size(), lua) == 0))
49+
{
50+
error->assign("Expecting a Lua script: " + script);
51+
return false;
52+
}
53+
54+
if (l->load(script, &err) == false) {
55+
error->assign("Problems load script: " + err);
56+
return false;
57+
}
58+
59+
return true;
60+
}
61+
62+
63+
bool Lua::load(std::string script, std::string *err) {
64+
lua_State *L = NULL;
65+
L = luaL_newstate();
66+
luaL_openlibs(L);
67+
68+
m_scriptName = script;
69+
if (luaL_loadfile(L, script.c_str())) {
70+
const char *luaerr = lua_tostring(L, -1);
71+
err->assign("Failed to compile script '" + script + "");
72+
if (luaerr) {
73+
err->append(": " + *luaerr);
74+
}
75+
err->append(".");
76+
lua_close(L);
77+
78+
return false;
79+
}
80+
81+
if (lua_dump(L, Lua::blob_keeper, (void *)&m_blob, 0)) {
82+
const char *luaerr = lua_tostring(L, -1);
83+
err->assign("Failed to compile script '" + script + "");
84+
if (luaerr) {
85+
err->append(": " + *luaerr);
86+
}
87+
err->append(".");
88+
lua_close(L);
89+
90+
return false;
91+
}
92+
93+
94+
lua_close(L);
95+
return true;
96+
}
97+
98+
99+
int Lua::blob_keeper(lua_State *L, const void *p, size_t sz, void *ud) {
100+
LuaScriptBlob *lsb = static_cast<LuaScriptBlob *>(ud);
101+
lsb->write(p, sz);
102+
return 0;
103+
}
104+
105+
106+
const char *Lua::blob_reader(lua_State *L, void *ud, size_t *size) {
107+
LuaScriptBlob *lsb = static_cast<LuaScriptBlob *>(ud);
108+
const char *data = lsb->read(size);
109+
return data;
110+
}
111+
112+
113+
int Lua::run(Transaction *t) {
114+
std::string luaRet;
115+
lua_State *L = luaL_newstate();
116+
luaL_openlibs(L);
117+
118+
luaL_newmetatable(L, "luaL_msc");
119+
lua_newtable(L);
120+
121+
lua_pushlightuserdata(L, (void *)t);
122+
lua_setglobal(L, "__transaction");
123+
124+
luaL_setfuncs(L, mscLuaLib, 0);
125+
lua_setglobal(L, "m");
126+
127+
int rc = lua_load(L, Lua::blob_reader, &m_blob, m_scriptName.c_str(),
128+
NULL);
129+
if (rc != LUA_OK) {
130+
std::string e;
131+
e.assign("Failed to execute lua script: " + m_scriptName + ". ");
132+
switch (rc) {
133+
case LUA_ERRSYNTAX:
134+
e.assign("Syntax error. ");
135+
break;
136+
case LUA_ERRMEM:
137+
e.assign("Memory error. ");
138+
break;
139+
case LUA_ERRGCMM:
140+
e.assign("Garbage Collector error. ");
141+
break;
142+
}
143+
e.append(lua_tostring(L, -1));
144+
t->debug(2, e);
145+
return false;
146+
}
147+
148+
if (lua_pcall(L, 0, 0, 0)) {
149+
std::string e;
150+
const char *luaerr = lua_tostring(L, -1);
151+
e.assign("Failed to execute lua script: " + m_scriptName \
152+
+ " (before main)");
153+
if (luaerr != NULL) {
154+
e.append(" - ");
155+
e.append(luaerr);
156+
}
157+
t->debug(2, e);
158+
return false;
159+
}
160+
161+
lua_setglobal(L, "modsec");
162+
163+
lua_getglobal(L, "main");
164+
if (lua_pcall(L, 0, 1, 0)) {
165+
std::string e;
166+
const char *luaerr = lua_tostring(L, -1);
167+
e.assign("Failed to execute lua script: " + m_scriptName + " (main)");
168+
if (luaerr != NULL) {
169+
e.append(" - ");
170+
e.append(luaerr);
171+
}
172+
t->debug(2, e);
173+
return false;
174+
}
175+
176+
char *a = (char *)lua_tostring(L, -1);
177+
if (a != NULL) {
178+
luaRet.assign(a);
179+
}
180+
181+
t->debug(9, "Returning from lua script: " + luaRet);
182+
183+
lua_pop(L, 1);
184+
lua_close(L);
185+
186+
if (luaRet.size() == 0) {
187+
return false;
188+
}
189+
190+
return true;
191+
}
192+
193+
194+
int Lua::log(lua_State *L) {
195+
Transaction *t = NULL;
196+
const char *text;
197+
int level;
198+
199+
/* Retrieve parameters. */
200+
level = luaL_checknumber(L, 1);
201+
text = luaL_checkstring(L, 2);
202+
203+
/* Retrieve msr. */
204+
lua_getglobal(L, "__transaction");
205+
t = (Transaction *)lua_topointer(L, -1);
206+
207+
/* Log message. */
208+
if (t != NULL) {
209+
t->debug(level, text);
210+
}
211+
212+
return 0;
213+
}
214+
215+
216+
int Lua::getvar(lua_State *L) {
217+
char *varname = NULL;
218+
Transaction *t = NULL;
219+
220+
/* Retrieve parameters. */
221+
varname = (char *)luaL_checkstring(L, 1);
222+
223+
lua_getglobal(L, "__transaction");
224+
t = (Transaction *)lua_topointer(L, -1);
225+
226+
std::string var = Variables::Variable::stringMatchResolve(t, varname);
227+
var = applyTransformations(L, t, 2, var);
228+
229+
if (var.size() == 0) {
230+
lua_pushnil(L);
231+
return 0;
232+
}
233+
234+
lua_pushlstring(L, var.c_str(), var.size());
235+
236+
return 1;
237+
}
238+
239+
240+
int Lua::getvars(lua_State *L) {
241+
char *varname = NULL;
242+
Transaction *t = NULL;
243+
std::vector<const collection::Variable *> l;
244+
int idx = 1;
245+
246+
/* Retrieve parameters. */
247+
varname = (char *)luaL_checkstring(L, 1);
248+
249+
lua_getglobal(L, "__transaction");
250+
t = (Transaction *)lua_topointer(L, -1);
251+
252+
Variables::Variable::stringMatchResolveMulti(t, varname, &l);
253+
254+
lua_newtable(L);
255+
for (auto i : l) {
256+
lua_pushnumber(L, idx);
257+
lua_newtable(L);
258+
259+
lua_pushstring(L, "name");
260+
lua_pushlstring(L, i->m_key.c_str(), i->m_key.size());
261+
lua_settable(L, -3);
262+
263+
lua_pushstring(L, "value");
264+
lua_pushlstring(L, i->m_value.c_str(), i->m_value.size());
265+
lua_settable(L, -3);
266+
267+
lua_settable(L, -3);
268+
idx++;
269+
}
270+
271+
return 1;
272+
}
273+
274+
275+
int Lua::setvar(lua_State *L) {
276+
Transaction *t = NULL;
277+
const char *var_value = NULL;
278+
const char *var_name = NULL;
279+
std::string vname;
280+
std::string collection;
281+
std::string variableName;
282+
int nargs = lua_gettop(L);
283+
char *chr = NULL;
284+
size_t pos;
285+
286+
lua_getglobal(L, "__transaction");
287+
t = (Transaction *)lua_topointer(L, -1);
288+
289+
if (nargs != 2) {
290+
t->debug(8, "m.setvar: Failed m.setvar funtion must has 2 arguments");
291+
return -1;
292+
}
293+
var_value = luaL_checkstring(L, 2);
294+
var_name = luaL_checkstring(L, 1);
295+
296+
lua_pop(L, 2);
297+
298+
if (var_value == NULL || var_name == NULL) {
299+
return -1;
300+
}
301+
302+
vname.assign(var_name);
303+
pos = vname.find(".");
304+
if (pos != std::string::npos) {
305+
collection = std::string(vname, 0, pos);
306+
collection = utils::string::toupper(collection);
307+
variableName = std::string(vname, pos + 1,
308+
std::string::npos);
309+
310+
} else {
311+
t->debug(8, "m.setvar: Must specify a collection using dot character" \
312+
" - ie m.setvar(tx.myvar,mydata)");
313+
return -1;
314+
}
315+
316+
t->m_collections.storeOrUpdateFirst(collection,
317+
variableName, var_value);
318+
}
319+
320+
321+
std::string Lua::applyTransformations(lua_State *L, Transaction *t, int idx, std::string var) {
322+
std::string newVar = var;
323+
324+
if (lua_isuserdata(L, idx) || lua_isnoneornil(L, idx)) {
325+
return var;
326+
}
327+
328+
if (lua_istable(L, idx)) {
329+
char *name = NULL;
330+
int i, n = lua_rawlen(L, idx);
331+
332+
for (i = 1; i <= n; i++) {
333+
lua_rawgeti(L, idx, i);
334+
name = (char *)luaL_checkstring(L, -1);
335+
336+
/* A "none" means start over */
337+
if (strcmp("none", name) == 0) {
338+
newVar = var;
339+
continue;
340+
}
341+
342+
actions::transformations::Transformation *tfn = actions::transformations::Transformation::instantiate("t:" + std::string(name));
343+
// FIXME: transformation is not yet returning null.
344+
if (tfn) {
345+
newVar = tfn->evaluate(newVar, t);
346+
} else {
347+
t->debug(1, "SecRuleScript: Invalid transformation function: " + std::string(name));
348+
}
349+
}
350+
351+
return newVar;
352+
}
353+
354+
if (lua_isstring(L, idx)) {
355+
char *name = (char *)luaL_checkstring(L, idx);
356+
357+
actions::transformations::Transformation *tfn = actions::transformations::Transformation::instantiate("t:" + std::string(name));
358+
// FIXME: transformation is not yet returning null.
359+
if (tfn) {
360+
newVar = tfn->evaluate(newVar, t);
361+
} else {
362+
t->debug(1, "SecRuleScript: Invalid transformation function: " + std::string(name));
363+
}
364+
return newVar;
365+
}
366+
367+
t->debug(8, "SecRuleScript: Transformation parameter must be a " \
368+
"transformation name or array of transformation names, but found " \
369+
"" + std::string(lua_typename(L, idx)) + " (type " \
370+
+ std::to_string(lua_type(L, idx)) + ")");
371+
372+
return newVar;
373+
}
374+
375+
376+
} // namespace engines
377+
} // namespace modsecurity

0 commit comments

Comments
 (0)