From 7b9673470a916c4a57a2fe8aae0548cab1ff22c5 Mon Sep 17 00:00:00 2001 From: evaccaro <30807261+evaccaro@users.noreply.github.com> Date: Mon, 19 Oct 2026 13:56:35 -0400 Subject: [PATCH 1/3] Fix remaining buffer size in storage command formatting Pass the remaining command buffer capacity to snprintf after advancing the buffer pointer. This keeps storage command formatting compatible with stricter compiler checks. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 605c1c5d-4b41-4ee4-8db3-a38d2ab61a30 --- vendor/libmemcached-0.32/libmemcached/memcached_storage.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/vendor/libmemcached-0.32/libmemcached/memcached_storage.c b/vendor/libmemcached-0.32/libmemcached/memcached_storage.c index bf853f09..fac8ce42 100644 --- a/vendor/libmemcached-0.32/libmemcached/memcached_storage.c +++ b/vendor/libmemcached-0.32/libmemcached/memcached_storage.c @@ -123,9 +123,9 @@ static inline memcached_return memcached_send(memcached_st *ptr, if (verb == DELETE_OP) { if (ptr->flags & MEM_NOREPLY) - write_length+= (size_t) snprintf(buffer_ptr, MEMCACHED_DEFAULT_COMMAND_SIZE, "noreply"); + write_length+= (size_t) snprintf(buffer_ptr, MEMCACHED_DEFAULT_COMMAND_SIZE - write_length, "noreply"); } else { - write_length+= (size_t) snprintf(buffer_ptr, MEMCACHED_DEFAULT_COMMAND_SIZE, + write_length+= (size_t) snprintf(buffer_ptr, MEMCACHED_DEFAULT_COMMAND_SIZE - write_length, "%u %llu %zu%s\r\n", flags, (unsigned long long)expiration, value_length, @@ -511,4 +511,3 @@ static memcached_return memcached_send_binary(memcached_st *ptr, return memcached_response(server, NULL, 0, NULL); } - From 21bc7ed78aaa60dba8d4c77dba7dfc4d8521b98e Mon Sep 17 00:00:00 2001 From: evaccaro <30807261+evaccaro@users.noreply.github.com> Date: Mon, 19 Oct 2026 13:59:02 -0400 Subject: [PATCH 2/3] Restore original trailing blank line Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 605c1c5d-4b41-4ee4-8db3-a38d2ab61a30 --- vendor/libmemcached-0.32/libmemcached/memcached_storage.c | 1 + 1 file changed, 1 insertion(+) diff --git a/vendor/libmemcached-0.32/libmemcached/memcached_storage.c b/vendor/libmemcached-0.32/libmemcached/memcached_storage.c index fac8ce42..ff997d13 100644 --- a/vendor/libmemcached-0.32/libmemcached/memcached_storage.c +++ b/vendor/libmemcached-0.32/libmemcached/memcached_storage.c @@ -511,3 +511,4 @@ static memcached_return memcached_send_binary(memcached_st *ptr, return memcached_response(server, NULL, 0, NULL); } + From e0f945ffcd6cc406bfbccdf7f39d12f35704c7c4 Mon Sep 17 00:00:00 2001 From: evaccaro <30807261+evaccaro@users.noreply.github.com> Date: Mon, 19 Oct 2026 14:21:01 -0400 Subject: [PATCH 3/3] Check storage command capacity before copying key data Reject command, prefix, and key combinations that leave no room in the command buffer before copying them. Cover oversized inputs, the exact capacity boundary, and delete with noreply. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 605c1c5d-4b41-4ee4-8db3-a38d2ab61a30 --- test/unit/memcached_test.rb | 28 +++++++++++++++++++ .../libmemcached/memcached_storage.c | 3 ++ 2 files changed, 31 insertions(+) diff --git a/test/unit/memcached_test.rb b/test/unit/memcached_test.rb index ff3e366f..eea2f19b 100644 --- a/test/unit/memcached_test.rb +++ b/test/unit/memcached_test.rb @@ -998,6 +998,34 @@ def test_key_too_long end end + def test_storage_command_with_oversized_prefix_and_key + cache = Memcached.new @servers, @options.merge(:prefix_key => "p" * 127) + key = "k" * 250 + + assert_raises(Memcached::ABadKeyWasProvidedOrCharactersOutOfRange) do + cache.set key, @value + end + assert_raises(Memcached::ABadKeyWasProvidedOrCharactersOutOfRange) do + cache.prepend key, "value" + end + end + + def test_storage_command_with_prefix_and_key_filling_buffer + cache = Memcached.new @servers, @options.merge(:prefix_key => "p" * 127) + + assert_raises(Memcached::ABadKeyWasProvidedOrCharactersOutOfRange) do + cache.set "k" * 218, @value + end + end + + def test_noreply_delete_with_oversized_prefix_and_key + cache = Memcached.new @servers, @noblock_options.merge(:prefix_key => "p" * 127) + + assert_raises(Memcached::ABadKeyWasProvidedOrCharactersOutOfRange) do + cache.delete "k" * 250 + end + end + def test_verify_key_disabled cache = Memcached.new @servers, :verify_key => false key = "i have a space" diff --git a/vendor/libmemcached-0.32/libmemcached/memcached_storage.c b/vendor/libmemcached-0.32/libmemcached/memcached_storage.c index ff997d13..510ce74a 100644 --- a/vendor/libmemcached-0.32/libmemcached/memcached_storage.c +++ b/vendor/libmemcached-0.32/libmemcached/memcached_storage.c @@ -107,6 +107,9 @@ static inline memcached_return memcached_send(memcached_st *ptr, char *buffer_ptr= buffer; const char *command= storage_op_string(verb); + if (strlen(command) + strlen(ptr->prefix_key) + key_length + 1 >= MEMCACHED_DEFAULT_COMMAND_SIZE) + return MEMCACHED_BAD_KEY_PROVIDED; + /* Copy in the command, no space needed, we handle that in the command function*/ memcpy(buffer_ptr, command, strlen(command));