Skip to content

Commit 5750057

Browse files
authored
[utilities_common] replace shell=True (sonic-net#2718)
#### What I did `subprocess()` - when using with `shell=True` is dangerous. Using subprocess function without a static string can lead to command injection. #### How I did it remove shell=True in utilities_common.cli.run_command() function. `subprocess()` - use `shell=False` instead, use list of strings Ref: [https://semgrep.dev/docs/cheat-sheets/python-command-injection/#mitigation](https://semgrep.dev/docs/cheat-sheets/python-command-injection/#mitigation) #### How to verify it Pass UT Manual test Signed-off-by: Mai Bui <[email protected]>
1 parent 6e0ee3e commit 5750057

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1451
-557
lines changed

clear/main.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -492,10 +492,10 @@ def flowcnt_route(ctx, namespace):
492492
"""Clear all route flow counters"""
493493
exit_if_route_flow_counter_not_support()
494494
if ctx.invoked_subcommand is None:
495-
command = "flow_counters_stat -c -t route"
495+
command = ['flow_counters_stat', '-c', '-t', 'route']
496496
# None namespace means default namespace
497497
if namespace is not None:
498-
command += " -n {}".format(namespace)
498+
command += ['-n', str(namespace)]
499499
clicommon.run_command(command)
500500

501501

@@ -506,12 +506,12 @@ def flowcnt_route(ctx, namespace):
506506
@click.argument('prefix-pattern', required=True)
507507
def pattern(prefix_pattern, vrf, namespace):
508508
"""Clear route flow counters by pattern"""
509-
command = "flow_counters_stat -c -t route --prefix_pattern {}".format(prefix_pattern)
509+
command = ['flow_counters_stat', '-c', '-t', 'route', '--prefix_pattern', str(prefix_pattern)]
510510
if vrf:
511-
command += ' --vrf {}'.format(vrf)
511+
command += ['--vrf', str(vrf)]
512512
# None namespace means default namespace
513513
if namespace is not None:
514-
command += " -n {}".format(namespace)
514+
command += ['-n', str(namespace)]
515515
clicommon.run_command(command)
516516

517517

@@ -522,12 +522,12 @@ def pattern(prefix_pattern, vrf, namespace):
522522
@click.argument('prefix', required=True)
523523
def route(prefix, vrf, namespace):
524524
"""Clear route flow counters by prefix"""
525-
command = "flow_counters_stat -c -t route --prefix {}".format(prefix)
525+
command = ['flow_counters_stat', '-c', '-t', 'route', '--prefix', str(prefix)]
526526
if vrf:
527-
command += ' --vrf {}'.format(vrf)
527+
command += ['--vrf', str(vrf)]
528528
# None namespace means default namespace
529529
if namespace is not None:
530-
command += " -n {}".format(namespace)
530+
command += ['-n', str(namespace)]
531531
clicommon.run_command(command)
532532

533533

config/main.py

+182-188
Large diffs are not rendered by default.

config/plugins/mlnx.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
SNIFFER_CONF_FILE = '/etc/supervisor/conf.d/mlnx_sniffer.conf'
5353
SNIFFER_CONF_FILE_IN_CONTAINER = CONTAINER_NAME + ':' + SNIFFER_CONF_FILE
5454
# Command to restart swss service
55-
COMMAND_RESTART_SWSS = 'systemctl restart swss.service'
55+
COMMAND_RESTART_SWSS = ['systemctl', 'restart', 'swss.service']
5656

5757

5858
# Global logger instance
@@ -99,12 +99,12 @@ def env_variable_delete(delete_line):
9999

100100

101101
def conf_file_copy(src, dest):
102-
command = 'docker cp ' + src + ' ' + dest
102+
command = ['docker', 'cp', str(src), str(dest)]
103103
clicommon.run_command(command)
104104

105105

106106
def conf_file_receive():
107-
command = "docker exec {} bash -c 'touch {}'".format(CONTAINER_NAME, SNIFFER_CONF_FILE)
107+
command = ['docker', 'exec', str(CONTAINER_NAME), 'bash', '-c', 'touch ' + str(SNIFFER_CONF_FILE)]
108108
clicommon.run_command(command)
109109
conf_file_copy(SNIFFER_CONF_FILE_IN_CONTAINER, TMP_SNIFFER_CONF_FILE)
110110

@@ -134,7 +134,7 @@ def sniffer_env_variable_set(enable, env_variable_name, env_variable_string=""):
134134
if not ignore:
135135
config_file_send()
136136

137-
command = 'rm -rf {}'.format(TMP_SNIFFER_CONF_FILE)
137+
command = ['rm', '-rf', str(TMP_SNIFFER_CONF_FILE)]
138138
clicommon.run_command(command)
139139

140140
return ignore

config/syslog.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -410,8 +410,8 @@ def add(db, server_ip_address, source, port, vrf):
410410

411411
try:
412412
add_entry(db.cfgdb, table, key, data)
413-
clicommon.run_command("systemctl reset-failed rsyslog-config rsyslog", display_cmd=True)
414-
clicommon.run_command("systemctl restart rsyslog-config", display_cmd=True)
413+
clicommon.run_command(['systemctl', 'reset-failed', 'rsyslog-config', 'rsyslog'], display_cmd=True)
414+
clicommon.run_command(['systemctl', 'restart', 'rsyslog-config'], display_cmd=True)
415415
log.log_notice("Added remote syslog logging: server={},source={},port={},vrf={}".format(
416416
server_ip_address,
417417
data.get(SYSLOG_SOURCE, "N/A"),
@@ -442,8 +442,8 @@ def delete(db, server_ip_address):
442442

443443
try:
444444
del_entry(db.cfgdb, table, key)
445-
clicommon.run_command("systemctl reset-failed rsyslog-config rsyslog", display_cmd=True)
446-
clicommon.run_command("systemctl restart rsyslog-config", display_cmd=True)
445+
clicommon.run_command(['systemctl', 'reset-failed', 'rsyslog-config', 'rsyslog'], display_cmd=True)
446+
clicommon.run_command(['systemctl', 'restart', 'rsyslog-config'], display_cmd=True)
447447
log.log_notice("Removed remote syslog logging: server={}".format(server_ip_address))
448448
except Exception as e:
449449
log.log_error("Failed to remove remote syslog logging: {}".format(str(e)))

config/vlan.py

+12-13
Original file line numberDiff line numberDiff line change
@@ -139,31 +139,30 @@ def del_vlan(db, vid, no_restart_dhcp_relay):
139139

140140

141141
def restart_ndppd():
142-
verify_swss_running_cmd = "docker container inspect -f '{{.State.Status}}' swss"
143-
docker_exec_cmd = "docker exec -i swss {}"
144-
ndppd_status_cmd= "supervisorctl status ndppd"
145-
ndppd_conf_copy_cmd = "cp /usr/share/sonic/templates/ndppd.conf /etc/supervisor/conf.d/"
146-
supervisor_update_cmd = "supervisorctl update"
147-
ndppd_config_gen_cmd = "sonic-cfggen -d -t /usr/share/sonic/templates/ndppd.conf.j2,/etc/ndppd.conf"
148-
ndppd_restart_cmd = "supervisorctl restart ndppd"
142+
verify_swss_running_cmd = ['docker', 'container', 'inspect', '-f', '{{.State.Status}}', 'swss']
143+
docker_exec_cmd = ['docker', 'exec', '-i', 'swss']
144+
ndppd_config_gen_cmd = ['sonic-cfggen', '-d', '-t', '/usr/share/sonic/templates/ndppd.conf.j2,/etc/ndppd.conf']
145+
ndppd_restart_cmd =['supervisorctl', 'restart', 'ndppd']
146+
ndppd_status_cmd= ["supervisorctl", "status", "ndppd"]
147+
ndppd_conf_copy_cmd = ['cp', '/usr/share/sonic/templates/ndppd.conf', '/etc/supervisor/conf.d/']
148+
supervisor_update_cmd = ['supervisorctl', 'update']
149149

150150
output, _ = clicommon.run_command(verify_swss_running_cmd, return_cmd=True)
151151

152152
if output and output.strip() != "running":
153153
click.echo(click.style('SWSS container is not running, changes will take effect the next time the SWSS container starts', fg='red'),)
154154
return
155155

156-
_, rc = clicommon.run_command(docker_exec_cmd.format(ndppd_status_cmd), ignore_error=True, return_cmd=True)
156+
_, rc = clicommon.run_command(docker_exec_cmd + ndppd_status_cmd, ignore_error=True, return_cmd=True)
157157

158158
if rc != 0:
159-
clicommon.run_command(docker_exec_cmd.format(ndppd_conf_copy_cmd))
160-
clicommon.run_command(docker_exec_cmd.format(supervisor_update_cmd), return_cmd=True)
159+
clicommon.run_command(docker_exec_cmd + ndppd_conf_copy_cmd)
160+
clicommon.run_command(docker_exec_cmd + supervisor_update_cmd, return_cmd=True)
161161

162162
click.echo("Starting ndppd service")
163-
clicommon.run_command(docker_exec_cmd.format(ndppd_config_gen_cmd))
163+
clicommon.run_command(docker_exec_cmd + ndppd_config_gen_cmd)
164164
sleep(3)
165-
clicommon.run_command(docker_exec_cmd.format(ndppd_restart_cmd), return_cmd=True)
166-
165+
clicommon.run_command(docker_exec_cmd + ndppd_restart_cmd, return_cmd=True)
167166

168167
@vlan.command('proxy_arp')
169168
@click.argument('vid', metavar='<vid>', required=True, type=int)

scripts/sonic-bootchart

+4-4
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,12 @@ def check_bootchart_installed():
5050

5151
def get_enabled_status():
5252
""" Get systemd-bootchart status """
53-
output, _ = clicommon.run_command("systemctl is-enabled systemd-bootchart", return_cmd=True)
53+
output, _ = clicommon.run_command(['systemctl', 'is-enabled', 'systemd-bootchart'], return_cmd=True)
5454
return output
5555

5656
def get_active_status():
5757
""" Get systemd-bootchart status """
58-
output, _ = clicommon.run_command("systemctl is-active systemd-bootchart", return_cmd=True)
58+
output, _ = clicommon.run_command(['systemctl', 'is-active', 'systemd-bootchart'], return_cmd=True)
5959
return output
6060

6161
def get_output_files():
@@ -75,14 +75,14 @@ def cli():
7575
@root_privileges_required
7676
def enable():
7777
""" Enable bootchart """
78-
clicommon.run_command("systemctl enable systemd-bootchart", display_cmd=True)
78+
clicommon.run_command(['systemctl', 'enable', 'systemd-bootchart'], display_cmd=True)
7979

8080

8181
@cli.command()
8282
@root_privileges_required
8383
def disable():
8484
""" Disable bootchart """
85-
clicommon.run_command("systemctl disable systemd-bootchart", display_cmd=True)
85+
clicommon.run_command(['systemctl', 'disable', 'systemd-bootchart'], display_cmd=True)
8686

8787

8888
@cli.command()

show/acl.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ def acl():
1919
@click.option('--verbose', is_flag=True, help="Enable verbose output")
2020
def rule(table_name, rule_id, verbose):
2121
"""Show existing ACL rules"""
22-
cmd = "acl-loader show rule"
22+
cmd = ['acl-loader', 'show', 'rule']
2323

2424
if table_name is not None:
25-
cmd += " {}".format(table_name)
25+
cmd += [str(table_name)]
2626

2727
if rule_id is not None:
28-
cmd += " {}".format(rule_id)
28+
cmd += [str(rule_id)]
2929

3030
clicommon.run_command(cmd, display_cmd=verbose)
3131

@@ -36,9 +36,9 @@ def rule(table_name, rule_id, verbose):
3636
@click.option('--verbose', is_flag=True, help="Enable verbose output")
3737
def table(table_name, verbose):
3838
"""Show existing ACL tables"""
39-
cmd = "acl-loader show table"
39+
cmd = ['acl-loader', 'show', 'table']
4040

4141
if table_name is not None:
42-
cmd += " {}".format(table_name)
42+
cmd += [str(table_name)]
4343

4444
clicommon.run_command(cmd, display_cmd=verbose)

show/chassis_modules.py

+10-10
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,13 @@ def midplane_status(chassis_module_name):
117117
def system_ports(systemportname, namespace, verbose):
118118
"""Show VOQ system ports information"""
119119

120-
cmd = "voqutil -c system_ports"
120+
cmd = ['voqutil', '-c', 'system_ports']
121121

122122
if systemportname is not None:
123-
cmd += " -i \"{}\"".format(systemportname)
123+
cmd += ['-i', str(systemportname)]
124124

125125
if namespace is not None:
126-
cmd += " -n {}".format(namespace)
126+
cmd += ['-n', str(namespace)]
127127

128128
clicommon.run_command(cmd, display_cmd=verbose)
129129

@@ -134,13 +134,13 @@ def system_ports(systemportname, namespace, verbose):
134134
def system_neighbors(asicname, ipaddress, verbose):
135135
"""Show VOQ system neighbors information"""
136136

137-
cmd = "voqutil -c system_neighbors"
137+
cmd = ['voqutil', '-c', 'system_neighbors']
138138

139139
if ipaddress is not None:
140-
cmd += " -a {}".format(ipaddress)
140+
cmd += ['-a', str(ipaddress)]
141141

142142
if asicname is not None:
143-
cmd += " -n {}".format(asicname)
143+
cmd += ['-n', str(asicname)]
144144

145145
clicommon.run_command(cmd, display_cmd=verbose)
146146

@@ -152,15 +152,15 @@ def system_neighbors(asicname, ipaddress, verbose):
152152
def system_lags(systemlagname, asicname, linecardname, verbose):
153153
"""Show VOQ system lags information"""
154154

155-
cmd = "voqutil -c system_lags"
155+
cmd = ['voqutil', '-c', 'system_lags']
156156

157157
if systemlagname is not None:
158-
cmd += " -s \"{}\"".format(systemlagname)
158+
cmd += ['-s', str(systemlagname)]
159159

160160
if asicname is not None:
161-
cmd += " -n {}".format(asicname)
161+
cmd += ['-n', str(asicname)]
162162

163163
if linecardname is not None:
164-
cmd += " -l \"{}\"".format(linecardname)
164+
cmd += ['-l', str(linecardname)]
165165

166166
clicommon.run_command(cmd, display_cmd=verbose)

show/dropcounters.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ def dropcounters():
1818
@click.option('--verbose', is_flag=True, help="Enable verbose output")
1919
def configuration(group, verbose):
2020
"""Show current drop counter configuration"""
21-
cmd = "dropconfig -c show_config"
21+
cmd = ['dropconfig', '-c', 'show_config']
2222

2323
if group:
24-
cmd += " -g '{}'".format(group)
24+
cmd += ['-g', str(group)]
2525

2626
clicommon.run_command(cmd, display_cmd=verbose)
2727

@@ -31,7 +31,7 @@ def configuration(group, verbose):
3131
@click.option('--verbose', is_flag=True, help="Enable verbose output")
3232
def capabilities(verbose):
3333
"""Show device drop counter capabilities"""
34-
cmd = "dropconfig -c show_capabilities"
34+
cmd = ['dropconfig', '-c', 'show_capabilities']
3535

3636
clicommon.run_command(cmd, display_cmd=verbose)
3737

@@ -43,12 +43,12 @@ def capabilities(verbose):
4343
@click.option('--verbose', is_flag=True, help="Enable verbose output")
4444
def counts(group, counter_type, verbose):
4545
"""Show drop counts"""
46-
cmd = "dropstat -c show"
46+
cmd = ['dropstat', '-c', 'show']
4747

4848
if group:
49-
cmd += " -g '{}'".format(group)
49+
cmd += ['-g', str(group)]
5050

5151
if counter_type:
52-
cmd += " -t '{}'".format(counter_type)
52+
cmd += ['-t', str(counter_type)]
5353

5454
clicommon.run_command(cmd, display_cmd=verbose)

show/fabric.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -18,30 +18,30 @@ def counters():
1818
@click.option('-e', '--errors', is_flag=True)
1919
def reachability(namespace, errors):
2020
"""Show fabric reachability"""
21-
cmd = "fabricstat -r"
21+
cmd = ['fabricstat', '-r']
2222
if namespace is not None:
23-
cmd += " -n {}".format(namespace)
23+
cmd += ['-n', str(namespace)]
2424
if errors:
25-
cmd += " -e"
25+
cmd += ["-e"]
2626
clicommon.run_command(cmd)
2727

2828
@counters.command()
2929
@multi_asic_util.multi_asic_click_option_namespace
3030
@click.option('-e', '--errors', is_flag=True)
3131
def port(namespace, errors):
3232
"""Show fabric port stat"""
33-
cmd = "fabricstat"
33+
cmd = ["fabricstat"]
3434
if namespace is not None:
35-
cmd += " -n {}".format(namespace)
35+
cmd += ['-n', str(namespace)]
3636
if errors:
37-
cmd += " -e"
37+
cmd += ["-e"]
3838
clicommon.run_command(cmd)
3939

4040
@counters.command()
4141
@multi_asic_util.multi_asic_click_option_namespace
4242
def queue(namespace):
4343
"""Show fabric queue stat"""
44-
cmd = "fabricstat -q"
44+
cmd = ['fabricstat', '-q']
4545
if namespace is not None:
46-
cmd += " -n {}".format(namespace)
46+
cmd += ['-n', str(namespace)]
4747
clicommon.run_command(cmd)

show/flow_counters.py

+10-10
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ def flowcnt_trap():
2121
@click.option('--namespace', '-n', 'namespace', default=None, type=click.Choice(multi_asic_util.multi_asic_ns_choices()), show_default=True, help='Namespace name or all')
2222
def stats(verbose, namespace):
2323
"""Show trap flow counter statistic"""
24-
cmd = "flow_counters_stat -t trap"
24+
cmd = ['flow_counters_stat', '-t', 'trap']
2525
if namespace is not None:
26-
cmd += " -n {}".format(namespace)
26+
cmd += ['-n', str(namespace)]
2727
clicommon.run_command(cmd, display_cmd=verbose)
2828

2929
#
@@ -57,9 +57,9 @@ def config(db):
5757
def stats(ctx, verbose, namespace):
5858
"""Show statistics of all route flow counters"""
5959
if ctx.invoked_subcommand is None:
60-
command = "flow_counters_stat -t route"
60+
command = ['flow_counters_stat', '-t', 'route']
6161
if namespace is not None:
62-
command += " -n {}".format(namespace)
62+
command += ['-n', str(namespace)]
6363
clicommon.run_command(command, display_cmd=verbose)
6464

6565

@@ -70,11 +70,11 @@ def stats(ctx, verbose, namespace):
7070
@click.argument('prefix-pattern', required=True)
7171
def pattern(prefix_pattern, vrf, verbose, namespace):
7272
"""Show statistics of route flow counters by pattern"""
73-
command = "flow_counters_stat -t route --prefix_pattern \"{}\"".format(prefix_pattern)
73+
command = ['flow_counters_stat', '-t', 'route', '--prefix_pattern', str(prefix_pattern)]
7474
if vrf:
75-
command += ' --vrf {}'.format(vrf)
75+
command += ['--vrf', str(vrf)]
7676
if namespace is not None:
77-
command += " -n {}".format(namespace)
77+
command += ['-n', str(namespace)]
7878
clicommon.run_command(command, display_cmd=verbose)
7979

8080

@@ -85,9 +85,9 @@ def pattern(prefix_pattern, vrf, verbose, namespace):
8585
@click.argument('prefix', required=True)
8686
def route(prefix, vrf, verbose, namespace):
8787
"""Show statistics of route flow counters by prefix"""
88-
command = "flow_counters_stat -t route --prefix {}".format(prefix)
88+
command = ['flow_counters_stat', '-t', 'route', '--prefix', str(prefix)]
8989
if vrf:
90-
command += ' --vrf {}'.format(vrf)
90+
command += ['--vrf', str(vrf)]
9191
if namespace is not None:
92-
command += " -n {}".format(namespace)
92+
command += ['-n', str(namespace)]
9393
clicommon.run_command(command, display_cmd=verbose)

0 commit comments

Comments
 (0)