diff mbox series

lua: Prevent mtdname and path from clobering each other

Message ID 20200626211036.7535-1-JPEWhacker@gmail.com
State Changes Requested
Headers show
Series lua: Prevent mtdname and path from clobering each other | expand

Commit Message

Joshua Watt June 26, 2020, 9:10 p.m. UTC
The lua properties "mtdname" and "path" are both initialized to the path
property in struct img_type, and both values were written back to the
path property when update struct img_type from the lua table. This means
that which ever one was encountered last when iterating would be the one
assigned to actual path property. This in particular causes problems
when attempting to chain to another handler that uses the path property
from lua, for example the following lua code could randomly fail if
mtdname was parsed last when chaining handlers:

 function my_handler(image)
   image.path = "/foo/bar"
   swupdate.call_handler("archive", image)
 end

To resolve this, implement custom __index and __newindex metamethods
that alias "mtdname" to "path".

This also fixed that "private" properties could be accessed directly as
image["offset"], since the __index table was the private table (meaning
any missing key lookups would fall back to keys of the private table).
Now, they can only be accessed through the "_private" property, as in
image["_private"]["offset"] (and as documented)

Signed-off-by: Joshua Watt <JPEWhacker@gmail.com>
---
 corelib/lua_interface.c | 67 ++++++++++++++++++++++++++++++++++++++---
 1 file changed, 62 insertions(+), 5 deletions(-)
diff mbox series

Patch

diff --git a/corelib/lua_interface.c b/corelib/lua_interface.c
index 219ee41..e4c300a 100644
--- a/corelib/lua_interface.c
+++ b/corelib/lua_interface.c
@@ -278,9 +278,6 @@  static void lua_string_to_img(struct img_type *img, const char *key,
 	if (!strcmp(key, "device"))
 		strncpy(img->device, value,
 			sizeof(img->device));
-	if (!strcmp(key, "mtdname"))
-		strncpy(img->path, value,
-			sizeof(img->path));
 	if (!strcmp(key, "path"))
 		strncpy(img->path, value,
 			sizeof(img->path));
@@ -477,7 +474,6 @@  static void update_table(lua_State* L, struct img_type *img)
 		LUA_PUSH_IMG_STRING(img, "type", type);
 		LUA_PUSH_IMG_STRING(img, "device", device);
 		LUA_PUSH_IMG_STRING(img, "path", path);
-		LUA_PUSH_IMG_STRING(img, "mtdname", path);
 		LUA_PUSH_IMG_STRING(img, "data", type_data);
 		LUA_PUSH_IMG_STRING(img, "filesystem", filesystem);
 		LUA_PUSH_IMG_STRING(img, "ivt", ivt_ascii);
@@ -562,6 +558,58 @@  static int l_istream_fclose(lua_State *L)
 #endif
 #endif
 
+static int imagetable_getindex(lua_State* L)
+{
+	if (lua_isstring(L, -1)) {
+		char const* key = lua_tostring(L, -1);
+
+		if (!strcmp(key, "_private")) {
+			/* Look up _private in the metatable */
+			lua_getmetatable(L, -2);
+			lua_pushstring(L, key);
+			lua_rawget(L, -2);
+			/* Remove metatable from stack */
+			lua_remove(L, -2);
+			return 1;
+		}
+
+		if (!strcmp(key, "mtdname"))
+			key = "path";
+
+		lua_pushstring(L, key);
+	} else {
+		lua_pushvalue(L, -1);
+	}
+
+	lua_rawget(L, -3);
+
+	return 1;
+}
+
+static int imagetable_newindex(lua_State* L)
+{
+	if (lua_isstring(L, -2)) {
+		char const* key = lua_tostring(L, -2);
+
+		/* Private cannot be set */
+		if (!strcmp(key, "_private"))
+			return 0;
+
+		if (!strcmp(key, "mtdname"))
+			key = "path";
+
+		lua_pushstring(L, key);
+		lua_pushvalue(L, -2);
+	} else {
+		lua_pushvalue(L, -2);
+		lua_pushvalue(L, -2);
+	}
+
+	lua_rawset(L, -5);
+
+	return 0;
+}
+
 static void image2table(lua_State* L, struct img_type *img)
 {
 	if (L && img) {
@@ -577,13 +625,22 @@  static void image2table(lua_State* L, struct img_type *img)
 		 * accessible by image["_private"]["offset"].
 		 * This access pattern strongly hints not to mess with the
 		 * image["_private"] table values from within the Lua realm.
+		 *
+		 * Custom __index and __newindex methods are used so that
+		 * "mtdname" can be an alias of "path"
 		 */
 		lua_newtable(L);
-		lua_pushvalue(L, -1);
+
 		lua_pushstring(L, "_private");
 		lua_newtable(L);
 		lua_settable(L, -3);
+
+		lua_pushcfunction(L, imagetable_getindex);
 		lua_setfield(L, -2, "__index");
+
+		lua_pushcfunction(L, imagetable_newindex);
+		lua_setfield(L, -2, "__newindex");
+
 		lua_setmetatable(L, -2);
 
 		update_table(L, img);