|
|
4a46eb |
From cfe79543cf7c96bb7598f43eabdcfd3ca011a51b Mon Sep 17 00:00:00 2001
|
|
|
4a46eb |
From: Eduardo Otubo <otubo@redhat.com>
|
|
|
4a46eb |
Date: Mon, 24 Aug 2020 16:03:42 -0400
|
|
|
4a46eb |
Subject: [PATCH 3/3] DHCP sandboxing failing on noexec mounted /var/tmp (#521)
|
|
|
4a46eb |
|
|
|
4a46eb |
RH-Author: Eduardo Otubo <otubo@redhat.com>
|
|
|
4a46eb |
Message-id: <20200824160342.23626-1-otubo@redhat.com>
|
|
|
4a46eb |
Patchwork-id: 98216
|
|
|
4a46eb |
O-Subject: [RHEL-8.2.0/RHEL-7.9/RHEL-8.2.1/RHEL-8.3.0 cloud-init PATCH] DHCP sandboxing failing on noexec mounted /var/tmp (#521)
|
|
|
4a46eb |
Bugzilla: 1871916
|
|
|
4a46eb |
RH-Acked-by: Cathy Avery <cavery@redhat.com>
|
|
|
4a46eb |
RH-Acked-by: Mohammed Gamal <mgamal@redhat.com>
|
|
|
4a46eb |
|
|
|
4a46eb |
commit db86753f81af73826158c9522f2521f210300e2b
|
|
|
4a46eb |
Author: Eduardo Otubo <otubo@redhat.com>
|
|
|
4a46eb |
Date: Mon Aug 24 15:34:24 2020 +0200
|
|
|
4a46eb |
|
|
|
4a46eb |
DHCP sandboxing failing on noexec mounted /var/tmp (#521)
|
|
|
4a46eb |
|
|
|
4a46eb |
* DHCP sandboxing failing on noexec mounted /var/tmp
|
|
|
4a46eb |
|
|
|
4a46eb |
If /var/tmp is mounted with noexec option the DHCP sandboxing will fail
|
|
|
4a46eb |
with Permission Denied. This patch simply avoids this error by checking
|
|
|
4a46eb |
the exec permission updating the dhcp path in negative case.
|
|
|
4a46eb |
|
|
|
4a46eb |
rhbz: https://bugzilla.redhat.com/show_bug.cgi?id=1857309
|
|
|
4a46eb |
|
|
|
4a46eb |
Signed-off-by: Eduardo Otubo <otubo@redhat.com>
|
|
|
4a46eb |
|
|
|
4a46eb |
* Replacing with os.* calls
|
|
|
4a46eb |
|
|
|
4a46eb |
* Adding test and removing isfile() useless call.
|
|
|
4a46eb |
|
|
|
4a46eb |
Co-authored-by: Rick Harding <rharding@mitechie.com>
|
|
|
4a46eb |
|
|
|
4a46eb |
Signed-off-by: Eduardo Otubo <otubo@redhat.com>
|
|
|
4a46eb |
Signed-off-by: Jon Maloy <jmaloy.redhat.com>
|
|
|
4a46eb |
---
|
|
|
4a46eb |
cloudinit/net/dhcp.py | 6 +++++
|
|
|
4a46eb |
cloudinit/net/tests/test_dhcp.py | 46 ++++++++++++++++++++++++++++++++
|
|
|
4a46eb |
2 files changed, 52 insertions(+)
|
|
|
4a46eb |
|
|
|
4a46eb |
diff --git a/cloudinit/net/dhcp.py b/cloudinit/net/dhcp.py
|
|
|
4a46eb |
index c033cc8e..841e72ee 100644
|
|
|
4a46eb |
--- a/cloudinit/net/dhcp.py
|
|
|
4a46eb |
+++ b/cloudinit/net/dhcp.py
|
|
|
4a46eb |
@@ -215,6 +215,12 @@ def dhcp_discovery(dhclient_cmd_path, interface, cleandir):
|
|
|
4a46eb |
pid_file = os.path.join(cleandir, 'dhclient.pid')
|
|
|
4a46eb |
lease_file = os.path.join(cleandir, 'dhcp.leases')
|
|
|
4a46eb |
|
|
|
4a46eb |
+ # In some cases files in /var/tmp may not be executable, launching dhclient
|
|
|
4a46eb |
+ # from there will certainly raise 'Permission denied' error. Try launching
|
|
|
4a46eb |
+ # the original dhclient instead.
|
|
|
4a46eb |
+ if not os.access(sandbox_dhclient_cmd, os.X_OK):
|
|
|
4a46eb |
+ sandbox_dhclient_cmd = dhclient_cmd_path
|
|
|
4a46eb |
+
|
|
|
4a46eb |
# ISC dhclient needs the interface up to send initial discovery packets.
|
|
|
4a46eb |
# Generally dhclient relies on dhclient-script PREINIT action to bring the
|
|
|
4a46eb |
# link up before attempting discovery. Since we are using -sf /bin/true,
|
|
|
4a46eb |
diff --git a/cloudinit/net/tests/test_dhcp.py b/cloudinit/net/tests/test_dhcp.py
|
|
|
4a46eb |
index c3fa1e04..08e2cfb5 100644
|
|
|
4a46eb |
--- a/cloudinit/net/tests/test_dhcp.py
|
|
|
4a46eb |
+++ b/cloudinit/net/tests/test_dhcp.py
|
|
|
4a46eb |
@@ -406,6 +406,52 @@ class TestDHCPDiscoveryClean(CiTestCase):
|
|
|
4a46eb |
'eth9', '-sf', '/bin/true'], capture=True)])
|
|
|
4a46eb |
m_kill.assert_has_calls([mock.call(my_pid, signal.SIGKILL)])
|
|
|
4a46eb |
|
|
|
4a46eb |
+ @mock.patch('cloudinit.net.dhcp.util.get_proc_ppid')
|
|
|
4a46eb |
+ @mock.patch('cloudinit.net.dhcp.os.kill')
|
|
|
4a46eb |
+ @mock.patch('cloudinit.net.dhcp.subp.subp')
|
|
|
4a46eb |
+ def test_dhcp_discovery_outside_sandbox(self, m_subp, m_kill, m_getppid):
|
|
|
4a46eb |
+ """dhcp_discovery brings up the interface and runs dhclient.
|
|
|
4a46eb |
+
|
|
|
4a46eb |
+ It also returns the parsed dhcp.leases file generated in the sandbox.
|
|
|
4a46eb |
+ """
|
|
|
4a46eb |
+ m_subp.return_value = ('', '')
|
|
|
4a46eb |
+ tmpdir = self.tmp_dir()
|
|
|
4a46eb |
+ dhclient_script = os.path.join(tmpdir, 'dhclient.orig')
|
|
|
4a46eb |
+ script_content = '#!/bin/bash\necho fake-dhclient'
|
|
|
4a46eb |
+ write_file(dhclient_script, script_content, mode=0o755)
|
|
|
4a46eb |
+ lease_content = dedent("""
|
|
|
4a46eb |
+ lease {
|
|
|
4a46eb |
+ interface "eth9";
|
|
|
4a46eb |
+ fixed-address 192.168.2.74;
|
|
|
4a46eb |
+ option subnet-mask 255.255.255.0;
|
|
|
4a46eb |
+ option routers 192.168.2.1;
|
|
|
4a46eb |
+ }
|
|
|
4a46eb |
+ """)
|
|
|
4a46eb |
+ lease_file = os.path.join(tmpdir, 'dhcp.leases')
|
|
|
4a46eb |
+ write_file(lease_file, lease_content)
|
|
|
4a46eb |
+ pid_file = os.path.join(tmpdir, 'dhclient.pid')
|
|
|
4a46eb |
+ my_pid = 1
|
|
|
4a46eb |
+ write_file(pid_file, "%d\n" % my_pid)
|
|
|
4a46eb |
+ m_getppid.return_value = 1 # Indicate that dhclient has daemonized
|
|
|
4a46eb |
+
|
|
|
4a46eb |
+ with mock.patch('os.access', return_value=False):
|
|
|
4a46eb |
+ self.assertCountEqual(
|
|
|
4a46eb |
+ [{'interface': 'eth9', 'fixed-address': '192.168.2.74',
|
|
|
4a46eb |
+ 'subnet-mask': '255.255.255.0', 'routers': '192.168.2.1'}],
|
|
|
4a46eb |
+ dhcp_discovery(dhclient_script, 'eth9', tmpdir))
|
|
|
4a46eb |
+ # dhclient script got copied
|
|
|
4a46eb |
+ with open(os.path.join(tmpdir, 'dhclient.orig')) as stream:
|
|
|
4a46eb |
+ self.assertEqual(script_content, stream.read())
|
|
|
4a46eb |
+ # Interface was brought up before dhclient called from sandbox
|
|
|
4a46eb |
+ m_subp.assert_has_calls([
|
|
|
4a46eb |
+ mock.call(
|
|
|
4a46eb |
+ ['ip', 'link', 'set', 'dev', 'eth9', 'up'], capture=True),
|
|
|
4a46eb |
+ mock.call(
|
|
|
4a46eb |
+ [os.path.join(tmpdir, 'dhclient.orig'), '-1', '-v', '-lf',
|
|
|
4a46eb |
+ lease_file, '-pf', os.path.join(tmpdir, 'dhclient.pid'),
|
|
|
4a46eb |
+ 'eth9', '-sf', '/bin/true'], capture=True)])
|
|
|
4a46eb |
+ m_kill.assert_has_calls([mock.call(my_pid, signal.SIGKILL)])
|
|
|
4a46eb |
+
|
|
|
4a46eb |
|
|
|
4a46eb |
class TestSystemdParseLeases(CiTestCase):
|
|
|
4a46eb |
|
|
|
4a46eb |
--
|
|
|
4a46eb |
2.18.2
|
|
|
4a46eb |
|