diff --git a/board/common/rootfs/usr/libexec/infix/iw.py b/board/common/rootfs/usr/libexec/infix/iw.py index 0ce76d36..035dd53f 100755 --- a/board/common/rootfs/usr/libexec/infix/iw.py +++ b/board/common/rootfs/usr/libexec/infix/iw.py @@ -13,6 +13,13 @@ import sys import json import subprocess import re +def decode_iw_ssid(ssid): + """Decode iw escaped SSID (\\xHH) to UTF-8, stripping non-printable chars.""" + try: + ssid = ssid.encode().decode('unicode_escape').encode('latin-1').decode('utf-8') + except (UnicodeDecodeError, UnicodeEncodeError): + return ssid + return ''.join(c for c in ssid if c.isprintable()) def run_iw(*args): @@ -260,7 +267,7 @@ def parse_interface_info(ifname): # SSID elif stripped.startswith('ssid '): - result['ssid'] = ' '.join(stripped.split()[1:]) + result['ssid'] = decode_iw_ssid(' '.join(stripped.split()[1:])) # Channel/frequency elif stripped.startswith('channel '): @@ -488,7 +495,7 @@ def parse_link(ifname): # SSID: NetworkName elif stripped.startswith('SSID: '): - result['ssid'] = stripped[6:] + result['ssid'] = decode_iw_ssid(stripped[6:]) # freq: 5180 elif stripped.startswith('freq: '): @@ -582,7 +589,7 @@ def main(): else: data = {'error': f'Unknown command: {command}'} - print(json.dumps(data, indent=2)) + print(json.dumps(data, indent=2, ensure_ascii=False)) except Exception as e: print(json.dumps({'error': str(e)})) diff --git a/src/confd/yang/confd/infix-if-wifi.yang b/src/confd/yang/confd/infix-if-wifi.yang index 9d16cfcf..d2b8d350 100644 --- a/src/confd/yang/confd/infix-if-wifi.yang +++ b/src/confd/yang/confd/infix-if-wifi.yang @@ -151,6 +151,9 @@ submodule infix-if-wifi { leaf ssid { type string { length "1..32"; + pattern '[^\x00-\x1f\x22\x5c\x7f]*' { + error-message "SSID must not contain control characters, double quotes, or backslashes."; + } } mandatory true; description @@ -322,6 +325,9 @@ submodule infix-if-wifi { leaf ssid { type string { length "1..32"; + pattern '[^\x00-\x1f\x22\x5c\x7f]*' { + error-message "SSID must not contain control characters, double quotes, or backslashes."; + } } mandatory true; description diff --git a/src/statd/python/yanger/__main__.py b/src/statd/python/yanger/__main__.py index 09b76adb..e156174c 100644 --- a/src/statd/python/yanger/__main__.py +++ b/src/statd/python/yanger/__main__.py @@ -97,7 +97,7 @@ def main(): common.LOG.warning("Unsupported model %s", args.model) sys.exit(1) - print(json.dumps(yang_data, indent=2)) + print(json.dumps(yang_data, indent=2, ensure_ascii=False)) if __name__ == "__main__": diff --git a/src/statd/python/yanger/ietf_interfaces/wifi.py b/src/statd/python/yanger/ietf_interfaces/wifi.py index d7342e33..ccf092d1 100644 --- a/src/statd/python/yanger/ietf_interfaces/wifi.py +++ b/src/statd/python/yanger/ietf_interfaces/wifi.py @@ -122,9 +122,15 @@ def parse_wpa_scan_result(scan_output): flags = parts[3].strip() ssid = parts[4].strip() if len(parts) > 4 else "" + try: + ssid = ssid.encode().decode('unicode_escape').encode('latin-1').decode('utf-8') + except (UnicodeDecodeError, UnicodeEncodeError): + pass + # Strip control chars (terminal injection risk from rogue APs) + ssid = ''.join(c for c in ssid if c.isprintable()) # Skip hidden SSIDs (empty or null-filled) - if not ssid or ssid.isspace() or '\\x00' in ssid: + if not ssid or ssid.isspace(): continue encryption = extract_encryption(flags)