Package: lua5.4
Version: 5.4.4-3
Severity: normal
X-Debbugs-Cc: none, Asher Gordon <asd...@posteo.net>

Dear Maintainer,

I found a bug in which calling lua_toclose() while the "main" stack is
active (i.e., not inside a function which was called by lua_call()), can
sometimes cause memory errors later. As I later found out, this was a
symptom of a bug in lua_settop(). Here is a minimal example showcasing
the bug:
#include <stdio.h>

#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

/* Here's where we do our experimentation. The table returned by the
   Lua program should be given as the sole argument on the Lua
   stack. */
static int experiment(lua_State *L) {
  /* local obj <close> = class:new() */
  lua_getfield(L, -1, "new");
  lua_rotate(L, -2, 1);
  lua_call(L, 1, 1);
  lua_toclose(L, -1);
  lua_pop(L, 1);

  return 0;
}

int main(int argc, char **argv) {
  lua_State *L;
  const char *prog;

  if (argc != 2) {
    fprintf(stderr, "Usage: %s FILE\n", argv[0]);
    return 1;
  }

  prog = argv[1];

  L = luaL_newstate();
  luaL_openlibs(L);

  if (luaL_loadfile(L, prog))
    lua_error(L);

  lua_call(L, 0, 1);

  if (!lua_istable(L, -1))
    luaL_error(L, "%s did not return a table", prog);

#ifdef BAD_CODE
  /* Here's where the error originates! If we call experiment()
     manually like this, closing the value causes memory errors later
     on. Instead, we have to call it through Lua. */
  experiment(L);
#else
  /* This works as expected. */
  lua_pushcfunction(L, experiment);
  lua_rotate(L, -2, 1);
  lua_call(L, 1, 0);
#endif

  lua_close(L);

  return 0;
}
local inspect = require 'inspect'

local class = {}

local mt = {__index = class}

function mt:__close ()
   print('Closing!')
   -- This triggers the error for some reason. I imagine it's not
   -- specific to the 'inspect' package, but rather just doing
   -- something complex with 'self'.
   print(inspect(self))
end

function class:new ()
   assert(self == mt.__index)
   return setmetatable({foo = 'bar'}, mt)
end

return class
Compile using

    $ gcc -Wall -O0 -DBAD_CODE `pkg-config --cflags lua5.4` -o memory-error 
memory-error.c `pkg-config --libs lua5.4`

and then run it with

    $ valgrind ./memory-error test.lua

You should notice many errors. If you compile without -DBAD_CODE, it
works as expected (see the source for details).

I tried this with the latest upstream version from git, and found that
the bug did not occur. After some bisecting, I found the commit where
this was fixed upstream. The commit is "196bb94d Bug: 'lua_settop' may
use an invalid pointer to stack"
https://github.com/lua/lua/commit/196bb94d66e727e0aec053a0276c3ad701500762

I'm not sure if this is a security issue or not. If so, please raise the
Severity accordingly.

I think this fix from upstream should be backported to Debian's Lua 5.4,
and possibly 5.{1,2,3} as well (I haven't tested those). Hopefully it is
as simple as applying the patch.

Thanks,
Asher

-- System Information:
Debian Release: trixie/sid
  APT prefers testing-debug
  APT policy: (500, 'testing-debug'), (500, 'testing')
Architecture: amd64 (x86_64)

Kernel: Linux 6.3.0-1-amd64 (SMP w/12 CPU threads; PREEMPT)
Kernel taint flags: TAINT_OOT_MODULE, TAINT_UNSIGNED_MODULE
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8), LANGUAGE not set
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled

Versions of packages lua5.4 depends on:
ii  libc6         2.37-5
ii  libreadline8  8.2-1.3

lua5.4 recommends no packages.

lua5.4 suggests no packages.

-- no debconf information

-- 
Yesterday upon the stair
I met a man who wasn't there.
He wasn't there again today --
I think he's from the CIA.
                               --------
I prefer to send and receive mail encrypted. Please send me your
public key, and if you do not have my public key, please let me
know. Thanks.

GPG fingerprint: 38F3 975C D173 4037 B397  8095 D4C9 C4FC 5460 8E68

Attachment: signature.asc
Description: PGP signature

Reply via email to