Skip to content

Commit 81be529

Browse files
add explicit trust_remote_code controls to resolve the security issue (#4511)
* add explicit trust_remote_code controls * add trust remote code in pipeline * fix * fix * fix * fix * fix ut * add trust-remote-code in cli * fix * fix * fix * fix * fix * fix * fix * fix * pr_ete_test --trust-remote-code * use ArgumentHelper.trust_remote_code(parser) in serve.py --------- Co-authored-by: zhulin1 <zhulinJulia24@163.com>
1 parent 8cd067a commit 81be529

78 files changed

Lines changed: 473 additions & 340 deletions

Some content is hidden

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

.github/workflows/pr_ete_test.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ jobs:
8989
exit 1
9090
- name: Test restful server - turbomind InternVL3-38B
9191
run: |
92-
CUDA_VISIBLE_DEVICES=6,7 lmdeploy serve api_server /nvme/qa_test_models/OpenGVLab/InternVL3-38B --tp 2 --backend turbomind --logprobs-mode raw_logprobs --allow-terminate-by-client > ${{env.SERVER_LOG}}/turbomind_InternVL3-38B_start_restful.log 2>&1 &
92+
CUDA_VISIBLE_DEVICES=6,7 lmdeploy serve api_server /nvme/qa_test_models/OpenGVLab/InternVL3-38B --tp 2 --backend turbomind --logprobs-mode raw_logprobs --allow-terminate-by-client --trust-remote-code > ${{env.SERVER_LOG}}/turbomind_InternVL3-38B_start_restful.log 2>&1 &
9393
echo "restful_pid=$!"
9494
for i in $(seq 1 180)
9595
do
@@ -169,7 +169,7 @@ jobs:
169169
exit 1
170170
- name: Test restful server - pytorch InternVL3_5-30B-A3B
171171
run: |
172-
CUDA_VISIBLE_DEVICES=6,7 lmdeploy serve api_server /nvme/qa_test_models/OpenGVLab/InternVL3_5-30B-A3B --tp 2 --backend pytorch --logprobs-mode raw_logprobs --allow-terminate-by-client > ${{env.SERVER_LOG}}/pytorch_InternVL3_5-30B-A3B_start_restful.log 2>&1 &
172+
CUDA_VISIBLE_DEVICES=6,7 lmdeploy serve api_server /nvme/qa_test_models/OpenGVLab/InternVL3_5-30B-A3B --tp 2 --backend pytorch --logprobs-mode raw_logprobs --allow-terminate-by-client --trust-remote-code > ${{env.SERVER_LOG}}/pytorch_InternVL3_5-30B-A3B_start_restful.log 2>&1 &
173173
echo "restful_pid=$!"
174174
for i in $(seq 1 180)
175175
do

autotest/tools/pipeline/llm_case.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ def run_pipeline_chat_test(model_path, run_config, cases_path, is_pr_test: bool
5454

5555
print('backend_config config: ' + str(backend_config))
5656
print('speculative_config config: ' + str(speculative_config))
57-
pipe = pipeline(model_path, backend_config=backend_config, speculative_config=speculative_config)
57+
pipe = pipeline(model_path, backend_config=backend_config, speculative_config=speculative_config,
58+
trust_remote_code=True)
5859

5960
cases_path = os.path.join(cases_path)
6061
with open(cases_path) as f:

autotest/tools/pipeline/mllm_case.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def run_pipeline_mllm_test(model_path, run_config, resource_path, is_pr_test: bo
6060
print(f"Warning: Cannot set attribute '{attr_name}' on backend_config. Skipping.")
6161

6262
print('backend_config config: ' + str(backend_config))
63-
pipe = pipeline(model_path, backend_config=backend_config)
63+
pipe = pipeline(model_path, backend_config=backend_config, trust_remote_code=True)
6464

6565
image = load_image(f'{resource_path}/{PIC1}')
6666

autotest/utils/config_utils.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ def get_cli_common_param(run_config: dict[str, Any]) -> str:
185185

186186
# Extra params
187187
cli_params.append(get_cli_str(extra_params))
188+
cli_params.append('--trust-remote-code')
188189

189190
return ' '.join(cli_params).strip()
190191

autotest/utils/quantization_utils.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ def quantization(config,
4545
else:
4646
quantization_cmd += ' --batch-size 32'
4747

48+
quantization_cmd += ' --trust-remote-code'
49+
4850
with open(quantization_log, 'w') as f:
4951
# remove existing folder
5052
subprocess.run([' '.join(['rm -rf', quantization_model_path])],

benchmark/profile_pipeline_api.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,12 +131,14 @@ def sample_random_requests(
131131

132132
class Engine:
133133

134-
def __init__(self, model_path: str, engine_config, csv: str, speculative_config: SpeculativeConfig | None = None):
134+
def __init__(self, model_path: str, engine_config, csv: str, speculative_config: SpeculativeConfig | None = None,
135+
trust_remote_code: bool = False):
135136
self.pipe = pipeline(model_path,
136137
backend_config=engine_config,
137138
log_level='ERROR',
138-
speculative_config=speculative_config)
139-
self.tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
139+
speculative_config=speculative_config,
140+
trust_remote_code=trust_remote_code)
141+
self.tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=trust_remote_code)
140142
self.return_routed_experts = getattr(self.pipe.backend_config, 'enable_return_routed_experts', False)
141143
self.csv = csv
142144

@@ -254,6 +256,7 @@ def parse_args():
254256
ArgumentHelper.top_k(parser)
255257
ArgumentHelper.log_level(parser)
256258
ArgumentHelper.backend(parser)
259+
ArgumentHelper.trust_remote_code(parser)
257260

258261
# pytorch engine args
259262
pt_group = parser.add_argument_group('PyTorch engine arguments')
@@ -319,7 +322,8 @@ def main():
319322
)
320323

321324
speculative_config = get_speculative_config(args)
322-
engine = Engine(args.model_path, engine_config, csv=args.csv, speculative_config=speculative_config)
325+
engine = Engine(args.model_path, engine_config, csv=args.csv, speculative_config=speculative_config,
326+
trust_remote_code=args.trust_remote_code)
323327

324328
profiler = Profiler(args.stream_output, [50, 75, 95, 99])
325329

benchmark/profile_restful_api.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -441,18 +441,20 @@ def get_model(pretrained_model_name_or_path: str) -> str:
441441
return pretrained_model_name_or_path
442442

443443

444-
def get_tokenizer(pretrained_model_name_or_path: str, ) -> PreTrainedTokenizer | PreTrainedTokenizerFast:
444+
def get_tokenizer(pretrained_model_name_or_path: str,
445+
trust_remote_code: bool = False) -> PreTrainedTokenizer | PreTrainedTokenizerFast:
445446
if pretrained_model_name_or_path.endswith('.json') or pretrained_model_name_or_path.endswith('.model'):
446447
from sglang.srt.hf_transformers_utils import get_tokenizer
447448

448449
return get_tokenizer(pretrained_model_name_or_path)
449450

450451
if pretrained_model_name_or_path is not None and not os.path.exists(pretrained_model_name_or_path):
451452
pretrained_model_name_or_path = get_model(pretrained_model_name_or_path)
452-
return AutoTokenizer.from_pretrained(pretrained_model_name_or_path, trust_remote_code=True)
453+
return AutoTokenizer.from_pretrained(pretrained_model_name_or_path, trust_remote_code=trust_remote_code)
453454

454455

455-
def get_processor(pretrained_model_name_or_path: str, ) -> PreTrainedTokenizer | PreTrainedTokenizerFast:
456+
def get_processor(pretrained_model_name_or_path: str,
457+
trust_remote_code: bool = False) -> PreTrainedTokenizer | PreTrainedTokenizerFast:
456458
assert (pretrained_model_name_or_path is not None and pretrained_model_name_or_path != '')
457459
if pretrained_model_name_or_path.endswith('.json') or pretrained_model_name_or_path.endswith('.model'):
458460
from sglang.srt.utils.hf_transformers_utils import get_processor
@@ -461,7 +463,7 @@ def get_processor(pretrained_model_name_or_path: str, ) -> PreTrainedTokenizer |
461463

462464
if pretrained_model_name_or_path is not None and not os.path.exists(pretrained_model_name_or_path):
463465
pretrained_model_name_or_path = get_model(pretrained_model_name_or_path)
464-
return AutoProcessor.from_pretrained(pretrained_model_name_or_path, trust_remote_code=True)
466+
return AutoProcessor.from_pretrained(pretrained_model_name_or_path, trust_remote_code=trust_remote_code)
465467

466468

467469
ASYNC_REQUEST_FUNCS = {
@@ -1172,9 +1174,9 @@ def parse_request_rate_range(request_rate_range):
11721174
return list(map(int, request_rate_range.split(',')))
11731175

11741176

1175-
def check_chat_template(model_path):
1177+
def check_chat_template(model_path, trust_remote_code: bool = False):
11761178
try:
1177-
tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
1179+
tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=args.trust_remote_code)
11781180
return 'chat_template' in tokenizer.init_kwargs
11791181
except Exception as e:
11801182
print(f'Fail to load tokenizer config with error={e}')
@@ -1256,15 +1258,15 @@ def run_benchmark(args_: argparse.Namespace):
12561258
'using `--model`.')
12571259
sys.exit(1)
12581260

1259-
if not check_chat_template(model_path):
1261+
if not check_chat_template(model_path, args.trust_remote_code):
12601262
print('\nWARNING It is recommended to use the `Chat` or `Instruct` '
12611263
'model for benchmarking.\n'
12621264
'Because when the tokenizer counts the output tokens, if '
12631265
'there is gibberish, it might count incorrectly.\n')
12641266

12651267
print(f'{args}\n')
12661268

1267-
tokenizer = get_tokenizer(tokenizer_id)
1269+
tokenizer = get_tokenizer(tokenizer_id, args.trust_remote_code)
12681270

12691271
if args.dataset_name == 'sharegpt':
12701272
assert args.random_input_len is None and args.random_output_len is None
@@ -1286,7 +1288,7 @@ def run_benchmark(args_: argparse.Namespace):
12861288
dataset_path=args.dataset_path,
12871289
)
12881290
elif args.dataset_name == 'image':
1289-
processor = get_processor(model_path)
1291+
processor = get_processor(model_path, args.trust_remote_code)
12901292
input_requests = sample_image_requests(
12911293
num_requests=args.num_prompts,
12921294
image_count=args.image_count,
@@ -1502,5 +1504,11 @@ def set_ulimit(target_soft_limit=65535):
15021504
default=None,
15031505
help='Disable a warmup request before the benchmark. ',
15041506
)
1507+
parser.add_argument(
1508+
'--trust-remote-code',
1509+
action='store_true',
1510+
default=False,
1511+
help='Trust remote code.',
1512+
)
15051513
args = parser.parse_args()
15061514
run_benchmark(args)

benchmark/profile_throughput.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,17 +135,20 @@ class Engine:
135135

136136
def __init__(self, model_path: str,
137137
engine_config: PytorchEngineConfig | TurbomindEngineConfig,
138-
speculative_config: SpeculativeConfig):
138+
speculative_config: SpeculativeConfig,
139+
trust_remote_code: bool = False):
139140
self.tokenizer = Tokenizer(model_path)
140141
if isinstance(engine_config, TurbomindEngineConfig):
141142
from lmdeploy.turbomind import TurboMind
142-
tm_model = TurboMind.from_pretrained(model_path, engine_config=engine_config)
143+
tm_model = TurboMind.from_pretrained(model_path, engine_config=engine_config,
144+
trust_remote_code=trust_remote_code)
143145
self.backend = 'turbomind'
144146
elif isinstance(engine_config, PytorchEngineConfig):
145147
from lmdeploy.pytorch.engine import Engine as PytorchEngine
146148
tm_model = PytorchEngine.from_pretrained(model_path,
147149
engine_config=engine_config,
148-
speculative_config=speculative_config)
150+
speculative_config=speculative_config,
151+
trust_remote_code=trust_remote_code)
149152
self.backend = 'pytorch'
150153

151154
self.tm_model = tm_model
@@ -295,6 +298,12 @@ def parse_args():
295298
help='Range of sampled ratio of input/output length, '
296299
'used only for random dataset.',
297300
)
301+
parser.add_argument(
302+
'--trust-remote-code',
303+
action='store_true',
304+
default=False,
305+
help='Trust remote code.',
306+
)
298307
# other args
299308
ArgumentHelper.top_p(parser)
300309
ArgumentHelper.temperature(parser)
@@ -382,7 +391,7 @@ def main():
382391
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
383392

384393
speculative_config = get_speculative_config(args)
385-
engine = Engine(args.model_path, engine_config, speculative_config)
394+
engine = Engine(args.model_path, engine_config, speculative_config, trust_remote_code=args.trust_remote_code)
386395

387396
if args.dataset_name == 'sharegpt':
388397
assert args.random_input_len is None and args.random_output_len is None

lmdeploy/api.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ def pipeline(model_path: str,
1717
chat_template_config: ChatTemplateConfig | None = None,
1818
log_level: str = 'WARNING',
1919
max_log_len: int | None = None,
20+
trust_remote_code: bool = False,
2021
speculative_config: SpeculativeConfig | None = None,
2122
**kwargs):
2223
"""Create a pipeline for inference.
@@ -41,6 +42,7 @@ def pipeline(model_path: str,
4142
``WARNING``, ``INFO``, ``DEBUG``]
4243
max_log_len: Max number of prompt characters or prompt tokens
4344
being printed in log.
45+
trust_remote_code: whether to trust remote code from model repositories.
4446
speculative_config: speculative decoding configuration.
4547
**kwargs: additional keyword arguments passed to the pipeline.
4648
@@ -73,6 +75,7 @@ def pipeline(model_path: str,
7375
chat_template_config=chat_template_config,
7476
log_level=log_level,
7577
max_log_len=max_log_len,
78+
trust_remote_code=trust_remote_code,
7679
speculative_config=speculative_config,
7780
**kwargs)
7881

lmdeploy/archs.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
logger = get_logger('lmdeploy')
1111

1212

13-
def autoget_backend(model_path: str) -> Literal['turbomind', 'pytorch']:
13+
def autoget_backend(model_path: str, trust_remote_code: bool = False):
1414
"""Get backend type in auto backend mode.
1515
1616
Args:
@@ -36,7 +36,7 @@ def autoget_backend(model_path: str) -> Literal['turbomind', 'pytorch']:
3636
is_turbomind_installed = True
3737
try:
3838
from lmdeploy.turbomind.supported_models import is_supported as is_supported_turbomind
39-
turbomind_has = is_supported_turbomind(model_path)
39+
turbomind_has = is_supported_turbomind(model_path, trust_remote_code=trust_remote_code)
4040
except ImportError:
4141
is_turbomind_installed = False
4242

@@ -57,7 +57,8 @@ def autoget_backend(model_path: str) -> Literal['turbomind', 'pytorch']:
5757

5858
def autoget_backend_config(
5959
model_path: str,
60-
backend_config: PytorchEngineConfig | TurbomindEngineConfig | None = None
60+
backend_config: PytorchEngineConfig | TurbomindEngineConfig | None = None,
61+
trust_remote_code: bool = False
6162
) -> tuple[Literal['turbomind', 'pytorch'], PytorchEngineConfig | TurbomindEngineConfig]:
6263
"""Get backend config automatically.
6364
@@ -75,7 +76,7 @@ def autoget_backend_config(
7576
if isinstance(backend_config, PytorchEngineConfig):
7677
return 'pytorch', backend_config
7778

78-
backend = autoget_backend(model_path)
79+
backend = autoget_backend(model_path, trust_remote_code=trust_remote_code)
7980
config = PytorchEngineConfig() if backend == 'pytorch' else TurbomindEngineConfig()
8081
if backend_config is not None:
8182
if type(backend_config) is type(config):
@@ -128,14 +129,14 @@ def check_vl_llm(backend: str, config: dict) -> bool:
128129
return False
129130

130131

131-
def get_task(backend: str, model_path: str):
132+
def get_task(backend: str, model_path: str, trust_remote_code: bool = False):
132133
"""Get pipeline type and pipeline class from model config."""
133134
from lmdeploy.serve.core import AsyncEngine
134135

135136
if os.path.exists(os.path.join(model_path, 'triton_models', 'weights')):
136137
# workspace model
137138
return 'llm', AsyncEngine
138-
_, config = get_model_arch(model_path)
139+
_, config = get_model_arch(model_path, trust_remote_code=trust_remote_code)
139140
if check_vl_llm(backend, config.to_dict()):
140141
from lmdeploy.serve.core import VLAsyncEngine
141142
return 'vlm', VLAsyncEngine
@@ -144,17 +145,17 @@ def get_task(backend: str, model_path: str):
144145
return 'llm', AsyncEngine
145146

146147

147-
def get_model_arch(model_path: str):
148+
def get_model_arch(model_path: str, trust_remote_code: bool = False):
148149
"""Get a model's architecture and configuration.
149150
150151
Args:
151152
model_path(str): the model path
152153
"""
153154
try:
154-
cfg = AutoConfig.from_pretrained(model_path, trust_remote_code=True)
155+
cfg = AutoConfig.from_pretrained(model_path, trust_remote_code=trust_remote_code)
155156
except Exception as e: # noqa
156157
from transformers import PretrainedConfig
157-
cfg = PretrainedConfig.from_pretrained(model_path, trust_remote_code=True)
158+
cfg = PretrainedConfig.from_pretrained(model_path, trust_remote_code=trust_remote_code)
158159

159160
_cfg = cfg.to_dict()
160161
if _cfg.get('architectures', None):

0 commit comments

Comments
 (0)