Skip to content

Commit dd24e2c

Browse files
Working on Codacy security code issues.
1 parent 7ca1d65 commit dd24e2c

1 file changed

Lines changed: 29 additions & 6 deletions

File tree

sigmf/convert/rohdeschwarz.py

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,19 @@
44
#
55
# SPDX-License-Identifier: LGPL-3.0-or-later
66
#
7-
# Last Updated: 4-03-2026
7+
# Last Updated: 4-04-2026
88

99
"""Rohde and Schwarz Converter"""
1010

1111
import io
12+
import os
1213
import logging
1314
import tarfile
1415
import getpass
1516
import tempfile
16-
import xml.etree.ElementTree as ET
17+
from defusedxml.ElementTree import parse
18+
19+
1720
from datetime import datetime, timedelta, timezone
1821
from pathlib import Path
1922
from typing import List, Optional, Tuple
@@ -60,6 +63,26 @@ def xml_to_dict(elem):
6063
return result
6164

6265

66+
def is_safe_member(tar, member, target_dir):
67+
"""
68+
Ensure the member will extract inside target_dir.
69+
Prevents path traversal attacks.
70+
"""
71+
member_path = os.path.join(target_dir, member.name)
72+
abs_target = os.path.abspath(target_dir)
73+
abs_member = os.path.abspath(member_path)
74+
75+
return abs_member.startswith(abs_target)
76+
77+
def safe_extract(tar, target_dir):
78+
"""
79+
Extract only safe members from a tarfile.
80+
"""
81+
for member in tar.getmembers():
82+
if not is_safe_member(tar, member, target_dir):
83+
raise Exception(f"Unsafe path detected in TAR: {member.name}")
84+
tar.extract(member, target_dir)
85+
6386
def extract_iq_tar_to_directory(rohdeschwarz_path, file_dest_dir=None):
6487
tar_path = Path(rohdeschwarz_path)
6588

@@ -69,7 +92,7 @@ def extract_iq_tar_to_directory(rohdeschwarz_path, file_dest_dir=None):
6992
file_dest_dir.mkdir(parents=True, exist_ok=True)
7093

7194
with tarfile.open(tar_path, "r") as tar:
72-
tar.extractall(file_dest_dir)
95+
safe_extract(tar, file_dest_dir)
7396

7497
xml_files = list(file_dest_dir.glob("*.xml"))
7598
if not xml_files:
@@ -78,7 +101,7 @@ def extract_iq_tar_to_directory(rohdeschwarz_path, file_dest_dir=None):
78101
# Assuming there is only one XML file in the archive, return its path for further processing
79102
return xml_files[0]
80103

81-
def _text_of(root: ET.Element, tag: str) -> Optional[str]:
104+
def _text_of(root, tag: str) -> Optional[str]:
82105
"""Extract and strip text from XML element."""
83106
elem = root.find(tag)
84107
return elem.text.strip() if (elem is not None and elem.text is not None) else None
@@ -97,7 +120,7 @@ def validate_rohdeschwarz(xml_path: Path) -> None:
97120
SigMFConversionError
98121
If required fields are missing or invalid, or IQ file doesn't exist.
99122
"""
100-
tree = ET.parse(xml_path)
123+
tree = parse(xml_path)
101124
root = tree.getroot()
102125

103126
# validate CenterFrequency
@@ -186,7 +209,7 @@ def _build_metadata(xml_path: Path) -> Tuple[dict, dict, list, int]:
186209
log.info("converting rohdeschwarz xml metadata to sigmf format")
187210

188211
xml_path = Path(xml_path)
189-
tree = ET.parse(xml_path)
212+
tree = parse(xml_path)
190213
root = tree.getroot()
191214

192215
# validate required fields and associated IQ file

0 commit comments

Comments
 (0)