From 483e82adc89c984cbe040857d9cf43fc725883cd Mon Sep 17 00:00:00 2001 From: dormando Date: Wed, 26 Aug 2009 02:36:14 -0700 Subject: [PATCH] Fix memory corruption issue with bad item lengths Partially fixed in 1.2.8, unfixed somewhere since, now fully fixed. Negative values allowed memory corruption, and high values also allowed corruption in swallow mode. Length is now guaranteed to be positive. Fixes issue 70. --- memcached.c | 15 ++++++++++----- t/issue_70.t | 22 ++++++++++++++++++++++ 2 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 t/issue_70.t diff --git a/memcached.c b/memcached.c index 59b42849fe..c074aa602e 100644 --- a/memcached.c +++ b/memcached.c @@ -2493,27 +2493,32 @@ static void process_update_command(conn *c, token_t *tokens, const size_t ntoken // does cas value exist? if (handle_cas) { - if (!safe_strtoull(tokens[5].value, &req_cas_id) - || vlen < 0 ) { + if (!safe_strtoull(tokens[5].value, &req_cas_id)) { out_string(c, "CLIENT_ERROR bad command line format"); return; } } + vlen += 2; + if (vlen < 0 || vlen - 2 < 0) { + out_string(c, "CLIENT_ERROR bad command line format"); + return; + } + if (settings.detail_enabled) { stats_prefix_record_set(key, nkey); } - it = item_alloc(key, nkey, flags, realtime(exptime), vlen+2); + it = item_alloc(key, nkey, flags, realtime(exptime), vlen); if (it == 0) { - if (! item_size_ok(nkey, flags, vlen + 2)) + if (! item_size_ok(nkey, flags, vlen)) out_string(c, "SERVER_ERROR object too large for cache"); else out_string(c, "SERVER_ERROR out of memory storing object"); /* swallow the data line */ c->write_and_go = conn_swallow; - c->sbytes = vlen + 2; + c->sbytes = vlen; /* Avoid stale data persisting in cache because we failed alloc. * Unacceptable for SET. Anywhere else too? */ diff --git a/t/issue_70.t b/t/issue_70.t new file mode 100644 index 0000000000..95e39db11c --- /dev/null +++ b/t/issue_70.t @@ -0,0 +1,22 @@ +#!/usr/bin/perl + +use strict; +use Test::More tests => 4; +use FindBin qw($Bin); +use lib "$Bin/lib"; +use MemcachedTest; + +my $server = new_memcached(); +my $sock = $server->sock; + +print $sock "set issue70 0 0 0\r\n\r\n"; +is (scalar <$sock>, "STORED\r\n", "stored issue70"); + +print $sock "set issue70 0 0 -1\r\n"; +is (scalar <$sock>, "CLIENT_ERROR bad command line format\r\n"); + +print $sock "set issue70 0 0 4294967295\r\n"; +is (scalar <$sock>, "CLIENT_ERROR bad command line format\r\n"); + +print $sock "set issue70 0 0 2147483647\r\nscoobyscoobydoo"; +is (scalar <$sock>, "CLIENT_ERROR bad command line format\r\n");