Skip to content

Commit 9975cc8

Browse files
florcabral130s
andauthored
Fix unsafe yaml load on dynparam (#202)
Co-authored-by: Isaac Saito <[email protected]>
1 parent 2654f22 commit 9975cc8

6 files changed

+43
-2
lines changed

package.xml

+2
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,6 @@
3737
<exec_depend>roslib</exec_depend>
3838
<exec_depend>rospy</exec_depend>
3939
<exec_depend>rosservice</exec_depend>
40+
41+
<test_depend>rosbash</test_depend>
4042
</package>

scripts/dynparam

+2-2
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ Examples:
110110
node = args[0]
111111
if len(args) == 2:
112112
node, value = args[0], args[1]
113-
values_dict = yaml.load(value, Loader=yaml.Loader)
113+
values_dict = yaml.safe_load(value)
114114
if type(values_dict) != dict:
115115
parser.error('invalid arguments. Please specify either a node name, parameter name and parameter value, or a node name and a YAML dictionary')
116116
elif len(args) == 3:
@@ -159,7 +159,7 @@ def do_load():
159159
f = open(path, 'r')
160160
try:
161161
params = {}
162-
for doc in yaml.load_all(f.read(), Loader=yaml.Loader):
162+
for doc in yaml.safe_load_all(f.read()):
163163
params.update(doc)
164164
finally:
165165
f.close()

test/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,5 @@ target_link_libraries(dynamic_reconfigure-test_client dynamic_reconfigure_config
1717
add_dependencies(tests dynamic_reconfigure-test_client)
1818

1919
add_rostest(test_python_simple_client.launch)
20+
21+
add_rostest(test_dynparam.launch)

test/test_dynparam.launch

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<launch>
2+
<node pkg="dynamic_reconfigure" type="dynamic_reconfigure-ref_server" name="ref_server" output="screen" />
3+
4+
<test test-name="test_dynparam" pkg="dynamic_reconfigure" type="test_dynparam.py" />
5+
</launch>

test/test_dynparam.py

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/usr/bin/env python
2+
3+
import unittest
4+
import rostest
5+
import rospy
6+
import os
7+
import subprocess
8+
9+
10+
class TestDynparam(unittest.TestCase):
11+
12+
def test_dynparam(self):
13+
unsafe_yaml_file = os.path.join(os.path.abspath(os.path.join(os.path.dirname(__file__))), 'test_unsafe_yaml.yaml')
14+
retcode_unsafe_yaml = 0
15+
16+
try:
17+
# run dynparam load with insecure yaml
18+
output = subprocess.check_output(['rosrun dynamic_reconfigure dynparam load ref_server ' + unsafe_yaml_file], stderr=subprocess.STDOUT, shell=True, executable="/bin/bash")
19+
except subprocess.CalledProcessError as e:
20+
self.assertIn('could not determine a constructor for the tag'.encode(), e.output) # check the right error is being thrown
21+
retcode_unsafe_yaml = e.returncode
22+
23+
# check the test failed
24+
self.assertNotEqual(retcode_unsafe_yaml, 0)
25+
26+
27+
if __name__ == '__main__':
28+
rospy.init_node('dynparam_test')
29+
rospy.sleep(3.0)
30+
rostest.rosrun('dynamic_reconfigure', 'test_dynparam', TestDynparam)

test/test_unsafe_yaml.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# When the line below gets read by unsafe yaml loader (e.g. `yaml.load`), the bash code may get executed, which is a huge security risk.
2+
str_: !!python/object/apply:os.system ["cat /etc/passwd"]

0 commit comments

Comments
 (0)