Skip to content

Commit 95ff26a

Browse files
committed
fix: Add input validation to model load (#404)
Validate input parameters used within python_backend model load
1 parent c94f397 commit 95ff26a

File tree

3 files changed

+326
-122
lines changed

3 files changed

+326
-122
lines changed

src/pb_utils.cc

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,21 @@
2626

2727
#include "pb_utils.h"
2828

29+
#include <sys/stat.h>
30+
31+
#include <fstream>
32+
2933
#ifdef _WIN32
3034
#include <windows.h>
3135

3236
#include <algorithm>
3337
#else
3438
#include <dlfcn.h>
39+
#include <unistd.h>
40+
#endif
41+
42+
#ifndef _WIN32
43+
extern char** environ;
3544
#endif
3645

3746

@@ -315,6 +324,30 @@ WrapTritonErrorInSharedPtr(TRITONSERVER_Error* error)
315324
}
316325
#endif // NOT TRITON_PB_STUB
317326

327+
bool
328+
IsValidIdentifier(const std::string& input)
329+
{
330+
// Check for invalid characters
331+
if (input.empty() ||
332+
input.find_first_of(INVALID_CHARS) != std::string::npos) {
333+
return false;
334+
}
335+
336+
return true;
337+
}
338+
339+
bool
340+
IsExecutableFile(const std::string& filepath)
341+
{
342+
struct stat file_stat;
343+
if (stat(filepath.c_str(), &file_stat) != 0) {
344+
return false;
345+
}
346+
347+
// Check if it's a regular file and executable by owner
348+
return S_ISREG(file_stat.st_mode) && (file_stat.st_mode & S_IXUSR);
349+
}
350+
318351
std::string
319352
GenerateUUID()
320353
{
@@ -323,4 +356,85 @@ GenerateUUID()
323356
return boost::uuids::to_string(uuid);
324357
}
325358

359+
// Helper function to get environment variables for Python virtual environments
360+
std::map<std::string, std::string>
361+
ParseActivationScript(const std::string& activate_path)
362+
{
363+
std::map<std::string, std::string> env_vars;
364+
365+
// Read the current environment as baseline
366+
#ifndef _WIN32
367+
if (environ != nullptr) {
368+
for (char** env = environ; *env != nullptr; env++) {
369+
std::string env_str(*env);
370+
size_t eq_pos = env_str.find('=');
371+
if (eq_pos != std::string::npos) {
372+
std::string key = env_str.substr(0, eq_pos);
373+
std::string value = env_str.substr(eq_pos + 1);
374+
env_vars[key] = value;
375+
}
376+
}
377+
}
378+
#endif
379+
380+
// Extract virtual environment root from activation script path
381+
std::string venv_path = activate_path;
382+
size_t bin_activate_pos = venv_path.find("/bin/activate");
383+
if (bin_activate_pos != std::string::npos) {
384+
venv_path = venv_path.substr(0, bin_activate_pos);
385+
}
386+
387+
// Set standard virtual environment variables
388+
env_vars["VIRTUAL_ENV"] = venv_path;
389+
env_vars["VIRTUAL_ENV_PROMPT"] = "(" + venv_path + ")";
390+
391+
// Update PATH to include the virtual environment's bin directory
392+
std::string new_path = venv_path + "/bin";
393+
if (env_vars.find("PATH") != env_vars.end()) {
394+
new_path += ":" + env_vars["PATH"];
395+
}
396+
env_vars["PATH"] = new_path;
397+
398+
// Update LD_LIBRARY_PATH to include the virtual environment's lib directory
399+
std::string new_lib_path = venv_path + "/lib";
400+
if (env_vars.find("LD_LIBRARY_PATH") != env_vars.end()) {
401+
new_lib_path += ":" + env_vars["LD_LIBRARY_PATH"];
402+
}
403+
env_vars["LD_LIBRARY_PATH"] = new_lib_path;
404+
405+
// Remove PYTHONHOME if it exists
406+
env_vars.erase("PYTHONHOME");
407+
408+
return env_vars;
409+
}
410+
411+
// Helper function to prepare environment array for execve
412+
std::pair<std::vector<std::string>, std::vector<char*>>
413+
PrepareEnvironment(
414+
const std::map<std::string, std::string>& env_vars,
415+
const std::string& additional_lib_path)
416+
{
417+
std::vector<std::string> env_strings;
418+
std::vector<char*> env_array;
419+
420+
for (const auto& [key, value] : env_vars) {
421+
std::string env_string;
422+
if (key == "LD_LIBRARY_PATH" && !additional_lib_path.empty()) {
423+
// Prepend the additional library path
424+
env_string = key + "=" + additional_lib_path + ":" + value;
425+
} else {
426+
env_string = key + "=" + value;
427+
}
428+
env_strings.push_back(env_string);
429+
}
430+
431+
// Convert to char* array
432+
for (auto& env_str : env_strings) {
433+
env_array.push_back(const_cast<char*>(env_str.c_str()));
434+
}
435+
env_array.push_back(nullptr);
436+
437+
return std::make_pair(std::move(env_strings), std::move(env_array));
438+
}
439+
326440
}}} // namespace triton::backend::python

src/pb_utils.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,12 @@
3636
#include <boost/uuid/uuid_generators.hpp>
3737
#include <boost/uuid/uuid_io.hpp>
3838
#include <climits>
39+
#include <map>
3940
#include <memory>
4041
#include <mutex>
4142
#include <string>
4243
#include <unordered_map>
44+
#include <utility>
4345
#include <vector>
4446

4547
#include "pb_exception.h"
@@ -341,11 +343,28 @@ bool IsUsingCUDAPool(
341343
// being retrieved from core that are not platform-agnostic.
342344
void SanitizePath(std::string& path);
343345

346+
// Invalid characters that are not allowed in user input
347+
constexpr const char* INVALID_CHARS = ";|&$`<>()[]{}\\\"'*?~#!";
348+
349+
// Validate that an identifier (model name, region name, etc.)
350+
bool IsValidIdentifier(const std::string& input);
351+
352+
// Check if a file exists and is executable
353+
bool IsExecutableFile(const std::string& filepath);
354+
344355
#ifndef TRITON_PB_STUB
345356
std::shared_ptr<TRITONSERVER_Error*> WrapTritonErrorInSharedPtr(
346357
TRITONSERVER_Error* error);
347358
#endif
348359

349360
std::string GenerateUUID();
350361

362+
// Environment handling utilities for Python activation scripts
363+
std::map<std::string, std::string> ParseActivationScript(
364+
const std::string& activate_path);
365+
366+
std::pair<std::vector<std::string>, std::vector<char*>> PrepareEnvironment(
367+
const std::map<std::string, std::string>& env_vars,
368+
const std::string& additional_lib_path = "");
369+
351370
}}} // namespace triton::backend::python

0 commit comments

Comments
 (0)