Activity log for bug #1626565

Date Who What changed Old value New value Message
2016-09-22 13:35:13 Denis bug added bug
2016-09-22 13:35:13 Denis attachment added Patch that fixes bug in memcached_servers_reset https://bugs.launchpad.net/bugs/1626565/+attachment/4746251/+files/libmemcached-ketama-servers_reset.patch
2016-09-22 14:29:28 Denis description When used with MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED at memcached_servers_reset ketama.continuum is freed, NULL-ed, but ketama.continuum_count is not zeroed. It leads to segfault when memcached_server_add() is accessing ketama.continuum_count[0]. The following code is a proof: #include <libmemcached/memcached.h> #include <stdio.h> int main() { const char *config_string= "--SERVER=localhost"; const char *key= "foo"; const char *value= "bar"; memcached_return_t err; size_t retlen; char *retvalue; memcached_st *memc= memcached(config_string, strlen(config_string)); err= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, true); if (err != MEMCACHED_SUCCESS) { printf("behavior set failed, %s\n", memcached_strerror(memc, err)); exit(1); } err= memcached_server_add(memc, "localhost", 11211); if (err != MEMCACHED_SUCCESS) { printf("server add failed, %s\n", memcached_strerror(memc, err)); exit(1); } err= memcached_set(memc, key, strlen(key), value, strlen(value), 0, 0); if (err != MEMCACHED_SUCCESS) { printf("set failed, %s\n", memcached_strerror(memc, err)); exit(1); } retvalue= memcached_get(memc, key, strlen(key), &retlen, 0, &err); if (retvalue) { printf("%s\n", retvalue); } else { printf("get failed, %s\n", memcached_strerror(memc, err)); } memcached_servers_reset(memc); err= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, true); if (err != MEMCACHED_SUCCESS) { printf("behavior set 2 failed, %s\n", memcached_strerror(memc, err)); exit(1); } err= memcached_server_add(memc, "localhost", 11211); if (err != MEMCACHED_SUCCESS) { printf("server add 2 failed, %s\n", memcached_strerror(memc, err)); exit(1); } err= memcached_set(memc, key, strlen(key), value, strlen(value), 0, 0); if (err != MEMCACHED_SUCCESS) { printf("set 2 failed, %s\n", memcached_strerror(memc, err)); exit(1); } retvalue= memcached_get(memc, key, strlen(key), &retlen, 0, &err); if (retvalue) { printf("%s\n", retvalue); } else { printf("get 2 failed, %s\n", memcached_strerror(memc, err)); } memcached_free(memc); } Actual behavior: $ gcc memcached_bug.c -o memcached_bug -lmemcached -ggdb $ ./memcached_bug bar Segmentation fault (core dumped) Expected behavior: $ gcc memcached_bug.c -o memcached_bug -lmemcached -ggdb $ ./memcached_bug bar bar gdb output: Program received signal SIGSEGV, Segmentation fault. 0x00007ffff7bbef3d in update_continuum (ptr=0x614c20) at libmemcached/hosts.cc:316 316 ptr->ketama.continuum[continuum_index].index= host_index; (gdb) bt #0 0x00007ffff7bbef3d in update_continuum (ptr=0x614c20) at libmemcached/hosts.cc:316 #1 0x00007ffff7bbf8f6 in memcached_server_add_with_weight (shell=0x614c20, hostname=<optimized out>, port=<optimized out>, weight=0) at libmemcached/hosts.cc:585 #2 0x0000000000400c56 in main () (gdb) list 311 if (memcached_is_weighted_ketama(ptr)) 312 { 313 for (uint32_t x = 0; x < pointer_per_hash; x++) 314 { 315 uint32_t value= ketama_server_hash(sort_host, (size_t)sort_host_length, x); 316 ptr->ketama.continuum[continuum_index].index= host_index; 317 ptr->ketama.continuum[continuum_index++].value= value; 318 } 319 } 320 else (gdb) print ptr->ketama.continuum $1 = (memcached_continuum_item_st *) 0x0 (gdb) print ptr->ketama.continuum_count $2 = 11 (gdb) quit Attached is a patch to fix that. When used with MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED at memcached_servers_reset ketama.continuum is freed, NULL-ed, but ketama.continuum_count is not zeroed. It leads to segfault when memcached_server_add() is accessing ketama.continuum[0]. The following code is a proof: #include <libmemcached/memcached.h> #include <stdio.h> int main() {         const char *config_string= "--SERVER=localhost";         const char *key= "foo";         const char *value= "bar";         memcached_return_t err;         size_t retlen;         char *retvalue;         memcached_st *memc= memcached(config_string, strlen(config_string));         err= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, true);         if (err != MEMCACHED_SUCCESS) {                 printf("behavior set failed, %s\n", memcached_strerror(memc, err));                 exit(1);         }         err= memcached_server_add(memc, "localhost", 11211);         if (err != MEMCACHED_SUCCESS) {                 printf("server add failed, %s\n", memcached_strerror(memc, err));                 exit(1);         }         err= memcached_set(memc, key, strlen(key), value, strlen(value), 0, 0);         if (err != MEMCACHED_SUCCESS) {                 printf("set failed, %s\n", memcached_strerror(memc, err));                 exit(1);         }         retvalue= memcached_get(memc, key, strlen(key), &retlen, 0, &err);         if (retvalue) {                 printf("%s\n", retvalue);         } else {                 printf("get failed, %s\n", memcached_strerror(memc, err));         }         memcached_servers_reset(memc);         err= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, true);         if (err != MEMCACHED_SUCCESS) {                 printf("behavior set 2 failed, %s\n", memcached_strerror(memc, err));                 exit(1);         }         err= memcached_server_add(memc, "localhost", 11211);         if (err != MEMCACHED_SUCCESS) {                 printf("server add 2 failed, %s\n", memcached_strerror(memc, err));                 exit(1);         }         err= memcached_set(memc, key, strlen(key), value, strlen(value), 0, 0);         if (err != MEMCACHED_SUCCESS) {                 printf("set 2 failed, %s\n", memcached_strerror(memc, err));                 exit(1);         }         retvalue= memcached_get(memc, key, strlen(key), &retlen, 0, &err);         if (retvalue) {                 printf("%s\n", retvalue);         } else {                 printf("get 2 failed, %s\n", memcached_strerror(memc, err));         }         memcached_free(memc); } Actual behavior: $ gcc memcached_bug.c -o memcached_bug -lmemcached -ggdb $ ./memcached_bug bar Segmentation fault (core dumped) Expected behavior: $ gcc memcached_bug.c -o memcached_bug -lmemcached -ggdb $ ./memcached_bug bar bar gdb output: Program received signal SIGSEGV, Segmentation fault. 0x00007ffff7bbef3d in update_continuum (ptr=0x614c20) at libmemcached/hosts.cc:316 316 ptr->ketama.continuum[continuum_index].index= host_index; (gdb) bt #0 0x00007ffff7bbef3d in update_continuum (ptr=0x614c20) at libmemcached/hosts.cc:316 #1 0x00007ffff7bbf8f6 in memcached_server_add_with_weight (shell=0x614c20, hostname=<optimized out>, port=<optimized out>, weight=0) at libmemcached/hosts.cc:585 #2 0x0000000000400c56 in main () (gdb) list 311 if (memcached_is_weighted_ketama(ptr)) 312 { 313 for (uint32_t x = 0; x < pointer_per_hash; x++) 314 { 315 uint32_t value= ketama_server_hash(sort_host, (size_t)sort_host_length, x); 316 ptr->ketama.continuum[continuum_index].index= host_index; 317 ptr->ketama.continuum[continuum_index++].value= value; 318 } 319 } 320 else (gdb) print ptr->ketama.continuum $1 = (memcached_continuum_item_st *) 0x0 (gdb) print ptr->ketama.continuum_count $2 = 11 (gdb) quit Attached is a patch to fix that.
2016-09-22 15:29:01 Denis description When used with MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED at memcached_servers_reset ketama.continuum is freed, NULL-ed, but ketama.continuum_count is not zeroed. It leads to segfault when memcached_server_add() is accessing ketama.continuum[0]. The following code is a proof: #include <libmemcached/memcached.h> #include <stdio.h> int main() {         const char *config_string= "--SERVER=localhost";         const char *key= "foo";         const char *value= "bar";         memcached_return_t err;         size_t retlen;         char *retvalue;         memcached_st *memc= memcached(config_string, strlen(config_string));         err= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, true);         if (err != MEMCACHED_SUCCESS) {                 printf("behavior set failed, %s\n", memcached_strerror(memc, err));                 exit(1);         }         err= memcached_server_add(memc, "localhost", 11211);         if (err != MEMCACHED_SUCCESS) {                 printf("server add failed, %s\n", memcached_strerror(memc, err));                 exit(1);         }         err= memcached_set(memc, key, strlen(key), value, strlen(value), 0, 0);         if (err != MEMCACHED_SUCCESS) {                 printf("set failed, %s\n", memcached_strerror(memc, err));                 exit(1);         }         retvalue= memcached_get(memc, key, strlen(key), &retlen, 0, &err);         if (retvalue) {                 printf("%s\n", retvalue);         } else {                 printf("get failed, %s\n", memcached_strerror(memc, err));         }         memcached_servers_reset(memc);         err= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, true);         if (err != MEMCACHED_SUCCESS) {                 printf("behavior set 2 failed, %s\n", memcached_strerror(memc, err));                 exit(1);         }         err= memcached_server_add(memc, "localhost", 11211);         if (err != MEMCACHED_SUCCESS) {                 printf("server add 2 failed, %s\n", memcached_strerror(memc, err));                 exit(1);         }         err= memcached_set(memc, key, strlen(key), value, strlen(value), 0, 0);         if (err != MEMCACHED_SUCCESS) {                 printf("set 2 failed, %s\n", memcached_strerror(memc, err));                 exit(1);         }         retvalue= memcached_get(memc, key, strlen(key), &retlen, 0, &err);         if (retvalue) {                 printf("%s\n", retvalue);         } else {                 printf("get 2 failed, %s\n", memcached_strerror(memc, err));         }         memcached_free(memc); } Actual behavior: $ gcc memcached_bug.c -o memcached_bug -lmemcached -ggdb $ ./memcached_bug bar Segmentation fault (core dumped) Expected behavior: $ gcc memcached_bug.c -o memcached_bug -lmemcached -ggdb $ ./memcached_bug bar bar gdb output: Program received signal SIGSEGV, Segmentation fault. 0x00007ffff7bbef3d in update_continuum (ptr=0x614c20) at libmemcached/hosts.cc:316 316 ptr->ketama.continuum[continuum_index].index= host_index; (gdb) bt #0 0x00007ffff7bbef3d in update_continuum (ptr=0x614c20) at libmemcached/hosts.cc:316 #1 0x00007ffff7bbf8f6 in memcached_server_add_with_weight (shell=0x614c20, hostname=<optimized out>, port=<optimized out>, weight=0) at libmemcached/hosts.cc:585 #2 0x0000000000400c56 in main () (gdb) list 311 if (memcached_is_weighted_ketama(ptr)) 312 { 313 for (uint32_t x = 0; x < pointer_per_hash; x++) 314 { 315 uint32_t value= ketama_server_hash(sort_host, (size_t)sort_host_length, x); 316 ptr->ketama.continuum[continuum_index].index= host_index; 317 ptr->ketama.continuum[continuum_index++].value= value; 318 } 319 } 320 else (gdb) print ptr->ketama.continuum $1 = (memcached_continuum_item_st *) 0x0 (gdb) print ptr->ketama.continuum_count $2 = 11 (gdb) quit Attached is a patch to fix that. libmemcached 1.0.18 When used with MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED at memcached_servers_reset ketama.continuum is freed, NULL-ed, but ketama.continuum_count is not zeroed. It leads to segfault when memcached_server_add() is accessing ketama.continuum[0]. The following code is a proof: #include <libmemcached/memcached.h> #include <stdio.h> int main() {         const char *config_string= "--SERVER=localhost";         const char *key= "foo";         const char *value= "bar";         memcached_return_t err;         size_t retlen;         char *retvalue;         memcached_st *memc= memcached(config_string, strlen(config_string));         err= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, true);         if (err != MEMCACHED_SUCCESS) {                 printf("behavior set failed, %s\n", memcached_strerror(memc, err));                 exit(1);         }         err= memcached_server_add(memc, "localhost", 11211);         if (err != MEMCACHED_SUCCESS) {                 printf("server add failed, %s\n", memcached_strerror(memc, err));                 exit(1);         }         err= memcached_set(memc, key, strlen(key), value, strlen(value), 0, 0);         if (err != MEMCACHED_SUCCESS) {                 printf("set failed, %s\n", memcached_strerror(memc, err));                 exit(1);         }         retvalue= memcached_get(memc, key, strlen(key), &retlen, 0, &err);         if (retvalue) {                 printf("%s\n", retvalue);         } else {                 printf("get failed, %s\n", memcached_strerror(memc, err));         }         memcached_servers_reset(memc);         err= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, true);         if (err != MEMCACHED_SUCCESS) {                 printf("behavior set 2 failed, %s\n", memcached_strerror(memc, err));                 exit(1);         }         err= memcached_server_add(memc, "localhost", 11211);         if (err != MEMCACHED_SUCCESS) {                 printf("server add 2 failed, %s\n", memcached_strerror(memc, err));                 exit(1);         }         err= memcached_set(memc, key, strlen(key), value, strlen(value), 0, 0);         if (err != MEMCACHED_SUCCESS) {                 printf("set 2 failed, %s\n", memcached_strerror(memc, err));                 exit(1);         }         retvalue= memcached_get(memc, key, strlen(key), &retlen, 0, &err);         if (retvalue) {                 printf("%s\n", retvalue);         } else {                 printf("get 2 failed, %s\n", memcached_strerror(memc, err));         }         memcached_free(memc); } Actual behavior: $ gcc memcached_bug.c -o memcached_bug -lmemcached -ggdb $ ./memcached_bug bar Segmentation fault (core dumped) Expected behavior: $ gcc memcached_bug.c -o memcached_bug -lmemcached -ggdb $ ./memcached_bug bar bar gdb output: Program received signal SIGSEGV, Segmentation fault. 0x00007ffff7bbef3d in update_continuum (ptr=0x614c20) at libmemcached/hosts.cc:316 316 ptr->ketama.continuum[continuum_index].index= host_index; (gdb) bt #0 0x00007ffff7bbef3d in update_continuum (ptr=0x614c20) at libmemcached/hosts.cc:316 #1 0x00007ffff7bbf8f6 in memcached_server_add_with_weight (shell=0x614c20, hostname=<optimized out>, port=<optimized out>, weight=0) at libmemcached/hosts.cc:585 #2 0x0000000000400c56 in main () (gdb) list 311 if (memcached_is_weighted_ketama(ptr)) 312 { 313 for (uint32_t x = 0; x < pointer_per_hash; x++) 314 { 315 uint32_t value= ketama_server_hash(sort_host, (size_t)sort_host_length, x); 316 ptr->ketama.continuum[continuum_index].index= host_index; 317 ptr->ketama.continuum[continuum_index++].value= value; 318 } 319 } 320 else (gdb) print ptr->ketama.continuum $1 = (memcached_continuum_item_st *) 0x0 (gdb) print ptr->ketama.continuum_count $2 = 11 (gdb) quit Attached is a patch to fix that.
2016-09-23 07:17:00 Denis attachment removed Patch that fixes bug in memcached_servers_reset https://bugs.launchpad.net/libmemcached/+bug/1626565/+attachment/4746251/+files/libmemcached-ketama-servers_reset.patch
2016-09-23 07:18:09 Denis attachment added fixed patch https://bugs.launchpad.net/libmemcached/+bug/1626565/+attachment/4746731/+files/libmemcached-ketama-servers_reset.patch
2016-09-23 07:21:20 Denis attachment removed fixed patch https://bugs.launchpad.net/libmemcached/+bug/1626565/+attachment/4746731/+files/libmemcached-ketama-servers_reset.patch
2016-09-23 07:21:43 Denis attachment added fixed patch https://bugs.launchpad.net/libmemcached/+bug/1626565/+attachment/4746734/+files/libmemcached-ketama-servers_reset.patch
2017-08-15 17:09:11 Jan Ove Kongshaug bug added subscriber Jan Ove Kongshaug