nuageinit: fix shell command injection in multiple rc.conf.d writes

This commit is contained in:
Baptiste Daroussin
2026-06-09 16:16:44 +02:00
parent da3890fdcc
commit 0211c8722f
2 changed files with 53 additions and 82 deletions
+30 -59
View File
@@ -240,37 +240,11 @@ local function nameservers(interface, obj)
local resolvconf_conf_handler = open_resolvconf_conf() local resolvconf_conf_handler = open_resolvconf_conf()
if obj.search then if obj.search then
local with_space = false resolvconf_conf_handler:write("search_domains=" .. nuage.shell_escape(table.concat(obj.search, " ")) .. "\n")
resolvconf_conf_handler:write('search_domains="')
for _, d in ipairs(obj.search) do
if with_space then
resolvconf_conf_handler:write(" " .. d)
else
resolvconf_conf_handler:write(d)
with_space = true
end
end
resolvconf_conf_handler:write('"\n')
end end
if obj.addresses then if obj.addresses then
local with_space = false resolvconf_conf_handler:write("name_servers=" .. nuage.shell_escape(table.concat(obj.addresses, " ")) .. "\n")
resolvconf_conf_handler:write('name_servers="')
for _, a in ipairs(obj.addresses) do
if with_space then
resolvconf_conf_handler:write(" " .. a)
else
resolvconf_conf_handler:write(a)
with_space = true
end
end
resolvconf_conf_handler:write('"\n')
end end
resolvconf_conf_handler:close() resolvconf_conf_handler:close()
@@ -455,18 +429,18 @@ local function network_config(obj)
local ifaces = get_ifaces_by_mac() local ifaces = get_ifaces_by_mac()
local matched = ifaces[v.match.macaddress] local matched = ifaces[v.match.macaddress]
if matched and matched == interface then if matched and matched == interface then
network:write("ifconfig_" .. interface .. '_name=' .. v["set-name"] .. '\n') network:write("ifconfig_" .. interface .. "_name=" .. nuage.shell_escape(v["set-name"]) .. "\n")
interface = v["set-name"] interface = v["set-name"]
end end
end end
if v.dhcp4 then if v.dhcp4 then
network:write("ifconfig_" .. interface .. '="DHCP"' .. extra_opts .. '\n') network:write("ifconfig_" .. interface .. "=" .. nuage.shell_escape("DHCP" .. extra_opts) .. "\n")
elseif v.addresses then elseif v.addresses then
for _, a in pairs(v.addresses) do for _, a in pairs(v.addresses) do
if a:match("^(%d+)%.(%d+)%.(%d+)%.(%d+)") then if a:match("^(%d+)%.(%d+)%.(%d+)%.(%d+)") then
network:write("ifconfig_" .. interface .. '="inet ' .. a .. extra_opts .. '"\n') network:write("ifconfig_" .. interface .. "=" .. nuage.shell_escape("inet " .. a .. extra_opts) .. "\n")
else else
network:write("ifconfig_" .. interface .. '_ipv6="inet6 ' .. a .. extra_opts .. '"\n') network:write("ifconfig_" .. interface .. "_ipv6=" .. nuage.shell_escape("inet6 " .. a .. extra_opts) .. "\n")
ipv6[#ipv6 + 1] = interface ipv6[#ipv6 + 1] = interface
end end
end end
@@ -476,24 +450,22 @@ local function network_config(obj)
end end
if set_defaultrouter and v.gateway4 then if set_defaultrouter and v.gateway4 then
set_defaultrouter = false set_defaultrouter = false
routing:write('defaultrouter="' .. v.gateway4 .. '"\n') routing:write("defaultrouter=" .. nuage.shell_escape(v.gateway4) .. "\n")
end end
if v.gateway6 then if v.gateway6 then
if set_defaultrouter6 then if set_defaultrouter6 then
set_defaultrouter6 = false set_defaultrouter6 = false
routing:write('ipv6_defaultrouter="' .. v.gateway6 .. '"\n') routing:write("ipv6_defaultrouter=" .. nuage.shell_escape(v.gateway6) .. "\n")
end end
routing:write("ipv6_route_" .. interface .. '="' .. v.gateway6) routing:write("ipv6_route_" .. interface .. "=" .. nuage.shell_escape(v.gateway6 .. " -prefixlen 128 -interface " .. interface) .. "\n")
routing:write(" -prefixlen 128 -interface " .. interface .. '"\n')
end end
end end
end end
::next:: ::next::
end end
if #ipv6 > 0 then if #ipv6 > 0 then
network:write('ipv6_network_interfaces="') network:write("ipv6_network_interfaces=" .. nuage.shell_escape(table.concat(ipv6, " ")) .. "\n")
network:write(table.concat(ipv6, " ") .. '"\n') network:write("ipv6_default_interface=" .. nuage.shell_escape(ipv6[1]) .. "\n")
network:write('ipv6_default_interface="' .. ipv6[1] .. '"\n')
end end
network:close() network:close()
routing:close() routing:close()
@@ -633,7 +605,7 @@ local function keyboard(obj)
warnmsg("unable to open " .. path .. " for writing") warnmsg("unable to open " .. path .. " for writing")
return return
end end
f:write('keymap="' .. keymap .. '"\n') f:write("keymap=" .. nuage.shell_escape(keymap) .. "\n")
f:close() f:close()
end end
@@ -648,10 +620,14 @@ local function locale(obj)
return return
end end
if type(obj.locale) == "string" then if type(obj.locale) == "string" then
f:write("export LANG=" .. obj.locale .. "\n") f:write("export LANG=" .. nuage.shell_escape(obj.locale) .. "\n")
elseif type(obj.locale) == "table" then elseif type(obj.locale) == "table" then
for k, v in pairs(obj.locale) do for k, v in pairs(obj.locale) do
f:write("export " .. k .. "=" .. v .. "\n") if not k:match("^[a-zA-Z_][a-zA-Z0-9_]*$") then
nuage.warn("locale: invalid variable name '" .. k .. "', skipping")
else
f:write("export " .. k .. "=" .. nuage.shell_escape(v) .. "\n")
end
end end
else else
nuage.warn("locale: invalid type " .. type(obj.locale) .. ", expecting string or object") nuage.warn("locale: invalid type " .. type(obj.locale) .. ", expecting string or object")
@@ -920,14 +896,14 @@ local function config2_network(p)
for _, v in pairs(obj["networks"]) do for _, v in pairs(obj["networks"]) do
local interface = mylinks[v["link"]] local interface = mylinks[v["link"]]
if v["type"] == "ipv4_dhcp" then if v["type"] == "ipv4_dhcp" then
network:write("ifconfig_" .. interface .. '="DHCP"\n') network:write("ifconfig_" .. interface .. "=" .. nuage.shell_escape("DHCP") .. "\n")
end end
if v["type"] == "ipv4" then if v["type"] == "ipv4" then
network:write( network:write(
"ifconfig_" .. interface .. '="inet ' .. v["ip_address"] .. " netmask " .. v["netmask"] .. '"\n' "ifconfig_" .. interface .. "=" .. nuage.shell_escape("inet " .. v["ip_address"] .. " netmask " .. v["netmask"]) .. "\n"
) )
if v["gateway"] then if v["gateway"] then
routing:write('defaultrouter="' .. v["gateway"] .. '"\n') routing:write("defaultrouter=" .. nuage.shell_escape(v["gateway"]) .. "\n")
end end
if v["routes"] then if v["routes"] then
for i, r in ipairs(v["routes"]) do for i, r in ipairs(v["routes"]) do
@@ -936,11 +912,10 @@ local function config2_network(p)
goto next goto next
end end
if r["network"] == "0.0.0.0" then if r["network"] == "0.0.0.0" then
routing:write('defaultrouter="' .. r["gateway"] .. '"\n') routing:write("defaultrouter=" .. nuage.shell_escape(r["gateway"]) .. "\n")
goto next goto next
end end
routing:write("route_" .. rname .. '="-net ' .. r["network"] .. " ") routing:write("route_" .. rname .. "=" .. nuage.shell_escape("-net " .. r["network"] .. " " .. r["gateway"] .. " " .. r["netmask"]) .. "\n")
routing:write(r["gateway"] .. " " .. r["netmask"] .. '"\n')
ipv4[#ipv4 + 1] = rname ipv4[#ipv4 + 1] = rname
::next:: ::next::
end end
@@ -949,11 +924,10 @@ local function config2_network(p)
if v["type"] == "ipv6" then if v["type"] == "ipv6" then
ipv6[#ipv6 + 1] = interface ipv6[#ipv6 + 1] = interface
ipv6_routes[#ipv6_routes + 1] = interface ipv6_routes[#ipv6_routes + 1] = interface
network:write("ifconfig_" .. interface .. '_ipv6="inet6 ' .. v["ip_address"] .. '"\n') network:write("ifconfig_" .. interface .. "_ipv6=" .. nuage.shell_escape("inet6 " .. v["ip_address"]) .. "\n")
if v["gateway"] then if v["gateway"] then
routing:write('ipv6_defaultrouter="' .. v["gateway"] .. '"\n') routing:write("ipv6_defaultrouter=" .. nuage.shell_escape(v["gateway"]) .. "\n")
routing:write("ipv6_route_" .. interface .. '="' .. v["gateway"]) routing:write("ipv6_route_" .. interface .. "=" .. nuage.shell_escape(v["gateway"] .. " -prefixlen 128 -interface " .. interface) .. "\n")
routing:write(" -prefixlen 128 -interface " .. interface .. '"\n')
end end
-- TODO compute the prefixlen for the routes -- TODO compute the prefixlen for the routes
--if v["routes"] then --if v["routes"] then
@@ -988,17 +962,14 @@ local function config2_network(p)
end end
if #ipv4 > 0 then if #ipv4 > 0 then
routing:write('static_routes="') routing:write("static_routes=" .. nuage.shell_escape(table.concat(ipv4, " ")) .. "\n")
routing:write(table.concat(ipv4, " ") .. '"\n')
end end
if #ipv6 > 0 then if #ipv6 > 0 then
network:write('ipv6_network_interfaces="') network:write("ipv6_network_interfaces=" .. nuage.shell_escape(table.concat(ipv6, " ")) .. "\n")
network:write(table.concat(ipv6, " ") .. '"\n') network:write("ipv6_default_interface=" .. nuage.shell_escape(ipv6[1]) .. "\n")
network:write('ipv6_default_interface="' .. ipv6[1] .. '"\n')
end end
if #ipv6_routes > 0 then if #ipv6_routes > 0 then
routing:write('ipv6_static_routes="') routing:write("ipv6_static_routes=" .. nuage.shell_escape(table.concat(ipv6, " ")) .. "\n")
routing:write(table.concat(ipv6, " ") .. '"\n')
end end
network:close() network:close()
routing:close() routing:close()
+23 -23
View File
@@ -223,15 +223,15 @@ network:
EOF EOF
atf_check /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud atf_check /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud
cat > network << EOF cat > network << EOF
ifconfig_${myiface}="inet 192.0.2.2/24" ifconfig_${myiface}='inet 192.0.2.2/24'
ifconfig_${myiface}_ipv6="inet6 2001:db8::2/64" ifconfig_${myiface}_ipv6='inet6 2001:db8::2/64'
ipv6_network_interfaces="${myiface}" ipv6_network_interfaces='${myiface}'
ipv6_default_interface="${myiface}" ipv6_default_interface='${myiface}'
EOF EOF
cat > routing << EOF cat > routing << EOF
defaultrouter="192.0.2.1" defaultrouter='192.0.2.1'
ipv6_defaultrouter="2001:db8::1" ipv6_defaultrouter='2001:db8::1'
ipv6_route_${myiface}="2001:db8::1 -prefixlen 128 -interface ${myiface}" ipv6_route_${myiface}='2001:db8::1 -prefixlen 128 -interface ${myiface}'
EOF EOF
atf_check -o file:network cat "${PWD}"/etc/rc.conf.d/network atf_check -o file:network cat "${PWD}"/etc/rc.conf.d/network
atf_check -o file:routing cat "${PWD}"/etc/rc.conf.d/routing atf_check -o file:routing cat "${PWD}"/etc/rc.conf.d/routing
@@ -406,15 +406,15 @@ cat > media/nuageinit/network_data.json << EOF
EOF EOF
atf_check /usr/libexec/nuageinit "${PWD}"/media/nuageinit config-2 atf_check /usr/libexec/nuageinit "${PWD}"/media/nuageinit config-2
cat > network << EOF cat > network << EOF
ifconfig_${myiface}="DHCP" ifconfig_${myiface}='DHCP'
ifconfig_${myiface}_ipv6="inet6 2001:db8::3257:9652/64" ifconfig_${myiface}_ipv6='inet6 2001:db8::3257:9652/64'
ipv6_network_interfaces="${myiface}" ipv6_network_interfaces='${myiface}'
ipv6_default_interface="${myiface}" ipv6_default_interface='${myiface}'
EOF EOF
cat > routing << EOF cat > routing << EOF
ipv6_defaultrouter="fd00::1" ipv6_defaultrouter='fd00::1'
ipv6_route_${myiface}="fd00::1 -prefixlen 128 -interface ${myiface}" ipv6_route_${myiface}='fd00::1 -prefixlen 128 -interface ${myiface}'
ipv6_static_routes="${myiface}" ipv6_static_routes='${myiface}'
EOF EOF
atf_check -o file:network cat "${PWD}"/etc/rc.conf.d/network atf_check -o file:network cat "${PWD}"/etc/rc.conf.d/network
atf_check -o file:routing cat "${PWD}"/etc/rc.conf.d/routing atf_check -o file:routing cat "${PWD}"/etc/rc.conf.d/routing
@@ -466,12 +466,12 @@ cat > media/nuageinit/network_data.json << EOF
EOF EOF
atf_check /usr/libexec/nuageinit "${PWD}"/media/nuageinit config-2 atf_check /usr/libexec/nuageinit "${PWD}"/media/nuageinit config-2
cat > network << EOF cat > network << EOF
ifconfig_${myiface}="inet 10.184.0.244 netmask 255.255.240.0" ifconfig_${myiface}='inet 10.184.0.244 netmask 255.255.240.0'
EOF EOF
cat > routing << EOF cat > routing << EOF
route_cloudinit1_${myiface}="-net 10.0.0.0 11.0.0.1 255.0.0.0" route_cloudinit1_${myiface}='-net 10.0.0.0 11.0.0.1 255.0.0.0'
defaultrouter="23.253.157.1" defaultrouter='23.253.157.1'
static_routes="cloudinit1_${myiface}" static_routes='cloudinit1_${myiface}'
EOF EOF
atf_check -o file:network cat "${PWD}"/etc/rc.conf.d/network atf_check -o file:network cat "${PWD}"/etc/rc.conf.d/network
atf_check -o file:routing cat "${PWD}"/etc/rc.conf.d/routing atf_check -o file:routing cat "${PWD}"/etc/rc.conf.d/routing
@@ -518,7 +518,7 @@ cat > media/nuageinit/network_data.json << EOF
} }
EOF EOF
atf_check /usr/libexec/nuageinit "${PWD}"/media/nuageinit config-2 atf_check /usr/libexec/nuageinit "${PWD}"/media/nuageinit config-2
atf_check -o inline:'name_servers="9.9.9.9 149.112.112.112"\n' \ atf_check -o inline:"name_servers='9.9.9.9 149.112.112.112'\n" \
cat "${PWD}"/etc/resolvconf.conf cat "${PWD}"/etc/resolvconf.conf
} }
@@ -1203,7 +1203,7 @@ keyboard:
variant: acc variant: acc
EOF EOF
atf_check -o empty /usr/libexec/nuageinit "${PWD}"/media/nuageinit config-2 atf_check -o empty /usr/libexec/nuageinit "${PWD}"/media/nuageinit config-2
atf_check -o inline:'keymap="fr.acc"\n' cat etc/rc.conf.d/keymap atf_check -o inline:"keymap='fr.acc'\n" cat etc/rc.conf.d/keymap
true true
} }
@@ -1351,7 +1351,7 @@ config2_userdata_locale_body()
locale: fr_FR.UTF-8 locale: fr_FR.UTF-8
EOF EOF
atf_check -o empty /usr/libexec/nuageinit "${PWD}"/media/nuageinit config-2 atf_check -o empty /usr/libexec/nuageinit "${PWD}"/media/nuageinit config-2
atf_check -o inline:"export LANG=fr_FR.UTF-8\n" cat etc/profile atf_check -o inline:"export LANG='fr_FR.UTF-8'\n" cat etc/profile
cat > media/nuageinit/user_data <<EOF cat > media/nuageinit/user_data <<EOF
#cloud-config #cloud-config
@@ -1360,8 +1360,8 @@ locale:
LC_ALL: de_DE.UTF-8 LC_ALL: de_DE.UTF-8
EOF EOF
atf_check -o empty /usr/libexec/nuageinit "${PWD}"/media/nuageinit config-2 atf_check -o empty /usr/libexec/nuageinit "${PWD}"/media/nuageinit config-2
atf_check -o match:"export LANG=de_DE.UTF-8" cat etc/profile atf_check -o match:"export LANG='de_DE.UTF-8'" cat etc/profile
atf_check -o match:"export LC_ALL=de_DE.UTF-8" cat etc/profile atf_check -o match:"export LC_ALL='de_DE.UTF-8'" cat etc/profile
true true
} }