Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(patch): add global math.randomseed patch support #5682

Merged
merged 12 commits into from
Dec 7, 2021
65 changes: 65 additions & 0 deletions apisix/patch.lua
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,25 @@ local ipmatcher = require("resty.ipmatcher")
local socket = require("socket")
local unix_socket = require("socket.unix")
local ssl = require("ssl")
local ngx = ngx
local get_phase = ngx.get_phase
local ngx_socket = ngx.socket
local original_tcp = ngx.socket.tcp
local original_udp = ngx.socket.udp
local concat_tab = table.concat
local debug = debug
local new_tab = require("table.new")
local log = ngx.log
local WARN = ngx.WARN
local ipairs = ipairs
local select = select
local setmetatable = setmetatable
local string = string
local table = table
local type = type
local tonumber = tonumber
local tostring = tostring
local min = math.min


local config_local
Expand Down Expand Up @@ -86,6 +93,64 @@ do
end


do -- `_G.math.randomseed` patch
leslie-tsang marked this conversation as resolved.
Show resolved Hide resolved
leslie-tsang marked this conversation as resolved.
Show resolved Hide resolved

-- Seeds the random generator, use with care.
-- Once - properly - seeded, this method is replaced with a stub
-- one. This is to enforce best-practices for seeding in ngx_lua,
-- and prevents third-party modules from overriding our correct seed
-- (many modules make a wrong usage of `math.randomseed()` by calling
-- it multiple times or by not using unique seeds for Nginx workers).
-- Inspired by kong.globalpatches
leslie-tsang marked this conversation as resolved.
Show resolved Hide resolved
local resty_random = require("resty.random")
local math_randomseed = math.randomseed
local seeded = {}

-- make linter happy
-- luacheck: ignore
math.randomseed = function()
local seed
local worker_pid = ngx.worker.pid()

-- check seed mark
if seeded[worker_pid] then
log(ngx.DEBUG, debug.traceback("attempt to seed already seeded random number " ..
"generator on process #" .. tostring(worker_pid), 2))
return
end

-- get randomseed
local bytes = resty_random.bytes(8)
if bytes then
log(ngx.DEBUG, "seeding from resty.random.bytes")

local t = {}
-- truncate the final number to prevent integer overflow,
-- since math.randomseed() could get cast to a platform-specific
-- integer with a different size and get truncated, hence, lose
-- randomness.
-- double-precision floating point should be able to represent numbers
-- without rounding with up to 15/16 digits but let's use 12 of them.
for i = 1, min(#bytes, 12) do
t[i] = string.byte(bytes, i)
end

local str = table.concat(t)
seed = tonumber(str)
else
log(ngx.ERR, "could not seed from resty.random.bytes, seeding ",
"seeding with time and process id instead (this can ",
"result to duplicated seeds)")

seed = ngx.now() * 1000 + worker_pid
end

seeded[worker_pid] = true
math_randomseed(seed)
end
end -- do


local patch_udp_socket
do
local old_udp_sock_setpeername
Expand Down