From 0b01da43b86c4519227374863af321cff81e5fe9 Mon Sep 17 00:00:00 2001 From: Evan Reichard Date: Wed, 7 Jan 2026 12:04:18 -0500 Subject: [PATCH] chore: update packages --- packages/llama-swap/default.nix | 4 +- packages/opencode/default.nix | 8 +- packages/stable-diffusion-cpp/default.nix | 12 +- .../stable-diffusion-cpp/lora_enable.patch | 221 ++++++++++++++++++ .../stable-diffusion-cpp/server_mask.patch | 13 ++ 5 files changed, 249 insertions(+), 9 deletions(-) create mode 100644 packages/stable-diffusion-cpp/lora_enable.patch create mode 100644 packages/stable-diffusion-cpp/server_mask.patch diff --git a/packages/llama-swap/default.nix b/packages/llama-swap/default.nix index c2e39f0..57d5c99 100644 --- a/packages/llama-swap/default.nix +++ b/packages/llama-swap/default.nix @@ -13,13 +13,13 @@ let in buildGoModule (finalAttrs: { pname = "llama-swap"; - version = "180"; + version = "182"; src = fetchFromGitHub { owner = "mostlygeek"; repo = "llama-swap"; tag = "v${finalAttrs.version}"; - hash = "sha256-WPDmENGH1uwNrobcIPA2vuNEsb9sP7Wl7T0wtUv1H/s="; + hash = "sha256-w/VQS8uCpgniwLiJsH/8IG/AGasRxjCv7fADTfpvWLw="; # populate values that require us to use git. By doing this in postFetch we # can delete .git afterwards and maintain better reproducibility of the src. leaveDotGit = true; diff --git a/packages/opencode/default.nix b/packages/opencode/default.nix index 7751371..6eff620 100644 --- a/packages/opencode/default.nix +++ b/packages/opencode/default.nix @@ -13,12 +13,12 @@ }: let pname = "opencode"; - version = "1.0.223"; + version = "1.1.4"; src = fetchFromGitHub { - owner = "sst"; + owner = "anomalyco"; repo = "opencode"; tag = "v${version}"; - hash = "sha256-CzbWv48UySgXfNgtWdIdFBcqx8GHT4rSJNDdpn39b0c="; # "sha256-Y0thIZ20p0FSBAH0mJfFn8e+OEUvlZyTuk+/yEt8Sy8="; + hash = "sha256-i9IO9FSZ2Mw0tPqFxfQfSbejx04J1eJ0IYy5fa77O2Y="; }; node_modules = stdenvNoCC.mkDerivation { @@ -75,7 +75,7 @@ let # NOTE: Required else we get errors that our fixed-output derivation references store paths dontFixup = true; - outputHash = "sha256-+HEd3I11VqejTi7cikbTL5+DmNGyvUC4Cm4ysfujwes="; + outputHash = "sha256-tea/pSuUOELsSSMdwi0mmG5GsFZpqR5MlyQvVUno7dM="; outputHashAlgo = "sha256"; outputHashMode = "recursive"; }; diff --git a/packages/stable-diffusion-cpp/default.nix b/packages/stable-diffusion-cpp/default.nix index 70f8253..b1b056a 100644 --- a/packages/stable-diffusion-cpp/default.nix +++ b/packages/stable-diffusion-cpp/default.nix @@ -34,13 +34,13 @@ let in effectiveStdenv.mkDerivation (finalAttrs: { pname = "stable-diffusion-cpp"; - version = "master-453-4ff2c8c"; + version = "master-462-c5602a6"; src = fetchFromGitHub { owner = "leejet"; repo = "stable-diffusion.cpp"; - rev = "master-453-4ff2c8c"; - hash = "sha256-8cN6dYOQAKnJpuQdtayp6+o71s64lG+FcTn8GsIM4jI="; + rev = "master-462-c5602a6"; + hash = "sha256-6uW9k30QqvozJACw+Hv4nRj9PyTzQqY/M0/CWjqrV28="; fetchSubmodules = true; }; @@ -102,6 +102,12 @@ effectiveStdenv.mkDerivation (finalAttrs: { (cmakeFeature "CMAKE_HIP_ARCHITECTURES" (builtins.concatStringsSep ";" rocmGpuTargets)) ]; + patchFlags = [ "-p1" ]; + patches = [ + ./lora_enable.patch # https://github.com/leejet/stable-diffusion.cpp/pull/1156 + ./server_mask.patch # https://github.com/leejet/stable-diffusion.cpp/pull/1178 + ]; + meta = with lib; { description = "Stable Diffusion inference in pure C/C++"; homepage = "https://github.com/leejet/stable-diffusion.cpp"; diff --git a/packages/stable-diffusion-cpp/lora_enable.patch b/packages/stable-diffusion-cpp/lora_enable.patch new file mode 100644 index 0000000..0318f44 --- /dev/null +++ b/packages/stable-diffusion-cpp/lora_enable.patch @@ -0,0 +1,221 @@ +From 4aaca67479469faab232dc276afe12acdcd7f801 Mon Sep 17 00:00:00 2001 +From: mateusgpe +Date: Wed, 31 Dec 2025 18:42:23 -0300 +Subject: [PATCH 1/2] fix(server): sanitize LoRA paths and enable dynamic + loading + +- Implement `sanitize_lora_path` in `SDGenerationParams` to prevent directory traversal attacks via LoRA tags in prompts. +- Restrict LoRA paths to be relative and strictly within the configured LoRA directory (no subdirectories allowed, optional? drawback: users cannot organize their LoRAs into subfolders.). +- Update server example to pass `lora_model_dir` to `process_and_check`, enabling LoRA extraction from prompts. +- Force `LORA_APPLY_AT_RUNTIME` in the server to allow applying LoRAs dynamically per request without reloading the model. +--- + examples/common/common.hpp | 67 +++++++++++++++++++++++++++++++++++--- + examples/server/main.cpp | 5 +-- + 2 files changed, 65 insertions(+), 7 deletions(-) + +diff --git a/examples/common/common.hpp b/examples/common/common.hpp +index 7ea95ed14..7f869868c 100644 +--- a/examples/common/common.hpp ++++ b/examples/common/common.hpp +@@ -1601,6 +1601,63 @@ struct SDGenerationParams { + return true; + } + ++ static bool sanitize_lora_path(const std::string& lora_model_dir, ++ const std::string& raw_path_str, ++ fs::path& full_path) { ++ if (lora_model_dir.empty()) { ++ return false; ++ } ++ ++ fs::path raw_path(raw_path_str); ++ ++ // Disallow absolute paths. ++ if (raw_path.is_absolute()) { ++ LOG_WARN("lora path must be relative: %s", raw_path_str.c_str()); ++ return false; ++ } ++ ++ // Disallow '..' in the raw path to prevent basic traversal attempts. ++ for (const auto& part : raw_path) { ++ if (part == "..") { ++ LOG_WARN("lora path cannot contain '..': %s", raw_path_str.c_str()); ++ return false; ++ } ++ } ++ ++ fs::path lora_dir(lora_model_dir); ++ full_path = lora_dir / raw_path; ++ ++ // --- Security Checks on Canonical Path --- ++ // Canonicalize paths to resolve symlinks and normalize separators for robust checks. ++ // weakly_canonical is used because the target file might not exist yet. ++ auto canonical_lora_dir = fs::weakly_canonical(lora_dir); ++ auto canonical_full_path = fs::weakly_canonical(full_path); ++ ++ // 1. The resolved path must not be a directory. ++ if (fs::is_directory(canonical_full_path)) { ++ LOG_WARN("lora path resolved to a directory, not a file: %s", raw_path_str.c_str()); ++ return false; ++ } ++ ++ // 2. The file must be inside the designated lora directory. ++ // We check this by ensuring the relative path does not climb up with '..'. ++ fs::path relative_path = canonical_full_path.lexically_relative(canonical_lora_dir); ++ for (const auto& part : relative_path) { ++ if (part == "..") { ++ LOG_WARN("lora path is outside of the lora model directory: %s", raw_path_str.c_str()); ++ return false; ++ } ++ } ++ ++ // 3. The file must be directly in the lora directory, not in a subdirectory. ++ if (relative_path.has_parent_path() && !relative_path.parent_path().empty()) { ++ LOG_WARN("lora path in subdirectories is not allowed: %s", raw_path_str.c_str()); ++ return false; ++ } ++ ++ return true; ++ } ++ + void extract_and_remove_lora(const std::string& lora_model_dir) { + if (lora_model_dir.empty()) { + return; +@@ -1632,10 +1689,10 @@ struct SDGenerationParams { + } + + fs::path final_path; +- if (is_absolute_path(raw_path)) { +- final_path = raw_path; +- } else { +- final_path = fs::path(lora_model_dir) / raw_path; ++ if (!sanitize_lora_path(lora_model_dir, raw_path, final_path)) { ++ tmp = m.suffix().str(); ++ prompt = std::regex_replace(prompt, re, "", std::regex_constants::format_first_only); ++ continue; + } + if (!fs::exists(final_path)) { + bool found = false; +@@ -1643,7 +1700,7 @@ struct SDGenerationParams { + fs::path try_path = final_path; + try_path += ext; + if (fs::exists(try_path)) { +- final_path = try_path; ++ final_path = try_path.lexically_normal(); + found = true; + break; + } +diff --git a/examples/server/main.cpp b/examples/server/main.cpp +index c540958f8..69c75d322 100644 +--- a/examples/server/main.cpp ++++ b/examples/server/main.cpp +@@ -293,6 +293,7 @@ int main(int argc, const char** argv) { + LOG_DEBUG("%s", default_gen_params.to_string().c_str()); + + sd_ctx_params_t sd_ctx_params = ctx_params.to_sd_ctx_params_t(false, false, false); ++ ctx_params.lora_apply_mode = LORA_APPLY_AT_RUNTIME; + sd_ctx_t* sd_ctx = new_sd_ctx(&sd_ctx_params); + + if (sd_ctx == nullptr) { +@@ -414,7 +415,7 @@ int main(int argc, const char** argv) { + return; + } + +- if (!gen_params.process_and_check(IMG_GEN, "")) { ++ if (!gen_params.process_and_check(IMG_GEN, ctx_params.lora_model_dir)) { + res.status = 400; + res.set_content(R"({"error":"invalid params"})", "application/json"); + return; +@@ -592,7 +593,7 @@ int main(int argc, const char** argv) { + return; + } + +- if (!gen_params.process_and_check(IMG_GEN, "")) { ++ if (!gen_params.process_and_check(IMG_GEN, ctx_params.lora_model_dir)) { + res.status = 400; + res.set_content(R"({"error":"invalid params"})", "application/json"); + return; + +From 4b80b61003aa06f41c6bdec47ff926e37007b87d Mon Sep 17 00:00:00 2001 +From: mateusgpe +Date: Thu, 1 Jan 2026 15:24:01 -0300 +Subject: [PATCH 2/2] fix: sanitize LoRA paths and enable dynamic loading + +- Remove the restriction that LoRA models must be in the root of the LoRA directory, allowing them to be organized in subfolders. +- Refactor the directory containment check to use `std::mismatch` instead of `lexically_relative` to verify the path is inside the allowed root. +- Remove redundant `lexically_normal()` call when resolving file extensions. +--- + examples/common/common.hpp | 29 ++++++++++------------------- + 1 file changed, 10 insertions(+), 19 deletions(-) + +diff --git a/examples/common/common.hpp b/examples/common/common.hpp +index 7f869868c..a2e919409 100644 +--- a/examples/common/common.hpp ++++ b/examples/common/common.hpp +@@ -1610,13 +1610,12 @@ struct SDGenerationParams { + + fs::path raw_path(raw_path_str); + +- // Disallow absolute paths. ++ // Disallow absolute paths and '..' components + if (raw_path.is_absolute()) { + LOG_WARN("lora path must be relative: %s", raw_path_str.c_str()); + return false; + } + +- // Disallow '..' in the raw path to prevent basic traversal attempts. + for (const auto& part : raw_path) { + if (part == "..") { + LOG_WARN("lora path cannot contain '..': %s", raw_path_str.c_str()); +@@ -1624,34 +1623,26 @@ struct SDGenerationParams { + } + } + ++ // Construct and canonicalize paths + fs::path lora_dir(lora_model_dir); + full_path = lora_dir / raw_path; + +- // --- Security Checks on Canonical Path --- +- // Canonicalize paths to resolve symlinks and normalize separators for robust checks. +- // weakly_canonical is used because the target file might not exist yet. + auto canonical_lora_dir = fs::weakly_canonical(lora_dir); + auto canonical_full_path = fs::weakly_canonical(full_path); + +- // 1. The resolved path must not be a directory. ++ // Check if path is a directory + if (fs::is_directory(canonical_full_path)) { + LOG_WARN("lora path resolved to a directory, not a file: %s", raw_path_str.c_str()); + return false; + } + +- // 2. The file must be inside the designated lora directory. +- // We check this by ensuring the relative path does not climb up with '..'. +- fs::path relative_path = canonical_full_path.lexically_relative(canonical_lora_dir); +- for (const auto& part : relative_path) { +- if (part == "..") { +- LOG_WARN("lora path is outside of the lora model directory: %s", raw_path_str.c_str()); +- return false; +- } +- } ++ // Verify path stays within lora directory ++ auto [root_end, nothing] = std::mismatch( ++ canonical_lora_dir.begin(), canonical_lora_dir.end(), ++ canonical_full_path.begin(), canonical_full_path.end()); + +- // 3. The file must be directly in the lora directory, not in a subdirectory. +- if (relative_path.has_parent_path() && !relative_path.parent_path().empty()) { +- LOG_WARN("lora path in subdirectories is not allowed: %s", raw_path_str.c_str()); ++ if (root_end != canonical_lora_dir.end()) { ++ LOG_WARN("lora path is outside of the lora model directory: %s", raw_path_str.c_str()); + return false; + } + +@@ -1700,7 +1691,7 @@ struct SDGenerationParams { + fs::path try_path = final_path; + try_path += ext; + if (fs::exists(try_path)) { +- final_path = try_path.lexically_normal(); ++ final_path = try_path; + found = true; + break; + } diff --git a/packages/stable-diffusion-cpp/server_mask.patch b/packages/stable-diffusion-cpp/server_mask.patch new file mode 100644 index 0000000..e9702a0 --- /dev/null +++ b/packages/stable-diffusion-cpp/server_mask.patch @@ -0,0 +1,13 @@ +diff --git i/examples/server/main.cpp w/examples/server/main.cpp +index 9fa8804..b15daca 100644 +--- i/examples/server/main.cpp ++++ w/examples/server/main.cpp +@@ -537,7 +537,7 @@ int main(int argc, const char** argv) { + } + + std::vector mask_bytes; +- if (req.form.has_field("mask")) { ++ if (req.form.has_file("mask")) { + auto file = req.form.get_file("mask"); + mask_bytes.assign(file.content.begin(), file.content.end()); + }