From 6a234d69b491b45f269a4f74800392aba62904ab Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Thu, 9 Apr 2026 08:56:20 +0000 Subject: [PATCH] fix: address critical security vulnerabilities - Remove hardcoded DeepSeek API key from e2e_test.js, use env var LLM_API_KEY - Fix SQL injection in elf_analyzer.ts via parameterized query (db.prepare/bind) - Fix SQL injection in fault_tree_analyzer.py via parameterized queries - Fix SQL injection in perf_analyzer.py via table name validation with regex - Replace shell=True in exe_utils.py with shlex.split + shell=False - Replace os.system() calls with subprocess.run() in perf_action.py, capture_ui.py, and perf_testcase.py - Add missing imports (subprocess, re, shlex) where needed Co-Authored-By: SunBo <10715606@qq.com> --- perf_testing/hapray/actions/perf_action.py | 5 ++- .../hapray/analyze/fault_tree_analyzer.py | 42 +++++++++++++++---- .../hapray/core/collection/capture_ui.py | 7 ++-- perf_testing/hapray/core/common/exe_utils.py | 6 ++- perf_testing/hapray/core/perf_testcase.py | 5 ++- scripts/e2e_test.js | 14 +++++-- .../src/core/elf/elf_analyzer.ts | 15 +++---- .../core/analyzers/perf_analyzer.py | 7 +++- 8 files changed, 72 insertions(+), 29 deletions(-) diff --git a/perf_testing/hapray/actions/perf_action.py b/perf_testing/hapray/actions/perf_action.py index f744be32..ca89a0c3 100644 --- a/perf_testing/hapray/actions/perf_action.py +++ b/perf_testing/hapray/actions/perf_action.py @@ -19,6 +19,7 @@ import queue import re import shutil +import subprocess import threading import time from concurrent.futures import ThreadPoolExecutor, as_completed @@ -347,13 +348,13 @@ def execute(args) -> ActionExecuteReturn: so_dir = Config.get('so_dir', None) if so_dir is not None: # hiperf report will use so_dir path to find symbols. - os.system(f'hdc file send {so_dir} /data/local/tmp/so_dir') + subprocess.run(['hdc', 'file', 'send', so_dir, '/data/local/tmp/so_dir'], check=False) action = PerfAction(reports_path, parsed_args.round, devices=parsed_args.devices) action.run() if so_dir is not None: - os.system('hdc shell rm -rf /data/local/tmp/so_dir') + subprocess.run(['hdc', 'shell', 'rm', '-rf', '/data/local/tmp/so_dir'], check=False) if parsed_args.hapflow: try: diff --git a/perf_testing/hapray/analyze/fault_tree_analyzer.py b/perf_testing/hapray/analyze/fault_tree_analyzer.py index 55648221..5093b766 100644 --- a/perf_testing/hapray/analyze/fault_tree_analyzer.py +++ b/perf_testing/hapray/analyze/fault_tree_analyzer.py @@ -110,28 +110,52 @@ def _analyze_impl( return result def _collect_app_invoke_times(self, cursor, name_match: str, app_pids: list) -> int: - return self._collect_invoke_times(cursor, name_match, f'pid in ({",".join(map(str, app_pids))})') + try: + # Validate that app_pids are integers to prevent injection + safe_pids = [int(pid) for pid in app_pids] + placeholders = ','.join('?' * len(safe_pids)) + cursor.execute( + f""" + SELECT count(*) FROM callstack + WHERE + name LIKE ? + and callid in ( + SELECT id FROM thread + where + ipid in ( + SELECT ipid + FROM process + where pid in ({placeholders}) + ) + ) + """, + [name_match] + safe_pids, + ) + rows = cursor.fetchall() + return rows[0][0] + except sqlite3.Error as e: + self.logger.error('FaultTreeAnalyzer invoke Database error: %s', str(e)) + return 0 def _collect_rs_invoke_times(self, cursor, name_match: str) -> int: - return self._collect_invoke_times(cursor, name_match, "name = 'render_service'") - - def _collect_invoke_times(self, cursor, name_match: str, process_match: str) -> int: try: - cursor.execute(f""" + cursor.execute( + """ SELECT count(*) FROM callstack WHERE - name LIKE '{name_match}' + name LIKE ? and callid in ( SELECT id FROM thread where ipid in ( SELECT ipid FROM process - where {process_match} + where name = 'render_service' ) ) - """) - + """, + [name_match], + ) rows = cursor.fetchall() return rows[0][0] except sqlite3.Error as e: diff --git a/perf_testing/hapray/core/collection/capture_ui.py b/perf_testing/hapray/core/collection/capture_ui.py index 2680a9f1..372f99c2 100644 --- a/perf_testing/hapray/core/collection/capture_ui.py +++ b/perf_testing/hapray/core/collection/capture_ui.py @@ -15,6 +15,7 @@ import os import re +import subprocess import zipfile from hypium import UiDriver @@ -134,9 +135,9 @@ def _capture_screenshot(self, ui_step_dir: str, label_name: str = None) -> str: self.driver.pull_file(remote_screenshot_path, local_screenshot_path) else: # 使用hdc命令直接传输 - recv_cmd = f'hdc file recv {remote_screenshot_path} {local_screenshot_path}' - Log.info(f'执行文件传输命令: {recv_cmd}') - os.system(recv_cmd) + recv_cmd = ['hdc', 'file', 'recv', remote_screenshot_path, local_screenshot_path] + Log.info(f'执行文件传输命令: {" ".join(recv_cmd)}') + subprocess.run(recv_cmd, check=False) # 验证文件是否成功保存 if os.path.exists(local_screenshot_path): diff --git a/perf_testing/hapray/core/common/exe_utils.py b/perf_testing/hapray/core/common/exe_utils.py index 0b7d658c..49a36316 100644 --- a/perf_testing/hapray/core/common/exe_utils.py +++ b/perf_testing/hapray/core/common/exe_utils.py @@ -17,6 +17,7 @@ import logging import os import platform +import shlex import shutil import sqlite3 import subprocess @@ -354,7 +355,10 @@ def build_hapray_cmd(args: list[str]) -> list[str]: def execute_command_check_output(cmd, timeout=120000): ret = 'error' try: - ret = subprocess.check_output(cmd, timeout=timeout, stderr=subprocess.STDOUT, shell=True) + # Use shell=False with a command list for safety; split string commands with shlex + if isinstance(cmd, str): + cmd = shlex.split(cmd) + ret = subprocess.check_output(cmd, timeout=timeout, stderr=subprocess.STDOUT) return ret.decode('gbk', 'ignore').encode('utf-8') except subprocess.CalledProcessError as e: logger.error('cmd->%s excute error output=%s', cmd, e.output) diff --git a/perf_testing/hapray/core/perf_testcase.py b/perf_testing/hapray/core/perf_testcase.py index 84e70611..3acfc51f 100644 --- a/perf_testing/hapray/core/perf_testcase.py +++ b/perf_testing/hapray/core/perf_testcase.py @@ -16,6 +16,7 @@ import json import os import re +import subprocess import time from abc import ABC, abstractmethod @@ -217,14 +218,14 @@ def update_current_page_ext_info(self, ext_info: dict): def set_device_redundant_mode(self): # 设置hdc参数 Log.info('设置hdc参数: persist.ark.properties 0x200105c') - os.system('hdc shell param set persist.ark.properties 0x200105c') + subprocess.run(['hdc', 'shell', 'param', 'set', 'persist.ark.properties', '0x200105c'], check=False) self._redundant_mode_status = True def reboot_device(self): regex = re.compile(r'\d+') # 重启手机 Log.info('重启手机') - os.system('hdc shell reboot') + subprocess.run(['hdc', 'shell', 'reboot'], check=False) # 检测手机是否重启成功 Log.info('检测手机重启状态') diff --git a/scripts/e2e_test.js b/scripts/e2e_test.js index 8529f11c..2ea7eb51 100644 --- a/scripts/e2e_test.js +++ b/scripts/e2e_test.js @@ -845,9 +845,15 @@ async function runE2ETests() { // 配置 LLM 环境变量用于符号恢复模块测试 console.log('🤖 配置 LLM 环境变量...'); - process.env.LLM_API_KEY = 'sk-14ccee5142d04e7fbbcda3418b715390'; - process.env.LLM_BASE_URL = 'https://api.deepseek.com/v1'; - process.env.LLM_MODEL = 'deepseek-chat'; + if (!process.env.LLM_API_KEY) { + console.warn('⚠ LLM_API_KEY 未设置,请通过环境变量提供(例如: export LLM_API_KEY=your-key)'); + } + if (!process.env.LLM_BASE_URL) { + process.env.LLM_BASE_URL = 'https://api.deepseek.com/v1'; + } + if (!process.env.LLM_MODEL) { + process.env.LLM_MODEL = 'deepseek-chat'; + } console.log('✓ LLM 环境变量配置完成:'); console.log(` - 模型名称: ${process.env.LLM_MODEL}`); @@ -959,4 +965,4 @@ if (require.main === module) { runE2ETests(); } -module.exports = { runE2ETests, checkDirectoryExists, checkFileExists, runCommand, testModule }; \ No newline at end of file +module.exports = { runE2ETests, checkDirectoryExists, checkFileExists, runCommand, testModule }; diff --git a/tools/static_analyzer/src/core/elf/elf_analyzer.ts b/tools/static_analyzer/src/core/elf/elf_analyzer.ts index 7bcb34f8..e9e02f2a 100644 --- a/tools/static_analyzer/src/core/elf/elf_analyzer.ts +++ b/tools/static_analyzer/src/core/elf/elf_analyzer.ts @@ -225,14 +225,15 @@ export class ElfAnalyzer { let SQL = await initSqlJs(); for (const dbFile of perfFiles) { const db = new SQL.Database(fs.readFileSync(dbFile)); - const results = db.exec(`SELECT symbol FROM perf_files where path like '%${path.basename(filePath)}%'`); - if (results.length === 0) { - continue; + const stmt = db.prepare('SELECT symbol FROM perf_files WHERE path LIKE ?'); + stmt.bind([`%${path.basename(filePath)}%`]); + while (stmt.step()) { + const row = stmt.get(); + if (row[0]) { + invokeSymbols.add(row[0] as string); + } } - - results[0].values.map((row) => { - invokeSymbols.add(row[0] as string); - }); + stmt.free(); } logger.info(`${filePath} parse symbols from perf ${Array.from(invokeSymbols.values()).join('\n')}`); diff --git a/tools/symbol_recovery/core/analyzers/perf_analyzer.py b/tools/symbol_recovery/core/analyzers/perf_analyzer.py index 562404ed..ec40acbf 100644 --- a/tools/symbol_recovery/core/analyzers/perf_analyzer.py +++ b/tools/symbol_recovery/core/analyzers/perf_analyzer.py @@ -5,6 +5,7 @@ """ import platform +import re import shutil import sqlite3 import subprocess @@ -203,7 +204,11 @@ def verify_sqlite_db(self, db_path): logger.info(f'数据库包含 {len(tables)} 个表:') for table in tables: table_name = table[0] - cursor.execute(f'SELECT COUNT(*) FROM {table_name};') + # Validate table name to prevent SQL injection (allow only alphanumeric and underscores) + if not re.match(r'^[A-Za-z_][A-Za-z0-9_]*$', table_name): + logger.warning(f' - {table_name}: 跳过(表名包含非法字符)') + continue + cursor.execute(f'SELECT COUNT(*) FROM [{table_name}];') count = cursor.fetchone()[0] logger.info(f' - {table_name}: {count} 行')