memcached/CVE-2019-11596.patch
2020-02-19 15:07:50 +08:00

371 lines
14 KiB
Diff

diff -Nurp memcached-1.5.10/assoc.c memcached-1.5.10-old/assoc.c
--- memcached-1.5.10/assoc.c 2018-07-18 16:39:52.000000000 -0400
+++ memcached-1.5.10-old/assoc.c 2019-05-31 04:34:02.477000000 -0400
@@ -28,7 +28,7 @@
static pthread_cond_t maintenance_cond = PTHREAD_COND_INITIALIZER;
static pthread_mutex_t maintenance_lock = PTHREAD_MUTEX_INITIALIZER;
-typedef unsigned long int ub4; /* unsigned 4-byte quantities */
+typedef uint32_t ub4; /* unsigned 4-byte quantities */
typedef unsigned char ub1; /* unsigned 1-byte quantities */
/* how many powers of 2's worth of buckets we use */
diff -Nurp memcached-1.5.10/cache.h memcached-1.5.10-old/cache.h
--- memcached-1.5.10/cache.h 2018-07-18 16:39:52.000000000 -0400
+++ memcached-1.5.10-old/cache.h 2019-05-31 04:34:36.887000000 -0400
@@ -34,8 +34,7 @@ typedef int cache_constructor_t(void* ob
* returned to the operating system.
*
* @param obj pointer to the object to clean up.
- * @param notused1 This parameter is currently not used.
- * @param notused2 This parameter is currently not used.
+ * @param notused This parameter is currently not used.
* @return you should return 0, but currently this is not checked
*/
typedef void cache_destructor_t(void* obj, void* notused);
diff -Nurp memcached-1.5.10/configure.ac memcached-1.5.10-old/configure.ac
--- memcached-1.5.10/configure.ac 2018-07-18 16:39:52.000000000 -0400
+++ memcached-1.5.10-old/configure.ac 2019-05-31 04:35:28.038000000 -0400
@@ -629,9 +629,18 @@ AC_CHECK_FUNCS(pledge, [
], [])
],[])
+AC_CHECK_FUNCS(cap_enter, [
+ AC_CHECK_HEADER(sys/capsicum.h, [
+ AC_DEFINE([HAVE_DROP_PRIVILEGES], 1,
+ [Define this if you have an implementation of drop_privileges()])
+ build_freebsd_privs=yes
+ ], [])
+],[])
+
AM_CONDITIONAL([BUILD_SOLARIS_PRIVS],[test "$build_solaris_privs" = "yes"])
AM_CONDITIONAL([BUILD_LINUX_PRIVS],[test "$build_linux_privs" = "yes"])
AM_CONDITIONAL([BUILD_OPENBSD_PRIVS],[test "$build_openbsd_privs" = "yes"])
+AM_CONDITIONAL([BUILD_FREEBSD_PRIVS],[test "$build_freebsd_privs" = "yes"])
AC_CHECK_HEADER(umem.h, [
AC_DEFINE([HAVE_UMEM_H], 1,
diff -Nurp memcached-1.5.10/doc/protocol.txt memcached-1.5.10-old/doc/protocol.txt
--- memcached-1.5.10/doc/protocol.txt 2018-07-18 16:39:52.000000000 -0400
+++ memcached-1.5.10-old/doc/protocol.txt 2019-05-31 04:35:50.981000000 -0400
@@ -633,7 +633,7 @@ memcache developers.
General-purpose statistics
--------------------------
-Upon receiving the "stats" command without arguments, the server sents
+Upon receiving the "stats" command without arguments, the server sends
a number of lines which look like this:
STAT <name> <value>\r\n
diff -Nurp memcached-1.5.10/extstore.c memcached-1.5.10-old/extstore.c
--- memcached-1.5.10/extstore.c 2018-08-10 16:36:38.000000000 -0400
+++ memcached-1.5.10-old/extstore.c 2019-05-31 04:37:14.321000000 -0400
@@ -183,6 +183,9 @@ const char *extstore_err(enum extstore_r
case EXTSTORE_INIT_PAGE_WBUF_ALIGNMENT:
rv = "page_size and wbuf_size must be divisible by 1024*1024*2";
break;
+ case EXTSTORE_INIT_TOO_MANY_PAGES:
+ rv = "page_count must total to < 65536. Increase page_size or lower path sizes";
+ break;
case EXTSTORE_INIT_OOM:
rv = "failed calloc for engine";
break;
@@ -230,6 +233,7 @@ void *extstore_init(struct extstore_conf
}
e->page_size = cf->page_size;
+ uint64_t temp_page_count = 0;
for (f = fh; f != NULL; f = f->next) {
f->fd = open(f->file, O_RDWR | O_CREAT | O_TRUNC, 0644);
if (f->fd < 0) {
@@ -240,10 +244,17 @@ void *extstore_init(struct extstore_conf
free(e);
return NULL;
}
- e->page_count += f->page_count;
+ temp_page_count += f->page_count;
f->offset = 0;
}
+ if (temp_page_count >= UINT16_MAX) {
+ *res = EXTSTORE_INIT_TOO_MANY_PAGES;
+ free(e);
+ return NULL;
+ }
+ e->page_count = temp_page_count;
+
e->pages = calloc(e->page_count, sizeof(store_page));
if (e->pages == NULL) {
*res = EXTSTORE_INIT_OOM;
diff -Nurp memcached-1.5.10/extstore.h memcached-1.5.10-old/extstore.h
--- memcached-1.5.10/extstore.h 2018-08-10 16:36:38.000000000 -0400
+++ memcached-1.5.10-old/extstore.h 2019-05-31 04:37:35.803000000 -0400
@@ -93,6 +93,7 @@ enum extstore_res {
EXTSTORE_INIT_NEED_MORE_WBUF,
EXTSTORE_INIT_NEED_MORE_BUCKETS,
EXTSTORE_INIT_PAGE_WBUF_ALIGNMENT,
+ EXTSTORE_INIT_TOO_MANY_PAGES,
EXTSTORE_INIT_OOM,
EXTSTORE_INIT_OPEN_FAIL,
EXTSTORE_INIT_THREAD_FAIL
diff -Nurp memcached-1.5.10/freebsd_priv.c memcached-1.5.10-old/freebsd_priv.c
--- memcached-1.5.10/freebsd_priv.c 1969-12-31 19:00:00.000000000 -0500
+++ memcached-1.5.10-old/freebsd_priv.c 2019-05-31 04:37:52.842000000 -0400
@@ -0,0 +1,18 @@
+#include <sys/capsicum.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "memcached.h"
+
+/*
+ * * dropping privileges is entering in capability mode
+ * * in FreeBSD vocabulary.
+ * */
+void drop_privileges() {
+ if (cap_enter() != 0) {
+ fprintf(stderr, "cap_enter failed: %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+}
diff -Nurp memcached-1.5.10/logger.c memcached-1.5.10-old/logger.c
--- memcached-1.5.10/logger.c 2018-08-10 16:36:38.000000000 -0400
+++ memcached-1.5.10-old/logger.c 2019-05-31 04:38:14.125000000 -0400
@@ -6,6 +6,7 @@
#include <errno.h>
#include <poll.h>
#include <ctype.h>
+#include <stdarg.h>
#if defined(__sun)
#include <atomic.h>
diff -Nurp memcached-1.5.10/Makefile.am memcached-1.5.10-old/Makefile.am
--- memcached-1.5.10/Makefile.am 2018-07-18 16:39:52.000000000 -0400
+++ memcached-1.5.10-old/Makefile.am 2019-05-31 04:33:27.162000000 -0400
@@ -42,6 +42,10 @@ if BUILD_OPENBSD_PRIVS
memcached_SOURCES += openbsd_priv.c
endif
+if BUILD_FREEBSD_PRIVS
+memcached_SOURCES += freebsd_priv.c
+endif
+
if ENABLE_SASL
memcached_SOURCES += sasl_defs.c
endif
diff -Nurp memcached-1.5.10/memcached.c memcached-1.5.10-old/memcached.c
--- memcached-1.5.10/memcached.c 2018-08-10 16:36:38.000000000 -0400
+++ memcached-1.5.10-old/memcached.c 2019-05-31 04:48:48.677000000 -0400
@@ -55,6 +55,10 @@
#include <getopt.h>
#endif
+#if defined(__FreeBSD__)
+#include <sys/sysctl.h>
+#endif
+
/* FreeBSD 4.x doesn't have IOV_MAX exposed. */
#ifndef IOV_MAX
#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__GNU__)
@@ -2599,6 +2603,7 @@ static void process_bin_flush(conn *c) {
static void process_bin_delete(conn *c) {
item *it;
+ uint32_t hv;
protocol_binary_request_delete* req = binary_get_request(c);
@@ -2620,7 +2625,7 @@ static void process_bin_delete(conn *c)
stats_prefix_record_delete(key, nkey);
}
- it = item_get(key, nkey, c, DONT_UPDATE);
+ it = item_get_locked(key, nkey, c, DONT_UPDATE, &hv);
if (it) {
uint64_t cas = ntohll(req->message.header.request.cas);
if (cas == 0 || cas == ITEM_get_cas(it)) {
@@ -2628,19 +2633,20 @@ static void process_bin_delete(conn *c)
pthread_mutex_lock(&c->thread->stats.mutex);
c->thread->stats.slab_stats[ITEM_clsid(it)].delete_hits++;
pthread_mutex_unlock(&c->thread->stats.mutex);
- item_unlink(it);
+ do_item_unlink(it, hv);
STORAGE_delete(c->thread->storage, it);
write_bin_response(c, NULL, 0, 0, 0);
} else {
write_bin_error(c, PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, NULL, 0);
}
- item_remove(it); /* release our reference */
+ do_item_remove(it); /* release our reference */
} else {
write_bin_error(c, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, NULL, 0);
pthread_mutex_lock(&c->thread->stats.mutex);
c->thread->stats.delete_misses++;
pthread_mutex_unlock(&c->thread->stats.mutex);
}
+ item_unlock(hv);
}
static void complete_nread_binary(conn *c) {
@@ -4323,6 +4329,7 @@ static void process_delete_command(conn
char *key;
size_t nkey;
item *it;
+ uint32_t hv;
assert(c != NULL);
@@ -4351,7 +4358,7 @@ static void process_delete_command(conn
stats_prefix_record_delete(key, nkey);
}
- it = item_get(key, nkey, c, DONT_UPDATE);
+ it = item_get_locked(key, nkey, c, DONT_UPDATE, &hv);
if (it) {
MEMCACHED_COMMAND_DELETE(c->sfd, ITEM_key(it), it->nkey);
@@ -4359,9 +4366,9 @@ static void process_delete_command(conn
c->thread->stats.slab_stats[ITEM_clsid(it)].delete_hits++;
pthread_mutex_unlock(&c->thread->stats.mutex);
- item_unlink(it);
+ do_item_unlink(it, hv);
STORAGE_delete(c->thread->storage, it);
- item_remove(it); /* release our reference */
+ do_item_remove(it); /* release our reference */
out_string(c, "DELETED");
} else {
pthread_mutex_lock(&c->thread->stats.mutex);
@@ -4370,6 +4377,7 @@ static void process_delete_command(conn
out_string(c, "NOT_FOUND");
}
+ item_unlock(hv);
}
static void process_verbosity_command(conn *c, token_t *tokens, const size_t ntokens) {
@@ -4536,7 +4544,7 @@ static void process_lru_command(conn *c,
out_string(c, "OK");
}
}
- } else if (strcmp(tokens[1].value, "mode") == 0 && ntokens >= 3 &&
+ } else if (strcmp(tokens[1].value, "mode") == 0 && ntokens >= 4 &&
settings.lru_maintainer_thread) {
if (strcmp(tokens[2].value, "flat") == 0) {
settings.lru_segmented = false;
@@ -4547,7 +4555,7 @@ static void process_lru_command(conn *c,
} else {
out_string(c, "ERROR");
}
- } else if (strcmp(tokens[1].value, "temp_ttl") == 0 && ntokens >= 3 &&
+ } else if (strcmp(tokens[1].value, "temp_ttl") == 0 && ntokens >= 4 &&
settings.lru_maintainer_thread) {
if (!safe_strtol(tokens[2].value, &ttl)) {
out_string(c, "ERROR");
@@ -6233,7 +6241,7 @@ static void usage(void) {
printf("-b, --listen-backlog=<num> set the backlog queue limit (default: 1024)\n");
printf("-B, --protocol=<name> protocol - one of ascii, binary, or auto (default)\n");
printf("-I, --max-item-size=<num> adjusts max item size\n"
- " (default: 1mb, min: 1k, max: 128m)\n");
+ " (default: 1mb, min: 1k, max: 1024m)\n");
#ifdef ENABLE_SASL
printf("-S, --enable-sasl turn on Sasl authentication\n");
#endif
@@ -6491,6 +6499,21 @@ static int enable_large_pages(void) {
return -1;
}
return 0;
+#elif defined(__FreeBSD__)
+ int spages;
+ size_t spagesl = sizeof(spages);
+
+ if (sysctlbyname("vm.pmap.pg_ps_enabled", &spages,
+ &spagesl, NULL, 0) != 0) {
+ fprintf(stderr, "Could not evaluate the presence of superpages features.");
+ return -1;
+ }
+ if (spages != 1) {
+ fprintf(stderr, "Superpages support not detected.\n");
+ fprintf(stderr, "Will use default page size.\n");
+ return -1;
+ }
+ return 0;
#else
return -1;
#endif
@@ -6951,7 +6974,7 @@ int main (int argc, char **argv) {
preallocate = true;
} else {
fprintf(stderr, "Cannot enable large pages on this system\n"
- "(There is no Linux support as of this version)\n");
+ "(There is no support as of this version)\n");
return 1;
}
break;
@@ -7247,6 +7270,10 @@ int main (int argc, char **argv) {
break;
#ifdef EXTSTORE
case EXT_PAGE_SIZE:
+ if (storage_file) {
+ fprintf(stderr, "Must specify ext_page_size before any ext_path arguments\n");
+ return 1;
+ }
if (subopts_value == NULL) {
fprintf(stderr, "Missing ext_page_size argument\n");
return 1;
diff -Nurp memcached-1.5.10/memcached.h memcached-1.5.10-old/memcached.h
--- memcached-1.5.10/memcached.h 2018-08-10 16:36:38.000000000 -0400
+++ memcached-1.5.10-old/memcached.h 2019-05-31 04:49:17.529000000 -0400
@@ -756,6 +756,7 @@ item *item_alloc(char *key, size_t nkey,
#define DO_UPDATE true
#define DONT_UPDATE false
item *item_get(const char *key, const size_t nkey, conn *c, const bool do_update);
+item *item_get_locked(const char *key, const size_t nkey, conn *c, const bool do_update, uint32_t *hv);
item *item_touch(const char *key, const size_t nkey, uint32_t exptime, conn *c);
int item_link(item *it);
void item_remove(item *it);
diff -Nurp memcached-1.5.10/scripts/memcached-tool memcached-1.5.10-old/scripts/memcached-tool
--- memcached-1.5.10/scripts/memcached-tool 2018-07-18 16:39:52.000000000 -0400
+++ memcached-1.5.10-old/scripts/memcached-tool 2019-05-31 05:40:26.276000000 -0400
@@ -98,13 +98,13 @@ if ($mode eq 'dump') {
# return format looks like this
# key=foo exp=2147483647 la=1521046038 cas=717111 fetch=no cls=13 size=1232
if (/^key=(\S+) exp=(-?\d+) .*/) {
- my $k = $1;
+ my ($k, $exp) = ($1, $2);
$k =~ s/%(.{2})/chr hex $1/eg;
- if ($2 == -1) {
+ if ($exp == -1) {
$keyexp{$k} = 0;
} else {
- $keyexp{$k} = $2;
+ $keyexp{$k} = $exp;
}
}
$keycount++;
diff -Nurp memcached-1.5.10/thread.c memcached-1.5.10-old/thread.c
--- memcached-1.5.10/thread.c 2018-08-10 16:36:38.000000000 -0400
+++ memcached-1.5.10-old/thread.c 2019-05-31 05:42:46.727000000 -0400
@@ -566,6 +566,17 @@ item *item_get(const char *key, const si
return it;
}
+// returns an item with the item lock held.
+// lock will still be held even if return is NULL, allowing caller to replace
+// an item atomically if desired.
+item *item_get_locked(const char *key, const size_t nkey, conn *c, const bool do_update, uint32_t *hv) {
+ item *it;
+ *hv = hash(key, nkey);
+ item_lock(*hv);
+ it = do_item_get(key, nkey, *hv, c, do_update);
+ return it;
+}
+
item *item_touch(const char *key, size_t nkey, uint32_t exptime, conn *c) {
item *it;
uint32_t hv;