chore(packages): bump llama-cpp, llama-swap, and stable-diffusion-cpp

- llama-cpp: 9496 -> 9802
- llama-swap: 216 -> 230; UI embed moved upstream to internal/server/,
  skip forking tests that exec /bin/bash (unavailable in the sandbox)
- stable-diffusion-cpp: 462 -> 721; drop lora_enable.patch and
  server_mask.patch now merged upstream
This commit is contained in:
2026-06-29 15:16:52 -04:00
parent 35b5ccd4f0
commit 8800be4610
6 changed files with 21 additions and 254 deletions

View File

@@ -3,13 +3,13 @@ let
# Version MUST be an integer string. # Version MUST be an integer string.
# For tagged releases use the tag number (e.g. "9222"). # For tagged releases use the tag number (e.g. "9222").
# For HEAD builds use YYYYMMDD (e.g. "20260519"). # For HEAD builds use YYYYMMDD (e.g. "20260519").
version = "9496"; version = "9802";
src = pkgs.fetchFromGitHub { src = pkgs.fetchFromGitHub {
owner = "ggml-org"; owner = "ggml-org";
repo = "llama.cpp"; repo = "llama.cpp";
rev = "94a220cd6745e6e3f8de62870b66fd5b9bc92700"; rev = "beac5309f1bc67534f509bf29420abf58fff063c";
hash = "sha256-1jAowfGVzrrHDwWWzKESY7aV82whnuIg1N37fmtcgyw="; hash = "sha256-muVLC9PBzu6fRD5ddz5I4b1INRGsfgjkuqnMj4MUoqk=";
leaveDotGit = true; leaveDotGit = true;
postFetch = '' postFetch = ''
git -C "$out" rev-parse --short HEAD > $out/COMMIT git -C "$out" rev-parse --short HEAD > $out/COMMIT
@@ -30,7 +30,7 @@ in
# WebUI npm deps hash for our pinned src. Upstream nixpkgs builds the WebUI # WebUI npm deps hash for our pinned src. Upstream nixpkgs builds the WebUI
# from tools/ui via `npm run build` in preConfigure (offline, using these # from tools/ui via `npm run build` in preConfigure (offline, using these
# deps), so no custom webui derivation / HF-bucket workaround is needed. # deps), so no custom webui derivation / HF-bucket workaround is needed.
npmDepsHash = "sha256-1iM0LGeI9e+gZEHk46lkBe51DxIhiimfAm9o3Z3m9Ik="; npmDepsHash = "sha256-X1DZgmhS/zHTqDT5zq0kywwntthcJ9vRXeqyO3zz6UU=";
# Add SPIR-V Headers for Vulkan Backend # Add SPIR-V Headers for Vulkan Backend
# Newer llama.cpp requires spirv/unified1/spirv.hpp which isn't # Newer llama.cpp requires spirv/unified1/spirv.hpp which isn't

View File

@@ -13,13 +13,13 @@ let
in in
buildGo126Module (finalAttrs: { buildGo126Module (finalAttrs: {
pname = "llama-swap"; pname = "llama-swap";
version = "216"; version = "230";
src = fetchFromGitHub { src = fetchFromGitHub {
owner = "mostlygeek"; owner = "mostlygeek";
repo = "llama-swap"; repo = "llama-swap";
tag = "v${finalAttrs.version}"; tag = "v${finalAttrs.version}";
hash = "sha256-PHSY4z2h406xL+EcIYyrzr4s28txO7SCsWm8hrXf+2U="; hash = "sha256-IoA7YMxOtrAeyVBSRVjUx64lPxBLNEzu5J5HAl2vr98=";
# populate values that require us to use git. By doing this in postFetch we # 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. # can delete .git afterwards and maintain better reproducibility of the src.
leaveDotGit = true; leaveDotGit = true;
@@ -32,7 +32,7 @@ buildGo126Module (finalAttrs: {
''; '';
}; };
vendorHash = "sha256-QysQ7YdwJcLTziwL25j73n3tQVvzVQIFxN4GkTU8JZg="; vendorHash = "sha256-is8pm5g27in/LraLVJUzsa7EPqs+C3qzY8OQ/DXe98A=";
passthru.ui = callPackage ./ui.nix { llama-swap = finalAttrs.finalPackage; }; passthru.ui = callPackage ./ui.nix { llama-swap = finalAttrs.finalPackage; };
passthru.npmDepsHash = "sha256-NJqEJ+XTdpPFtJJxP4CGu+JDUW7lKDcFgsixQJ3SXtQ="; passthru.npmDepsHash = "sha256-NJqEJ+XTdpPFtJJxP4CGu+JDUW7lKDcFgsixQJ3SXtQ=";
@@ -55,8 +55,8 @@ buildGo126Module (finalAttrs: {
ldflags+=" -X main.commit=$(cat COMMIT)" ldflags+=" -X main.commit=$(cat COMMIT)"
ldflags+=" -X main.date=$(cat SOURCE_DATE_EPOCH)" ldflags+=" -X main.date=$(cat SOURCE_DATE_EPOCH)"
# copy for go:embed in proxy/ui_embed.go # copy for go:embed in internal/server/ui.go
cp -r ${finalAttrs.passthru.ui}/ui_dist proxy/ cp -r ${finalAttrs.passthru.ui}/ui_dist internal/server/
''; '';
excludedPackages = [ excludedPackages = [
@@ -73,7 +73,14 @@ buildGo126Module (finalAttrs: {
checkFlags = checkFlags =
let let
skippedTests = lib.optionals (stdenv.isDarwin && stdenv.isx86_64) [ # These tests write fixtures with a hardcoded `#!/bin/bash` shebang and exec
# them; the sandbox has no /bin/bash, so fork/exec fails with ENOENT.
forkingTests = [
"TestProcessCommand_StopForkingWrapper"
"TestProcessCommand_StopHonorsGracefulTimeout"
"TestProcessCommand_StopReapsForkedGrandchild"
];
skippedTests = forkingTests ++ lib.optionals (stdenv.isDarwin && stdenv.isx86_64) [
# Fail only on x86_64-darwin intermittently # Fail only on x86_64-darwin intermittently
# https://github.com/mostlygeek/llama-swap/issues/320 # https://github.com/mostlygeek/llama-swap/issues/320
"TestProcess_AutomaticallyStartsUpstream" "TestProcess_AutomaticallyStartsUpstream"

View File

@@ -9,7 +9,7 @@ buildNpmPackage (finalAttrs: {
postPatch = '' postPatch = ''
substituteInPlace vite.config.ts \ substituteInPlace vite.config.ts \
--replace-fail "../proxy/ui_dist" "${placeholder "out"}/ui_dist" --replace-fail "../internal/server/ui_dist" "${placeholder "out"}/ui_dist"
''; '';
sourceRoot = "${finalAttrs.src.name}/ui-svelte"; sourceRoot = "${finalAttrs.src.name}/ui-svelte";

View File

@@ -34,13 +34,13 @@ let
in in
effectiveStdenv.mkDerivation (finalAttrs: { effectiveStdenv.mkDerivation (finalAttrs: {
pname = "stable-diffusion-cpp"; pname = "stable-diffusion-cpp";
version = "master-462-c5602a6"; version = "master-721-8caa3f9";
src = fetchFromGitHub { src = fetchFromGitHub {
owner = "leejet"; owner = "leejet";
repo = "stable-diffusion.cpp"; repo = "stable-diffusion.cpp";
rev = "master-462-c5602a6"; rev = "master-721-8caa3f9";
hash = "sha256-6uW9k30QqvozJACw+Hv4nRj9PyTzQqY/M0/CWjqrV28="; hash = "sha256-voybvJQrG6/Puogf9vBr/3jzHBcl1MnIAsRQtswUw2U=";
fetchSubmodules = true; fetchSubmodules = true;
}; };
@@ -102,12 +102,6 @@ effectiveStdenv.mkDerivation (finalAttrs: {
(cmakeFeature "CMAKE_HIP_ARCHITECTURES" (builtins.concatStringsSep ";" rocmGpuTargets)) (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; { meta = with lib; {
description = "Stable Diffusion inference in pure C/C++"; description = "Stable Diffusion inference in pure C/C++";
homepage = "https://github.com/leejet/stable-diffusion.cpp"; homepage = "https://github.com/leejet/stable-diffusion.cpp";

View File

@@ -1,221 +0,0 @@
From 4aaca67479469faab232dc276afe12acdcd7f801 Mon Sep 17 00:00:00 2001
From: mateusgpe <mushgp@gmail.com>
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 <mushgp@gmail.com>
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;
}

View File

@@ -1,13 +0,0 @@
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<uint8_t> 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());
}