diff -ruN neutron-bak/agent/linux/ipset_manager.py neutron/agent/linux/ipset_manager.py --- neutron-bak/agent/linux/ipset_manager.py 2022-02-16 15:11:40.419016919 +0800 +++ neutron/agent/linux/ipset_manager.py 2022-02-16 15:17:02.328133786 +0800 @@ -146,7 +146,7 @@ cmd_ns.extend(['ip', 'netns', 'exec', self.namespace]) cmd_ns.extend(cmd) self.execute(cmd_ns, run_as_root=True, process_input=input, - check_exit_code=fail_on_errors) + check_exit_code=fail_on_errors, privsep_exec=True) def _get_new_set_ips(self, set_name, expected_ips): new_member_ips = (set(expected_ips) - diff -ruN neutron-bak/agent/linux/iptables_manager.py neutron/agent/linux/iptables_manager.py --- neutron-bak/agent/linux/iptables_manager.py 2022-02-16 15:05:53.853147520 +0800 +++ neutron/agent/linux/iptables_manager.py 2021-07-07 14:59:16.000000000 +0800 @@ -475,12 +475,15 @@ args = ['iptables-save', '-t', table] if self.namespace: args = ['ip', 'netns', 'exec', self.namespace] + args - return self.execute(args, run_as_root=True).split('\n') + #return self.execute(args, run_as_root=True).split('\n') + return self.execute(args, run_as_root=True, + privsep_exec=True).split('\n') def _get_version(self): # Output example is 'iptables v1.6.2' args = ['iptables', '--version'] - version = str(self.execute(args, run_as_root=True).split()[1][1:]) + #version = str(self.execute(args, run_as_root=True).split()[1][1:]) + version = str(self.execute(args, run_as_root=True, privsep_exec=True).split()[1][1:]) LOG.debug('IPTables version installed: %s', version) return version @@ -505,8 +508,10 @@ args += ['-w', self.xlock_wait_time, '-W', XLOCK_WAIT_INTERVAL] try: kwargs = {} if lock else {'log_fail_as_error': False} + #self.execute(args, process_input='\n'.join(commands), + # run_as_root=True, **kwargs) self.execute(args, process_input='\n'.join(commands), - run_as_root=True, **kwargs) + run_as_root=True, privsep_exec=True, **kwargs) except RuntimeError as error: return error @@ -568,7 +573,8 @@ if self.namespace: args = ['ip', 'netns', 'exec', self.namespace] + args try: - save_output = self.execute(args, run_as_root=True) + #save_output = self.execute(args, run_as_root=True) + save_output = self.execute(args, run_as_root=True, privsep_exec=True) except RuntimeError: # We could be racing with a cron job deleting namespaces. # It is useless to try to apply iptables rules over and @@ -769,7 +775,8 @@ args.append('-Z') if self.namespace: args = ['ip', 'netns', 'exec', self.namespace] + args - current_table = self.execute(args, run_as_root=True) + #current_table = self.execute(args, run_as_root=True) + current_table = self.execute(args, run_as_root=True, privsep_exec=True) current_lines = current_table.split('\n') for line in current_lines[2:]: diff -ruN neutron-bak/agent/linux/utils.py neutron/agent/linux/utils.py --- neutron-bak/agent/linux/utils.py 2022-02-16 15:06:03.133090388 +0800 +++ neutron/agent/linux/utils.py 2021-07-08 09:34:12.000000000 +0800 @@ -38,6 +38,7 @@ from neutron.agent.linux import xenapi_root_helper from neutron.common import utils from neutron.conf.agent import common as config +from neutron.privileged.agent.linux import utils as priv_utils from neutron import wsgi @@ -85,13 +86,24 @@ if run_as_root: cmd = shlex.split(config.get_root_helper(cfg.CONF)) + cmd LOG.debug('Running command: %s', cmd) - obj = utils.subprocess_popen(cmd, shell=False, - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + #obj = utils.subprocess_popen(cmd, shell=False, + # stdin=subprocess.PIPE, + # stdout=subprocess.PIPE, + # stderr=subprocess.PIPE) + obj = subprocess.Popen(cmd, shell=False, stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) return obj, cmd +def _execute_process(cmd, _process_input, addl_env, run_as_root): + obj, cmd = create_process(cmd, run_as_root=run_as_root, addl_env=addl_env) + _stdout, _stderr = obj.communicate(_process_input) + returncode = obj.returncode + obj.stdin.close() + _stdout = helpers.safe_decode_utf8(_stdout) + _stderr = helpers.safe_decode_utf8(_stderr) + return _stdout, _stderr, returncode + def execute_rootwrap_daemon(cmd, process_input, addl_env): cmd = list(map(str, addl_env_args(addl_env) + cmd)) @@ -103,31 +115,45 @@ LOG.debug('Running command (rootwrap daemon): %s', cmd) client = RootwrapDaemonHelper.get_client() try: - return client.execute(cmd, process_input) + #return client.execute(cmd, process_input) + returncode, __stdout, _stderr = client.execute(cmd, process_input) except Exception: with excutils.save_and_reraise_exception(): LOG.error('Rootwrap error running command: %s', cmd) + _stdout = helpers.safe_decode_utf8(_stdout) + _stderr = helpers.safe_decode_utf8(_stderr) + return _stdout, _stderr, returncode def execute(cmd, process_input=None, addl_env=None, check_exit_code=True, return_stderr=False, log_fail_as_error=True, - extra_ok_codes=None, run_as_root=False): + extra_ok_codes=None, run_as_root=False, privsep_exec=False): try: if process_input is not None: _process_input = encodeutils.to_utf8(process_input) else: _process_input = None - if run_as_root and cfg.CONF.AGENT.root_helper_daemon: - returncode, _stdout, _stderr = ( - execute_rootwrap_daemon(cmd, process_input, addl_env)) + #if run_as_root and cfg.CONF.AGENT.root_helper_daemon: + # returncode, _stdout, _stderr = ( + # execute_rootwrap_daemon(cmd, process_input, addl_env)) + #else: + # obj, cmd = create_process(cmd, run_as_root=run_as_root, + # addl_env=addl_env) + # _stdout, _stderr = obj.communicate(_process_input) + # returncode = obj.returncode + # obj.stdin.close() + #_stdout = helpers.safe_decode_utf8(_stdout) + #_stderr = helpers.safe_decode_utf8(_stderr) + + if run_as_root and privsep_exec: + _stdout, _stderr, returncode = priv_utils.execute_process( + cmd, _process_input, addl_env) + elif run_as_root and cfg.CONF.AGENT.root_helper_daemon: + _stdout, _stderr, returncode = execute_rootwarp_daemon( + cmd, process_input, addl_env) else: - obj, cmd = create_process(cmd, run_as_root=run_as_root, - addl_env=addl_env) - _stdout, _stderr = obj.communicate(_process_input) - returncode = obj.returncode - obj.stdin.close() - _stdout = helpers.safe_decode_utf8(_stdout) - _stderr = helpers.safe_decode_utf8(_stderr) + _stdout, _stderr, returncode = _execute_process( + cmd, _process_input, addl_env, run_as_root) extra_ok_codes = extra_ok_codes or [] if returncode and returncode not in extra_ok_codes: diff -ruN neutron-bak/cmd/ipset_cleanup.py neutron/cmd/ipset_cleanup.py --- neutron-bak/cmd/ipset_cleanup.py 2022-02-16 15:18:00.727786180 +0800 +++ neutron/cmd/ipset_cleanup.py 2021-07-07 15:00:03.000000000 +0800 @@ -38,7 +38,8 @@ def remove_iptables_reference(ipset): # Remove any iptables reference to this IPset cmd = ['iptables-save'] if 'IPv4' in ipset else ['ip6tables-save'] - iptables_save = utils.execute(cmd, run_as_root=True) + #iptables_save = utils.execute(cmd, run_as_root=True) + iptables_save = utils.execute(cmd, run_as_root=True, privsep_exec=True) if ipset in iptables_save: cmd = ['iptables'] if 'IPv4' in ipset else ['ip6tables'] @@ -50,7 +51,8 @@ params = rule.split() params[0] = '-D' try: - utils.execute(cmd + params, run_as_root=True) + #utils.execute(cmd + params, run_as_root=True) + utils.execute(cmd + params, run_as_root=True, privsep_exec=True) except Exception: LOG.exception('Error, unable to remove iptables rule ' 'for IPset: %s', ipset) @@ -65,7 +67,8 @@ LOG.info('Destroying IPset: %s', ipset) cmd = ['ipset', 'destroy', ipset] try: - utils.execute(cmd, run_as_root=True) + #utils.execute(cmd, run_as_root=True) + utils.execute(cmd, run_as_root=True, privsep_exec=True) except Exception: LOG.exception('Error, unable to destroy IPset: %s', ipset) @@ -75,7 +78,8 @@ LOG.info('Destroying IPsets with prefix: %s', conf.prefix) cmd = ['ipset', '-L', '-n'] - ipsets = utils.execute(cmd, run_as_root=True) + #ipsets = utils.execute(cmd, run_as_root=True) + ipsets = utils.execute(cmd, run_as_root=True, privsep_exec=True) for ipset in ipsets.split('\n'): if conf.allsets or ipset.startswith(conf.prefix): destroy_ipset(conf, ipset) diff -ruN neutron-bak/privileged/agent/linux/utils.py neutron/privileged/agent/linux/utils.py --- neutron-bak/privileged/agent/linux/utils.py 1970-01-01 08:00:00.000000000 +0800 +++ neutron/privileged/agent/linux/utils.py 2021-07-07 14:58:21.000000000 +0800 @@ -0,0 +1,82 @@ +# Copyright 2020 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the 'License'); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import os +import re + +from eventlet.green import subprocess +from neutron_lib.utils import helpers +from oslo_concurrency import processutils +from oslo_utils import fileutils + +from neutron import privileged + + +NETSTAT_PIDS_REGEX = re.compile(r'.* (?P\d{2,6})/.*') + + +@privileged.default.entrypoint +def find_listen_pids_namespace(namespace): + return _find_listen_pids_namespace(namespace) + + +def _find_listen_pids_namespace(namespace): + '''Retrieve a list of pids of listening processes within the given netns + This method is implemented separately to allow unit testing. + ''' + pids = set() + cmd = ['ip', 'netns', 'exec', namespace, 'netstat', '-nlp'] + output = processutils.execute(*cmd) + for line in output[0].splitlines(): + m = NETSTAT_PIDS_REGEX.match(line) + if m: + pids.add(m.group('pid')) + return list(pids) + + +@privileged.default.entrypoint +def delete_if_exists(path, remove=os.unlink): + fileutils.delete_if_exists(path, remove=remove) + + +@privileged.default.entrypoint +def execute_process(cmd, _process_input, addl_env): + obj, cmd = _create_process(cmd, addl_env=addl_env) + _stdout, _stderr = obj.communicate(_process_input) + returncode = obj.returncode + obj.stdin.close() + _stdout = helpers.safe_decode_utf8(_stdout) + _stderr = helpers.safe_decode_utf8(_stderr) + return _stdout, _stderr, returncode + + +def _addl_env_args(addl_env): + '''Build arguments for adding additional environment vars with env''' + + # NOTE (twilson) If using rootwrap, an EnvFilter should be set up for the + # command instead of a CommandFilter. + if addl_env is None: + return [] + return ['env'] + ['%s=%s' % pair for pair in addl_env.items()] + + +def _create_process(cmd, addl_env=None): + '''Create a process object for the given command. + The return value will be a tuple of the process object and the + list of command arguments used to create it. + ''' + cmd = list(map(str, _addl_env_args(addl_env) + list(cmd))) + obj = subprocess.Popen(cmd, shell=False, stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + return obj, cmd |