From nobody Tue Jun 9 16:04:30 2026 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4gZYdB4rJWz6gD0f for ; Tue, 09 Jun 2026 16:04:30 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R13" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4gZYdB3S8Dz4Drb for ; Tue, 09 Jun 2026 16:04:30 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1781021070; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=G5Sf7JwKl0sUMExg9o8FyRely9JW7TxyIKnJuG9lIio=; b=TvoE+ukzlmdgKmZZo+fnUGfdAy0H8IHrJdD0Bd8dGEpjvCDdLXIECwJ8vfrD/dMze2HYE7 b/kVyRIKbYidbA5I0sD5ETUBmk0jqbofpOfcXlF+f+acYEuVnd1sN6DpLA5i6NkKCI9ITx HJS3OG4BrDVrPPkB5eQ31mGUSOAtwfzmXIyXEWYGQp0qs9McLzX5qh8olEKS/iQ74gM21b YDJbBsVbJrAo4ylHM5hiPyAlDpxUvUlta7DrbXhnZGANisvzjco8TxF6++EhvIGd5S2/Bi nh5GGZNxxiBzdLoQ+CBtTS8DnzmdGlRJO9hnhqJ23Jw1Gf+CzsUrGHQlX2AQoQ== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1781021070; a=rsa-sha256; cv=none; b=qhGEzAR281hdgIIXjmDW5S/SdV1RZHErdd5bFihdXfr9+JYNBkQRJB8Z2pFOjoHr4BBEv1 LQOIde98t8olVaGvfccYOI2MYwtKj2gcROR2ObOEF0kay4FSn5YWxEOhgcuZd9ThyCSrYp dD8w0hv4fLjmuy+SXPgV635fKHB0C4SnsrLUHPgkXJHhfNvH+EZU5lv33vuAcMGr22d4pJ MbojsToMkwl/ggiNpjwA25CD2oBeYd/LwgJoxQYfgF/4Rasi21DUARs7u6HUNUYtTpMXt2 m9zWAWdM+rzbybW+0XGDliFqWiJDU50xpAPx1OPmAnl2TgzS7HFbfN188ffH4A== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1781021070; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=G5Sf7JwKl0sUMExg9o8FyRely9JW7TxyIKnJuG9lIio=; b=YIEYa0XUKVzOrEAxwj8GSvBJLua2dK7NdvWdYIWoLBmcLp3stSrRj+vmTm65pSfxdCHnxN GTVQk72j+2DC37+a34Y1ePPp3FML9I76O6X52s49+XG16rpmHix0LJ3+FfxZIXqzwyRYQw MW6H0U4bBNqd50DaP+Wyw2kUiFhq/Q7SJsTz/x3d3rMljTKca2da1dETRYEUKq8W5myqYd s7acRZo2bXHMYjTJGtBltrhYDs4rIdx+hIWuwBmmCI8ltafde+nI26WXR2KsgL4OOAiWIC gz3kVT7MnSR/JlS5BLajZRGtmF3O7uJWNn+v5X6lqHkg91f8VpHsI7vPSmNFHA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4gZYdB2NYczhpH for ; Tue, 09 Jun 2026 16:04:30 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 21df8 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Tue, 09 Jun 2026 16:04:30 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Baptiste Daroussin Subject: git: 0211c8722ff2 - main - nuageinit: fix shell command injection in multiple rc.conf.d writes List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: bapt X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 0211c8722ff2ac9367565e526e62837745bb2cce Auto-Submitted: auto-generated Date: Tue, 09 Jun 2026 16:04:30 +0000 Message-Id: <6a28398e.21df8.2708f907@gitrepo.freebsd.org> The branch main has been updated by bapt: URL: https://cgit.FreeBSD.org/src/commit/?id=0211c8722ff2ac9367565e526e62837745bb2cce commit 0211c8722ff2ac9367565e526e62837745bb2cce Author: Baptiste Daroussin AuthorDate: 2026-06-09 14:16:44 +0000 Commit: Baptiste Daroussin CommitDate: 2026-06-09 16:04:24 +0000 nuageinit: fix shell command injection in multiple rc.conf.d writes --- libexec/nuageinit/nuageinit | 89 ++++++++++++------------------------ libexec/nuageinit/tests/nuageinit.sh | 46 +++++++++---------- 2 files changed, 53 insertions(+), 82 deletions(-) diff --git a/libexec/nuageinit/nuageinit b/libexec/nuageinit/nuageinit index 9a0399ad4862..6e900e01df4e 100755 --- a/libexec/nuageinit/nuageinit +++ b/libexec/nuageinit/nuageinit @@ -240,37 +240,11 @@ local function nameservers(interface, obj) local resolvconf_conf_handler = open_resolvconf_conf() if obj.search then - local with_space = false - - 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') + resolvconf_conf_handler:write("search_domains=" .. nuage.shell_escape(table.concat(obj.search, " ")) .. "\n") end if obj.addresses then - local with_space = false - - 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') + resolvconf_conf_handler:write("name_servers=" .. nuage.shell_escape(table.concat(obj.addresses, " ")) .. "\n") end resolvconf_conf_handler:close() @@ -455,18 +429,18 @@ local function network_config(obj) local ifaces = get_ifaces_by_mac() local matched = ifaces[v.match.macaddress] 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"] end end 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 for _, a in pairs(v.addresses) do 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 - 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 end end @@ -476,24 +450,22 @@ local function network_config(obj) end if set_defaultrouter and v.gateway4 then set_defaultrouter = false - routing:write('defaultrouter="' .. v.gateway4 .. '"\n') + routing:write("defaultrouter=" .. nuage.shell_escape(v.gateway4) .. "\n") end if v.gateway6 then if set_defaultrouter6 then set_defaultrouter6 = false - routing:write('ipv6_defaultrouter="' .. v.gateway6 .. '"\n') + routing:write("ipv6_defaultrouter=" .. nuage.shell_escape(v.gateway6) .. "\n") end - routing:write("ipv6_route_" .. interface .. '="' .. v.gateway6) - routing:write(" -prefixlen 128 -interface " .. interface .. '"\n') + routing:write("ipv6_route_" .. interface .. "=" .. nuage.shell_escape(v.gateway6 .. " -prefixlen 128 -interface " .. interface) .. "\n") end end end ::next:: end if #ipv6 > 0 then - network:write('ipv6_network_interfaces="') - network:write(table.concat(ipv6, " ") .. '"\n') - network:write('ipv6_default_interface="' .. ipv6[1] .. '"\n') + network:write("ipv6_network_interfaces=" .. nuage.shell_escape(table.concat(ipv6, " ")) .. "\n") + network:write("ipv6_default_interface=" .. nuage.shell_escape(ipv6[1]) .. "\n") end network:close() routing:close() @@ -633,7 +605,7 @@ local function keyboard(obj) warnmsg("unable to open " .. path .. " for writing") return end - f:write('keymap="' .. keymap .. '"\n') + f:write("keymap=" .. nuage.shell_escape(keymap) .. "\n") f:close() end @@ -648,10 +620,14 @@ local function locale(obj) return end 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 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 else 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 local interface = mylinks[v["link"]] if v["type"] == "ipv4_dhcp" then - network:write("ifconfig_" .. interface .. '="DHCP"\n') + network:write("ifconfig_" .. interface .. "=" .. nuage.shell_escape("DHCP") .. "\n") end if v["type"] == "ipv4" then 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 - routing:write('defaultrouter="' .. v["gateway"] .. '"\n') + routing:write("defaultrouter=" .. nuage.shell_escape(v["gateway"]) .. "\n") end if v["routes"] then for i, r in ipairs(v["routes"]) do @@ -936,11 +912,10 @@ local function config2_network(p) goto next end 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 end - routing:write("route_" .. rname .. '="-net ' .. r["network"] .. " ") - routing:write(r["gateway"] .. " " .. r["netmask"] .. '"\n') + routing:write("route_" .. rname .. "=" .. nuage.shell_escape("-net " .. r["network"] .. " " .. r["gateway"] .. " " .. r["netmask"]) .. "\n") ipv4[#ipv4 + 1] = rname ::next:: end @@ -949,11 +924,10 @@ local function config2_network(p) if v["type"] == "ipv6" then ipv6[#ipv6 + 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 - routing:write('ipv6_defaultrouter="' .. v["gateway"] .. '"\n') - routing:write("ipv6_route_" .. interface .. '="' .. v["gateway"]) - routing:write(" -prefixlen 128 -interface " .. interface .. '"\n') + routing:write("ipv6_defaultrouter=" .. nuage.shell_escape(v["gateway"]) .. "\n") + routing:write("ipv6_route_" .. interface .. "=" .. nuage.shell_escape(v["gateway"] .. " -prefixlen 128 -interface " .. interface) .. "\n") end -- TODO compute the prefixlen for the routes --if v["routes"] then @@ -988,17 +962,14 @@ local function config2_network(p) end if #ipv4 > 0 then - routing:write('static_routes="') - routing:write(table.concat(ipv4, " ") .. '"\n') + routing:write("static_routes=" .. nuage.shell_escape(table.concat(ipv4, " ")) .. "\n") end if #ipv6 > 0 then - network:write('ipv6_network_interfaces="') - network:write(table.concat(ipv6, " ") .. '"\n') - network:write('ipv6_default_interface="' .. ipv6[1] .. '"\n') + network:write("ipv6_network_interfaces=" .. nuage.shell_escape(table.concat(ipv6, " ")) .. "\n") + network:write("ipv6_default_interface=" .. nuage.shell_escape(ipv6[1]) .. "\n") end if #ipv6_routes > 0 then - routing:write('ipv6_static_routes="') - routing:write(table.concat(ipv6, " ") .. '"\n') + routing:write("ipv6_static_routes=" .. nuage.shell_escape(table.concat(ipv6, " ")) .. "\n") end network:close() routing:close() diff --git a/libexec/nuageinit/tests/nuageinit.sh b/libexec/nuageinit/tests/nuageinit.sh index 3f3e2843c35d..ce574a350ecc 100644 --- a/libexec/nuageinit/tests/nuageinit.sh +++ b/libexec/nuageinit/tests/nuageinit.sh @@ -223,15 +223,15 @@ network: EOF atf_check /usr/libexec/nuageinit "${PWD}"/media/nuageinit nocloud cat > network << EOF -ifconfig_${myiface}="inet 192.0.2.2/24" -ifconfig_${myiface}_ipv6="inet6 2001:db8::2/64" -ipv6_network_interfaces="${myiface}" -ipv6_default_interface="${myiface}" +ifconfig_${myiface}='inet 192.0.2.2/24' +ifconfig_${myiface}_ipv6='inet6 2001:db8::2/64' +ipv6_network_interfaces='${myiface}' +ipv6_default_interface='${myiface}' EOF cat > routing << EOF -defaultrouter="192.0.2.1" -ipv6_defaultrouter="2001:db8::1" -ipv6_route_${myiface}="2001:db8::1 -prefixlen 128 -interface ${myiface}" +defaultrouter='192.0.2.1' +ipv6_defaultrouter='2001:db8::1' +ipv6_route_${myiface}='2001:db8::1 -prefixlen 128 -interface ${myiface}' EOF atf_check -o file:network cat "${PWD}"/etc/rc.conf.d/network atf_check -o file:routing cat "${PWD}"/etc/rc.conf.d/routing @@ -406,15 +406,15 @@ cat > media/nuageinit/network_data.json << EOF EOF atf_check /usr/libexec/nuageinit "${PWD}"/media/nuageinit config-2 cat > network << EOF -ifconfig_${myiface}="DHCP" -ifconfig_${myiface}_ipv6="inet6 2001:db8::3257:9652/64" -ipv6_network_interfaces="${myiface}" -ipv6_default_interface="${myiface}" +ifconfig_${myiface}='DHCP' +ifconfig_${myiface}_ipv6='inet6 2001:db8::3257:9652/64' +ipv6_network_interfaces='${myiface}' +ipv6_default_interface='${myiface}' EOF cat > routing << EOF -ipv6_defaultrouter="fd00::1" -ipv6_route_${myiface}="fd00::1 -prefixlen 128 -interface ${myiface}" -ipv6_static_routes="${myiface}" +ipv6_defaultrouter='fd00::1' +ipv6_route_${myiface}='fd00::1 -prefixlen 128 -interface ${myiface}' +ipv6_static_routes='${myiface}' EOF atf_check -o file:network cat "${PWD}"/etc/rc.conf.d/network atf_check -o file:routing cat "${PWD}"/etc/rc.conf.d/routing @@ -466,12 +466,12 @@ cat > media/nuageinit/network_data.json << EOF EOF atf_check /usr/libexec/nuageinit "${PWD}"/media/nuageinit config-2 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 cat > routing << EOF -route_cloudinit1_${myiface}="-net 10.0.0.0 11.0.0.1 255.0.0.0" -defaultrouter="23.253.157.1" -static_routes="cloudinit1_${myiface}" +route_cloudinit1_${myiface}='-net 10.0.0.0 11.0.0.1 255.0.0.0' +defaultrouter='23.253.157.1' +static_routes='cloudinit1_${myiface}' EOF atf_check -o file:network cat "${PWD}"/etc/rc.conf.d/network atf_check -o file:routing cat "${PWD}"/etc/rc.conf.d/routing @@ -518,7 +518,7 @@ cat > media/nuageinit/network_data.json << EOF } EOF 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 } @@ -1203,7 +1203,7 @@ keyboard: variant: acc EOF 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 } @@ -1351,7 +1351,7 @@ config2_userdata_locale_body() locale: fr_FR.UTF-8 EOF 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 <