From 8178f7bd884410b53329d6fc0b9c49891081a91d Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 6 Jan 2016 00:24:06 +0000 Subject: tests/test.lua: Fix fake module() function to prevent _M from being _G (test.lua's environment), which caused modules to break the sandbox when they set _M.* --- tests/test.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/test.lua b/tests/test.lua index de1e40fd..bb11ab26 100644 --- a/tests/test.lua +++ b/tests/test.lua @@ -137,7 +137,10 @@ function dotest(unitname) end local oldmodule, old_M = _fakeG.module, _fakeG._M; - _fakeG.module = function () _M = _G end + _fakeG.module = function () + setmetatable(unit, nil); + unit._M = unit; + end setfenv(chunk, unit); local success, err = pcall(chunk); _fakeG.module, _fakeG._M = oldmodule, old_M; -- cgit v1.2.3 From 2ab42c8dbf95ea250e4dd16b21b12c2b6dddb5b1 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 17 May 2013 14:52:52 +0100 Subject: util.ip: Automatically determine protocol of IP address if none specified. Return error if invalid. [Backported from 0.10] --- util/ip.lua | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/util/ip.lua b/util/ip.lua index 856bf034..226432cc 100644 --- a/util/ip.lua +++ b/util/ip.lua @@ -12,7 +12,15 @@ local ip_mt = { __index = function (ip, key) return (ip_methods[key])(ip); end, local hex2bits = { ["0"] = "0000", ["1"] = "0001", ["2"] = "0010", ["3"] = "0011", ["4"] = "0100", ["5"] = "0101", ["6"] = "0110", ["7"] = "0111", ["8"] = "1000", ["9"] = "1001", ["A"] = "1010", ["B"] = "1011", ["C"] = "1100", ["D"] = "1101", ["E"] = "1110", ["F"] = "1111" }; local function new_ip(ipStr, proto) - if proto ~= "IPv4" and proto ~= "IPv6" then + if not proto then + local sep = ipStr:match("^%x+(.)"); + if sep == ":" then proto = "IPv6" + elseif sep == "." then proto = "IPv4" + end + if not proto then + return nil, "invalid address"; + end + elseif proto ~= "IPv4" and proto ~= "IPv6" then return nil, "invalid protocol"; end if proto == "IPv6" and ipStr:find('.', 1, true) then -- cgit v1.2.3 From 2b6402720494ef8632a2f26970b9cc935dee8d41 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 18 May 2013 21:41:17 +0100 Subject: util.ip: Fix protocol detection of IPv6 addresses beginning with : [Backported from 0.10] --- util/ip.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/util/ip.lua b/util/ip.lua index 226432cc..043303ee 100644 --- a/util/ip.lua +++ b/util/ip.lua @@ -14,8 +14,10 @@ local hex2bits = { ["0"] = "0000", ["1"] = "0001", ["2"] = "0010", ["3"] = "0011 local function new_ip(ipStr, proto) if not proto then local sep = ipStr:match("^%x+(.)"); - if sep == ":" then proto = "IPv6" - elseif sep == "." then proto = "IPv4" + if sep == ":" or (not(sep) and ipStr:sub(1,1) == ":") then + proto = "IPv6" + elseif sep == "." then + proto = "IPv4" end if not proto then return nil, "invalid address"; -- cgit v1.2.3 From 4f709973f8079e8e6deaa78c195d44f221590933 Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Tue, 18 Jun 2013 23:02:20 +0200 Subject: net.dns: Support IPv6 addresses in resolv.conf [Backported from 0.10] --- net/dns.lua | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/net/dns.lua b/net/dns.lua index 7ec13c81..9d90c24c 100644 --- a/net/dns.lua +++ b/net/dns.lua @@ -14,6 +14,7 @@ local socket = require "socket"; local timer = require "util.timer"; +local new_ip = require "util.ip".new_ip; local _, windows = pcall(require, "util.windows"); local is_windows = (_ and windows) or os.getenv("WINDIR"); @@ -599,11 +600,12 @@ function resolver:adddefaultnameservers() -- - - - - adddefaultnameservers if resolv_conf then for line in resolv_conf:lines() do line = line:gsub("#.*$", "") - :match('^%s*nameserver%s+(.*)%s*$'); + :match('^%s*nameserver%s+([%x:%.]*)%s*$'); if line then - line:gsub("%f[%d.](%d+%.%d+%.%d+%.%d+)%f[^%d.]", function (address) - self:addnameserver(address) - end); + local ip = new_ip(line); + if ip then + self:addnameserver(ip.addr); + end end end end @@ -623,7 +625,12 @@ function resolver:getsocket(servernum) -- - - - - - - - - - - - - getsocket if sock then return sock; end local ok, err; - sock, err = socket.udp(); + local peer = self.server[servernum]; + if peer:find(":") then + sock, err = socket.udp6(); + else + sock, err = socket.udp(); + end if sock and self.socket_wrapper then sock, err = self.socket_wrapper(sock, self); end if not sock then return nil, err; @@ -636,7 +643,7 @@ function resolver:getsocket(servernum) -- - - - - - - - - - - - - getsocket -- if so, try the next server ok, err = sock:setsockname('*', 0); if not ok then return self:servfail(sock, err); end - ok, err = sock:setpeername(self.server[servernum], 53); + ok, err = sock:setpeername(peer, 53); if not ok then return self:servfail(sock, err); end return sock; end -- cgit v1.2.3 From e03302f412a0c4fa2c239251851baf9e99fbff3a Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 4 Jan 2016 17:47:40 +0100 Subject: util.ip: Support zone id syntax in IPv6 addresses --- util/ip.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/util/ip.lua b/util/ip.lua index 043303ee..acfd7f24 100644 --- a/util/ip.lua +++ b/util/ip.lua @@ -25,6 +25,10 @@ local function new_ip(ipStr, proto) elseif proto ~= "IPv4" and proto ~= "IPv6" then return nil, "invalid protocol"; end + local zone; + if proto == "IPv6" and ipStr:find('%', 1, true) then + ipStr, zone = ipStr:match("^(.-)%%(.*)"); + end if proto == "IPv6" and ipStr:find('.', 1, true) then local changed; ipStr, changed = ipStr:gsub(":(%d+)%.(%d+)%.(%d+)%.(%d+)$", function(a,b,c,d) @@ -33,7 +37,7 @@ local function new_ip(ipStr, proto) if changed ~= 1 then return nil, "invalid-address"; end end - return setmetatable({ addr = ipStr, proto = proto }, ip_mt); + return setmetatable({ addr = ipStr, proto = proto, zone = zone }, ip_mt); end local function toBits(ip) -- cgit v1.2.3 From 58885565fee199cba81a0d113eb6839d1f5fc727 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 4 Jan 2016 15:46:06 +0100 Subject: net.dns: Allow a zone id in resolv.conf (eg like %eth0) --- net/dns.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/dns.lua b/net/dns.lua index 9d90c24c..49958ed7 100644 --- a/net/dns.lua +++ b/net/dns.lua @@ -600,7 +600,7 @@ function resolver:adddefaultnameservers() -- - - - - adddefaultnameservers if resolv_conf then for line in resolv_conf:lines() do line = line:gsub("#.*$", "") - :match('^%s*nameserver%s+([%x:%.]*)%s*$'); + :match('^%s*nameserver%s+([%x:%.]*%%?%S*)%s*$'); if line then local ip = new_ip(line); if ip then -- cgit v1.2.3 From 8a8f379272deeb7dbaeb35c3aadb0b03def8849e Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 6 Jan 2016 02:46:47 +0100 Subject: util.uuid: Use /dev/urandom --- util/uuid.lua | 43 ++++++++++++++++--------------------------- 1 file changed, 16 insertions(+), 27 deletions(-) diff --git a/util/uuid.lua b/util/uuid.lua index bb70d000..58f792fd 100644 --- a/util/uuid.lua +++ b/util/uuid.lua @@ -6,44 +6,33 @@ -- COPYING file in the source package for more information. -- - -local tostring = tostring; -local os_time = os.time; -local os_clock = os.clock; -local sha1 = require "util.hashes".sha1; +local error = error; +local round_up = math.ceil; +local urandom, urandom_err = io.open("/dev/urandom", "r+"); module "uuid" -local last_uniq_time = 0; -local function uniq_time() - local new_uniq_time = os_time(); - if last_uniq_time >= new_uniq_time then new_uniq_time = last_uniq_time + 1; end - last_uniq_time = new_uniq_time; - return new_uniq_time; -end - -local function new_random(x) - return sha1(x..os_clock()..tostring({}), true); -end - -local buffer = new_random(uniq_time()); -local function _seed(x) - buffer = new_random(buffer..x); -end local function get_nibbles(n) - if #buffer < n then _seed(uniq_time()); end - local r = buffer:sub(0, n); - buffer = buffer:sub(n+1); - return r; + local binary_random = urandom:read(round_up(n/2)); + local hex_random = binary_random:gsub(".", + function (x) return ("%02x"):format(x:byte()) end); + return hex_random:sub(1, n); end local function get_twobits() - return ("%x"):format(get_nibbles(1):byte() % 4 + 8); + return ("%x"):format(urandom:read(1):byte() % 4 + 8); end function generate() + if not urandom then + error("Unable to obtain a secure random number generator, please see https://prosody.im/doc/random ("..urandom_err..")"); + end -- generate RFC 4122 complaint UUIDs (version 4 - random) return get_nibbles(8).."-"..get_nibbles(4).."-4"..get_nibbles(3).."-"..(get_twobits())..get_nibbles(3).."-"..get_nibbles(12); end -seed = _seed; + +function seed(x) + urandom:write(x); + urandom:flush(); +end return _M; -- cgit v1.2.3 From cb1eeb23869d5207f2fad1ef557d8f453be6f15e Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 7 Jan 2016 15:37:47 +0000 Subject: mod_http_files: Santize the path relative to our base URL before translating it to a filesystem path, fixes a relative path traversal vulnerability --- plugins/mod_http_files.lua | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/plugins/mod_http_files.lua b/plugins/mod_http_files.lua index 9839fed9..6275cca5 100644 --- a/plugins/mod_http_files.lua +++ b/plugins/mod_http_files.lua @@ -49,6 +49,34 @@ if not mime_map then end end +local forbidden_chars_pattern = "[/%z]"; +if prosody.platform == "windows" then + forbidden_chars_pattern = "[/%z\001-\031\127\"*:<>?|]" +end + +local urldecode = require "util.http".urldecode; +function sanitize_path(path) + local out = {}; + + local c = 0; + for component in path:gmatch("([^/]+)") do + component = urldecode(component); + if component:find(forbidden_chars_pattern) then + return nil; + elseif component == ".." then + if c <= 0 then + return nil; + end + out[c] = nil; + c = c - 1; + elseif component ~= "." then + c = c + 1; + out[c] = component; + end + end + return "/"..table.concat(out, "/"); +end + local cache = setmetatable({}, { __mode = "kv" }); -- Let the garbage collector have it if it wants to. function serve(opts) @@ -60,7 +88,11 @@ function serve(opts) local directory_index = opts.directory_index; local function serve_file(event, path) local request, response = event.request, event.response; - local orig_path = request.path; + path = sanitize_path(path); + if not path then + return 400; + end + local orig_path = sanitize_path(request.path); local full_path = base_path .. (path and "/"..path or ""):gsub("/", path_sep); local attr = stat(full_path:match("^.*[^\\/]")); -- Strip trailing path separator because Windows if not attr then -- cgit v1.2.3 From 76de073eea372f346476b15aa5abe65233762e72 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 8 Jan 2016 13:01:27 +0000 Subject: Backout 88d54bec26b7 prior to release, as it certainly requires more testing --- net/dns.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/dns.lua b/net/dns.lua index 49958ed7..f56157d0 100644 --- a/net/dns.lua +++ b/net/dns.lua @@ -862,7 +862,9 @@ function resolver:receive(rset) -- - - - - - - - - - - - - - - - - receive --self.print(response); for j,rr in pairs(response.answer) do - self:remember(rr, response.question[1].type) + if rr.name:sub(-#response.question[1].name, -1) == response.question[1].name then + self:remember(rr, response.question[1].type) + end end -- retire the query -- cgit v1.2.3 -- cgit v1.2.3