[sonic-config-engine] Replace os.system, replace yaml.load, remove subprocess with shell=True#12533
Conversation
Signed-off-by: maipbui <[email protected]>
| self.yang_parser.loadYangModel() | ||
| self.test_dir = os.path.dirname(os.path.realpath(__file__)) | ||
| self.script_file = PYTHON_INTERPRETTER + ' ' + os.path.join(self.test_dir, '..', 'sonic-cfggen') | ||
| self.script_file = [PYTHON_INTERPRETTER] + [os.path.join(self.test_dir, '..', 'sonic-cfggen')] |
There was a problem hiding this comment.
| self.script_file = [PYTHON_INTERPRETTER] + [os.path.join(self.test_dir, '..', 'sonic-cfggen')] | |
| self.script_file = [PYTHON_INTERPRETTER, os.path.join(self.test_dir, '..', 'sonic-cfggen')] | |
| ``` #Closed |
| args, unknown = parser.parse_known_args(shlex.split(argument)) | ||
| parser.add_argument("-o", "--output-file", help="Output file", nargs='?', const=None) | ||
| args, unknown = parser.parse_known_args(argument) | ||
| print(args) |
| parser.add_argument("-S", "--hwsku-config", help="hwsku config file, used with -p and -m or -k", nargs='?', const=None) | ||
| parser.add_argument("-j", "--json", help="additional json file input, used with -p, -S and -m or -k", nargs='?', const=None) | ||
| args, unknown = parser.parse_known_args(shlex.split(argument)) | ||
| parser.add_argument("-o", "--output-file", help="Output file", nargs='?', const=None) |
There was a problem hiding this comment.
Because there're some commands that have output redirection.
Original command:
Changed command
Implementation of new behavior:
https://github.com/sonic-net/sonic-buildimage/blob/ce3e0759543cd00a5a515b31ffb3e87de48c2e76/src/sonic-config-engine/tests/test_j2files.py#L46-#L59
There was a problem hiding this comment.
I prefer following subprocess functions, adding stdout=None, stderr=None to this function parameter list.
| self.yang = utils.YangWrapper() | ||
| self.test_dir = os.path.dirname(os.path.realpath(__file__)) | ||
| self.script_file = utils.PYTHON_INTERPRETTER + ' ' + os.path.join(self.test_dir, '..', 'sonic-cfggen') | ||
| self.script_file = [utils.PYTHON_INTERPRETTER] + [os.path.join(self.test_dir, '..', 'sonic-cfggen')] |
|
|
||
| def run_script(self, argument, check_stderr=False, verbose=False): | ||
| print('\n Running sonic-cfggen ' + argument) | ||
| print('\n Running sonic-cfggen ', argument) |
There was a problem hiding this comment.
No, but argument variable is a list, cannot be concatenated with string in the print statement.
There was a problem hiding this comment.
Updated to shlex.join
There was a problem hiding this comment.
I notice it is not available in python 3.7. Then + is good enough in test code.
| def setUp(self): | ||
| self.test_dir = os.path.dirname(os.path.realpath(__file__)) | ||
| self.script_file = utils.PYTHON_INTERPRETTER + ' ' + os.path.join(self.test_dir, '..', 'sonic-cfggen') | ||
| self.script_file = [utils.PYTHON_INTERPRETTER] + [os.path.join(self.test_dir, '..', 'sonic-cfggen')] |
| def setUp(self): | ||
| self.test_dir = os.path.dirname(os.path.realpath(__file__)) | ||
| self.script_file = utils.PYTHON_INTERPRETTER + ' ' + os.path.join(self.test_dir, '..', 'sonic-cfggen') | ||
| self.script_file = [utils.PYTHON_INTERPRETTER] + [os.path.join(self.test_dir, '..', 'sonic-cfggen')] |
| self.t2_chassis_fe_port_config = os.path.join(self.test_dir, 't2-chassis-fe-port-config.ini') | ||
|
|
||
| def run_script(self, argument, check_stderr=False): | ||
| print('\n Running sonic-cfggen ' + argument) |
| def setUp(self): | ||
| self.test_dir = os.path.dirname(os.path.realpath(__file__)) | ||
| self.script_file = utils.PYTHON_INTERPRETTER + ' ' + os.path.join(self.test_dir, '..', 'sonic-cfggen') | ||
| self.script_file = [utils.PYTHON_INTERPRETTER] + [os.path.join(self.test_dir, '..', 'sonic-cfggen')] |
| def run_script(self, argument): | ||
| print('CMD: sonic-cfggen ' + argument) | ||
| output = subprocess.check_output(self.script_file + ' ' + argument, shell=True) | ||
| print('CMD: sonic-cfggen ', argument) |
| self.yang = utils.YangWrapper() | ||
| self.test_dir = os.path.dirname(os.path.realpath(__file__)) | ||
| self.script_file = utils.PYTHON_INTERPRETTER + ' ' + os.path.join(self.test_dir, '..', 'sonic-cfggen') | ||
| self.script_file = [utils.PYTHON_INTERPRETTER] + [os.path.join(self.test_dir, '..', 'sonic-cfggen')] |
| self.port_config = os.path.join(self.test_dir, 't0-sample-port-config.ini') | ||
|
|
||
| def run_script(self, argument, check_stderr=False): | ||
| print('\n Running sonic-cfggen ' + argument) |
| self.test_dir = os.path.dirname(os.path.realpath(__file__)) | ||
| self.test_data_dir = os.path.join(self.test_dir, 'multi_npu_data') | ||
| self.script_file = utils.PYTHON_INTERPRETTER + ' ' + os.path.join(self.test_dir, '..', 'sonic-cfggen') | ||
| self.script_file = [utils.PYTHON_INTERPRETTER] + [os.path.join(self.test_dir, '..', 'sonic-cfggen')] |
| os.environ["CFGGEN_UNIT_TESTING"] = "2" | ||
|
|
||
| def run_script(self, argument, check_stderr=False): | ||
| print('\n Running sonic-cfggen ' + argument) |
Signed-off-by: maipbui <[email protected]>
Signed-off-by: maipbui <[email protected]>
| write_output = False | ||
| if '-o' in argument: | ||
| write_output = True | ||
| output_file = argument[-1] |
There was a problem hiding this comment.
How to guarantee '-o' is the last argument?
There was a problem hiding this comment.
I changed to different solution.
| os.system(echo_cmd) | ||
| subprocess.call(['sudo', 'mkdir', '/host']) | ||
| subprocess.call(['sudo', 'touch', '/host/machine.conf']) | ||
| getstatusoutput_noshell_pipe(echo_cmd1, echo_cmd2) |
There was a problem hiding this comment.
Can you explain these commands?
| def remove_machine_conf(self, file_exist, dir_exist): | ||
| if not file_exist: | ||
| os.system('sudo rm -f /host/machine.conf') | ||
| subprocess.call(['sudo', 'rm', '-f', '/host/machine.conf']) |
There was a problem hiding this comment.
there's no user input in 'sudo rm -f /host/machine.conf', why is it a risk?
There was a problem hiding this comment.
It's better for extra security when using subprocess and with array of strings. https://semgrep.dev/docs/cheat-sheets/python-command-injection/#1c-using-os-module-to-execute-commands
Signed-off-by: maipbui <[email protected]>
Signed-off-by: maipbui <[email protected]>
….load, remove subprocess with shell=True (sonic-net#12533)" (sonic-net#12616)" This reverts commit 661c467.
…ubprocess with shell=True (#12607) Signed-off-by: maipbui <[email protected]> #### Why I did it Missing import statement in PR #12533 #### How I did it Revert [PR 12646](#12616) Add import statement 1. https://github.com/sonic-net/sonic-buildimage/blob/31f7afa92e8d1e353ef2f3b004711dd18c0d94f6/src/sonic-config-engine/tests/test_j2files_t2_chassis_fe.py#L8 2. https://github.com/sonic-net/sonic-buildimage/blob/31f7afa92e8d1e353ef2f3b004711dd18c0d94f6/src/sonic-config-engine/tests/test_j2files.py#L8 3. https://github.com/sonic-net/sonic-buildimage/blob/31f7afa92e8d1e353ef2f3b004711dd18c0d94f6/src/sonic-config-engine/tests/test_multinpu_cfggen.py#L11 #### How to verify it Pass UT
Signed-off-by: maipbui [email protected]
Why I did it
subprocessis used withshell=True, which is very dangerous for shell injection.os- not secure against maliciously constructed input and dangerous if used to evaluate dynamic contentyaml.loadcan create arbitrary Python objectsHow I did it
Replace
osbysubprocess, removeshell=TrueUse
yaml.safe_load()How to verify it
Pass UT
Which release branch to backport (provide reason below if selected)
Description for the changelog
Ensure to add label/tag for the feature raised. example - PR#2174 under sonic-utilities repo. where, Generic Config and Update feature has been labelled as GCU.
Link to config_db schema for YANG module changes
A picture of a cute animal (not mandatory but encouraged)