From 757d8c6e322eeda299aa5e055e38b1ed48977f2d Mon Sep 17 00:00:00 2001 From: Slawek Kaplonski Date: Mon, 23 Aug 2021 13:01:37 +0200 Subject: [PATCH] Remove dhcp_extra_opt value after first newline character Passing newline to the dnsmasq may cause security issues, especially that in case of Neutron that dhcp options' values are controlled by cloud users. This patch removes everything what is after first newline character in the dhcp_extra_opt's values before passing them to dnsmasq. Closes-Bug: #1939733 Change-Id: Ifeaf258f0b5ea86f25620ac4116d618980a7272e (cherry picked from commit df891f0593d234e01f27d7c0376d9702e178ecfb) --- neutron/agent/linux/dhcp.py | 7 ++++--- neutron/tests/unit/agent/linux/test_dhcp.py | 7 ++++++- ...wline-chars-in-dhcp-extra-options-bf86d30371556d63.yaml | 6 ++++++ 3 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 releasenotes/notes/fix-newline-chars-in-dhcp-extra-options-bf86d30371556d63.yaml diff --git a/neutron/agent/linux/dhcp.py b/neutron/agent/linux/dhcp.py index ee2c8123305..651e5f261af 100644 --- a/neutron/agent/linux/dhcp.py +++ b/neutron/agent/linux/dhcp.py @@ -1288,10 +1288,11 @@ class Dnsmasq(DhcpLocalProcess): elif not option.isdigit(): option = 'option:%s' % option if extra_tag: - tags = ('tag:' + tag, extra_tag[:-1], '%s' % option) + tags = ['tag:' + tag, extra_tag[:-1], '%s' % option] else: - tags = ('tag:' + tag, '%s' % option) - return ','.join(tags + args) + tags = ['tag:' + tag, '%s' % option] + + return ','.join(tags + [v.split("\n", 1)[0] for v in args]) @staticmethod def _convert_to_literal_addrs(ip_version, ips): diff --git a/neutron/tests/unit/agent/linux/test_dhcp.py b/neutron/tests/unit/agent/linux/test_dhcp.py index 64cd9fb679f..d04888e60af 100644 --- a/neutron/tests/unit/agent/linux/test_dhcp.py +++ b/neutron/tests/unit/agent/linux/test_dhcp.py @@ -227,6 +227,9 @@ class FakeV6PortExtraOpt(object): self.extra_dhcp_opts = [ DhcpOpt(opt_name='dns-server', opt_value='ffea:3ba5:a17a:4ba3::100', + ip_version=constants.IP_VERSION_6), + DhcpOpt(opt_name='malicious-option', + opt_value='aaa\nbbb.ccc\n', ip_version=constants.IP_VERSION_6)] @@ -2921,7 +2924,9 @@ class TestDnsmasq(TestBase): exp_opt_data = ('tag:subnet-eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee,' 'option6:domain-search,openstacklocal\n' 'tag:port-hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh,' - 'option6:dns-server,ffea:3ba5:a17a:4ba3::100').lstrip() + 'option6:dns-server,ffea:3ba5:a17a:4ba3::100\n' + 'tag:port-hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh,' + 'option6:malicious-option,aaa').lstrip() dm = self._get_dnsmasq(FakeV6NetworkStatelessDHCP()) dm._output_hosts_file() dm._output_opts_file() diff --git a/releasenotes/notes/fix-newline-chars-in-dhcp-extra-options-bf86d30371556d63.yaml b/releasenotes/notes/fix-newline-chars-in-dhcp-extra-options-bf86d30371556d63.yaml new file mode 100644 index 00000000000..d2a8c2f68bb --- /dev/null +++ b/releasenotes/notes/fix-newline-chars-in-dhcp-extra-options-bf86d30371556d63.yaml @@ -0,0 +1,6 @@ +--- +security: + - | + Fix `bug 1939733 `_ by + dropping from the dhcp extra option values everything what is after first + newline (``\n``) character before passing them to the dnsmasq.