def test_restart_node_with_full_disk(self): def _get_disk_usage_percentage(remote_client): disk_info = remote_client.get_disk_info() percentage = disk_info[1] + disk_info[2]; for item in percentage.split(): if "%" in item: self.log.info("disk usage {0}".format(item)) return item[:-1] remote_client = RemoteMachineShellConnection(self.master) output, error = remote_client.execute_command_raw("rm -rf full_disk*", use_channel=True) remote_client.log_command_output(output, error) percentage = _get_disk_usage_percentage(remote_client) try: while int(percentage) < 99: output, error = remote_client.execute_command("dd if=/dev/zero of=full_disk{0} bs=3G count=1".format(percentage + str(time.time())), use_channel=True) remote_client.log_command_output(output, error) percentage = _get_disk_usage_percentage(remote_client) processes1 = remote_client.get_running_processes() output, error = remote_client.execute_command("/etc/init.d/couchbase-server restart", use_channel=True) remote_client.log_command_output(output, error) finally: output, error = remote_client.execute_command_raw("rm -rf full_disk*", use_channel=True) remote_client.log_command_output(output, error) remote_client.disconnect()
def test_restart_node_with_full_disk(self): def _get_disk_usage_percentage(remote_client): disk_info = remote_client.get_disk_info() percentage = disk_info[1] + disk_info[2]; for item in percentage.split(): if "%" in item: self.log.info("disk usage {0}".format(item)) return item[:-1] remote_client = RemoteMachineShellConnection(self.master) output, error = remote_client.execute_command_raw("rm -rf full_disk*", use_channel=True) remote_client.log_command_output(output, error) percentage = _get_disk_usage_percentage(remote_client) try: while int(percentage) < 95: output, error = remote_client.execute_command("dd if=/dev/zero of=full_disk{0} bs=3G count=1".format(percentage + str(time.time())), use_channel=True) remote_client.log_command_output(output, error) percentage = _get_disk_usage_percentage(remote_client) processes1 = remote_client.get_running_processes() output, error = remote_client.execute_command("/etc/init.d/couchbase-server restart", use_channel=True) remote_client.log_command_output(output, error) finally: output, error = remote_client.execute_command_raw("rm -rf full_disk*", use_channel=True) remote_client.log_command_output(output, error) remote_client.disconnect()
def serviceInstallBasic(self): for server in self.servers: shell = RemoteMachineShellConnection(server) self.assertTrue(self.service_clean(shell)) self.assertTrue(self.install_gateway(shell)) shell.execute_command_raw( 'rm -rf {0}/* {1}/* {2}/sync_gateway.json {3}/tmp/test*; mkdir {3}/tmp/test {3}/tmp/test2' .format(self.logsdir, self.datadir, self.configdir, self.folder_prefix)) output, error = self.run_sync_gateway_service_install( shell, self.extra_param) self.check_normal_error_output(shell, output, error) self.assertTrue(self.is_sync_gateway_service_running(shell)) self.assertTrue(self.is_sync_gateway_process_running(shell)) if not "--runbase" in self.extra_param: # hardcoded for services LOGS_TEMPLATE_VAR=${RUNBASE_TEMPLATE_VAR}/logs self.datadir = '/home/sync_gateway' if not "--logsdir" in self.extra_param: self.logsdir = '/home/sync_gateway/logs' if not "--cfgpath" in self.extra_param: self.configdir = '/home/sync_gateway' self.assertTrue( shell.file_exists(self.logsdir, 'sync_gateway_error.log')) self.assertTrue(shell.file_exists(self.datadir, 'data')) self.assertTrue(shell.file_exists(self.configdir, self.configfile))
def webHookMutipleWebHooks(self): for server in self.servers: shell = RemoteMachineShellConnection(server) type = shell.extract_remote_info().type.lower() shell.copy_file_local_to_remote( "pytests/sg/simpleServe.go", "{0}/tmp/simpleServe2.go".format(self.folder_prefix)) self.log.info('=== Starting SimpleServe second instances') if type == 'windows': shell.terminate_process(process_name='simpleServe2.exe') output, error = shell.execute_command_raw( 'c:/Go/bin/go.exe run c:/tmp/simpleServe2.go 8082' ' >{0}/tmp/simpleServe2.txt 2>&1 &'.format( self.folder_prefix)) else: shell.terminate_process(process_name='simpleServe2') shell.execute_command( "kill $(ps aux | grep '8082' | awk '{print $2}')") output, error = shell.execute_command_raw( 'go run /tmp/simpleServe2.go 8082' ' >/tmp/simpleServe2.txt 2>&1 &') self.start_sync_gateway(shell, self.configfile) shell.log_command_output(output, error) success, revision, status = self.create_doc_logfiles( shell, self.doc_id, self.doc_content, [ '{0}/tmp/simpleServe.txt'.format(self.folder_prefix), '{0}/tmp/simpleServe2.txt'.format(self.folder_prefix) ]) self.assertTrue(success) shell.disconnect()
def serviceInstallSGPath(self): for server in self.servers: shell = RemoteMachineShellConnection(server) self.assertTrue(self.service_clean(shell)) self.assertTrue(self.install_gateway(shell)) shell.execute_command_raw('mv /opt/couchbase-sync-gateway/bin /opt/couchbase-sync-gateway/bin2 ') output, error = self.run_sync_gateway_service_install(shell, '--sgpath=/opt/couchbase-sync-gateway/bin2/sync_gateway') self.check_normal_error_output(shell, output, error) self.assertTrue(self.is_sync_gateway_service_running(shell)) self.assertTrue(self.is_sync_gateway_process_running(shell)) self.assertTrue(shell.file_exists(self.logsdir, 'sync_gateway_error.log')) self.assertTrue(shell.file_exists(self.datadir, 'data')) self.assertTrue(shell.file_exists(self.configdir, self.configfile))
def test_moxi_cve_2016_8705(self): """ This bug affected commands: set, setQ, add, addQ, replace, replaceQ The different of signed and unsigned integer could trigger an integer overflow and leads to heap buffer overflow To trigger this bug, bodylen must greater than keylen """ OPCODE_ADD = "\x02" keylen = struct.pack("!H", 0xfa) extlen = "\x08" bodylen = struct.pack("!I", 0xffffffd0) opaque = struct.pack("!I", 0) CAS = struct.pack("!Q", 0) extras_flags = 0xdeadbeef extras_expiry = struct.pack("!I", 0xe10) body = "A" * 1024 packet = MEMCACHED_REQUEST_MAGIC + OPCODE_ADD + keylen + extlen packet += DATA_TYPE + VBUCKET + bodylen + opaque + CAS packet += body option = " -vv > %s.out 2>&1" % self.moxi_server.ip for bucket in self.buckets: try: self._run_moxi(self.master, bucket, option=option) mc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) mc.connect((self.moxi_server.ip, int(self.moxi_port))) mc.sendall(packet) self.log.info("key status: %s " % mc.recv(1024)) mc.close() self.log.info("check if memcached handle this bug in log") shell = RemoteMachineShellConnection(self.moxi_server) grep_cmd = "grep 'Packet too big: 0xffffffd0' %s.out " % self.moxi_server.ip o, e = shell.execute_command_raw(grep_cmd) if o: self.assertTrue( 'Packet too big: 0xffffffd0' in o[0], "Memcached failed in bodylen < and keylen + extlen") else: self.log.error("there is no error in output") shell.disconnect() finally: self._stop_moxi() shell = RemoteMachineShellConnection(self.moxi_server) shell.execute_command_raw("rm %s.out" % self.moxi_server.ip) shell.disconnect()
def _stop_moxi(self): self.log.info("kill moxi server at %s " % self.moxi_server.ip) command = "kill -9 $(ps aux | grep -v grep | grep {0} | awk '{{print $2}}')".format(self.moxi_port) shell = RemoteMachineShellConnection(self.moxi_server) output, error = shell.execute_command_raw(command) shell.log_command_output(output, error) shell.disconnect()
def _stop_moxi(self): command = "kill -9 $(ps aux | grep -v grep | grep {0} | awk '{{print $2}}')".format( self.moxi_port) shell = RemoteMachineShellConnection(self.moxi_server) output, error = shell.execute_command_raw(command) shell.log_command_output(output, error) shell.disconnect()
def test_moxi_cve_2016_8705(self): """ This bug affected commands: set, setQ, add, addQ, replace, replaceQ The different of signed and unsigned integer could trigger an integer overflow and leads to heap buffer overflow To trigger this bug, bodylen must greater than keylen """ OPCODE_ADD = "\x02" keylen = struct.pack("!H",0xfa) extlen = "\x08" bodylen = struct.pack("!I",0xffffffd0) opaque = struct.pack("!I",0) CAS = struct.pack("!Q",0) extras_flags = 0xdeadbeef extras_expiry = struct.pack("!I",0xe10) body = "A"*1024 packet = MEMCACHED_REQUEST_MAGIC + OPCODE_ADD + keylen + extlen packet += DATA_TYPE + VBUCKET + bodylen + opaque + CAS packet += body option = " -vv > %s.out 2>&1" % self.moxi_server.ip for bucket in self.buckets: try: self._run_moxi(self.master, bucket, option=option) mc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) mc.connect((self.moxi_server.ip, int(self.moxi_port))) mc.sendall(packet) self.log.info("key status: %s " % mc.recv(1024)) mc.close() self.log.info("check if memcached handle this bug in log") shell = RemoteMachineShellConnection(self.moxi_server) grep_cmd = "grep 'Packet too big: 0xffffffd0' %s.out " % self.moxi_server.ip o, e = shell.execute_command_raw(grep_cmd) if o: self.assertTrue('Packet too big: 0xffffffd0' in o[0], "Memcached failed in bodylen < and keylen + extlen") else: self.log.error("there is no error in output") shell.disconnect() finally: self._stop_moxi() shell = RemoteMachineShellConnection(self.moxi_server) shell.execute_command_raw("rm %s.out" % self.moxi_server.ip) shell.disconnect()
def configHelp(self): for server in self.servers: shell = RemoteMachineShellConnection(server) output, error = shell.execute_command_raw('/opt/couchbase-sync-gateway/bin/sync_gateway -help') for index, str in enumerate(help_string): if index != help_string[index]: self.log.info('configHelp found unmatched help text. error({0}), help({1})'.format(error[index], help_string[index])) self.assertEqual(error[index], help_string[index]) shell.disconnect()
def run_moxi(self, server, port_listen, node_ip, bucket_name): command = ("nohup /opt/couchbase/bin/moxi -u root -Z usr=Administrator,pwd=password,port_listen={0}," + "concurrency=1024,wait_queue_timeout=200,connect_timeout=400,connect_max_errors=3," + "connect_retry_interval=30000,auth_timeout=100,downstream_conn_max=16,downstream_timeout=5000" + ",cycle=200,default_bucket_name={2} http://{1}:8091/pools/default/bucketsStreaming/{2} -d").\ format(port_listen, node_ip, bucket_name) shell = RemoteMachineShellConnection(server) output, error = shell.execute_command_raw(command) shell.log_command_output(output, error) shell.disconnect()
def _run_moxi(self, server, port_listen, node_ip, bucket_name): command = ("nohup /opt/couchbase/bin/moxi -u root -Z usr=Administrator,pwd=password,port_listen={0}," + "concurrency=1024,wait_queue_timeout=200,connect_timeout=400,connect_max_errors=3," + "connect_retry_interval=30000,auth_timeout=100,downstream_conn_max=16,downstream_timeout=5000" + ",cycle=200,default_bucket_name={2} http://{1}:8091/pools/default/bucketsStreaming/{2} -d").\ format(port_listen, node_ip, bucket_name) shell = RemoteMachineShellConnection(server) output, error = shell.execute_command_raw(command) shell.log_command_output(output, error) shell.disconnect()
def test_debug_symbols(self): shell = RemoteMachineShellConnection(self.moxi_server) try: command = 'file /opt/moxi/bin/moxi.actual' output, error = shell.execute_command_raw(command) shell.log_command_output(output, error) self.assertTrue(''.join(output).find('dynamically linked') != -1 and\ ''.join(output).find('not stripped') != -1, "MB-9842 Debug symbols are not included") finally: shell.disconnect()
def change_max_buckets(self, total_buckets): command = "curl -X POST -u {0}:{1} -d maxBucketCount={2} http://{3}:{4}/internalSettings".format\ (self.servers[0].rest_username, self.servers[0].rest_password, total_buckets, self.servers[0].ip, self.servers[0].port) shell = RemoteMachineShellConnection(self.servers[0]) output, error = shell.execute_command_raw(command) shell.log_command_output(output, error) shell.disconnect()
def serviceInstallSGPath(self): for server in self.servers: shell = RemoteMachineShellConnection(server) self.assertTrue(self.service_clean(shell)) self.assertTrue(self.install_gateway(shell)) shell.execute_command_raw( 'mv /opt/couchbase-sync-gateway/bin /opt/couchbase-sync-gateway/bin2 ' ) output, error = self.run_sync_gateway_service_install( shell, '--sgpath=/opt/couchbase-sync-gateway/bin2/sync_gateway') self.check_normal_error_output(shell, output, error) self.assertTrue(self.is_sync_gateway_service_running(shell)) self.assertTrue(self.is_sync_gateway_process_running(shell)) self.assertTrue( shell.file_exists('/home/sync_gateway/logs', 'sync_gateway_error.log')) self.assertTrue(shell.file_exists('/home/sync_gateway', 'data')) self.assertTrue( shell.file_exists('/home/sync_gateway', self.configfile))
def test_debug_symbols(self): shell = RemoteMachineShellConnection(self.moxi_server) try: command = 'file /opt/moxi/bin/moxi.actual' output, error = shell.execute_command_raw(command) shell.log_command_output(output, error) self.assertTrue(''.join(output).find('dynamically linked') != -1 and\ ''.join(output).find('not stripped') != -1, "MB-9842 Debug symbols are not included") finally: shell.disconnect()
def test_moxi_cve_2016_8706(self): """ This test check the affected command: SASL Auth whose opcode is 0x21. if bodylen smaller than keylen, an integer overflow will occurs and trigger heap buffer overflow If this bug was fixed, there would be no memcached crashed """ OPCODE_SET = "\x21" keylen = struct.pack("!H", 32) bodylen = struct.pack("!I", 1) packet = MEMCACHED_REQUEST_MAGIC + OPCODE_SET + keylen + bodylen * 2 + "A" * 1000 option = " -vv > %s.out 2>&1" % self.moxi_server.ip for bucket in self.buckets: try: self._run_moxi(self.master, bucket, option=option) mc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) mc.connect((self.moxi_server.ip, int(self.moxi_port))) mc.sendall(packet) self.log.info("key status: %s " % mc.recv(1024)) mc.close() self.log.info("check if memcached handle this bug in log") shell = RemoteMachineShellConnection(self.moxi_server) grep_cmd = "grep 'Content of packet bigger than encoded body: 0x20 > 0x1' %s.out "\ % self.moxi_server.ip o, e = shell.execute_command_raw(grep_cmd) shell.disconnect() if o: self.assertTrue( 'Content of packet bigger than encoded body: 0x20 > 0x1' in o[0], "Memcached failed in bodylen < and keylen + extlen") else: self.log.error("there is no error in output") finally: self._stop_moxi() shell = RemoteMachineShellConnection(self.moxi_server) shell.execute_command_raw("rm %s.out" % self.moxi_server.ip) shell.disconnect()
def configHelp(self): for server in self.servers: shell = RemoteMachineShellConnection(server) output, error = shell.execute_command_raw( '/opt/couchbase-sync-gateway/bin/sync_gateway -help') for index, str in enumerate(help_string): if index != help_string[index]: self.log.info( 'configHelp found unmatched help text. error({0}), help({1})' .format(error[index], help_string[index])) self.assertEqual(error[index], help_string[index]) shell.disconnect()
def test_moxi_cve_2016_8706(self): """ This test check the affected command: SASL Auth whose opcode is 0x21. if bodylen smaller than keylen, an integer overflow will occurs and trigger heap buffer overflow If this bug was fixed, there would be no memcached crashed """ OPCODE_SET = "\x21" keylen = struct.pack("!H", 32) bodylen = struct.pack("!I", 1) packet = MEMCACHED_REQUEST_MAGIC + OPCODE_SET + keylen + bodylen*2 + "A"*1000 option = " -vv > %s.out 2>&1" % self.moxi_server.ip for bucket in self.buckets: try: self._run_moxi(self.master, bucket, option=option) mc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) mc.connect((self.moxi_server.ip, int(self.moxi_port))) mc.sendall(packet) self.log.info("key status: %s " % mc.recv(1024)) mc.close() self.log.info("check if memcached handle this bug in log") shell = RemoteMachineShellConnection(self.moxi_server) grep_cmd = "grep 'Content of packet bigger than encoded body: 0x20 > 0x1' %s.out "\ % self.moxi_server.ip o, e = shell.execute_command_raw(grep_cmd) shell.disconnect() if o: self.assertTrue('Content of packet bigger than encoded body: 0x20 > 0x1' in o[0], "Memcached failed in bodylen < and keylen + extlen") else: self.log.error("there is no error in output") finally: self._stop_moxi() shell = RemoteMachineShellConnection(self.moxi_server) shell.execute_command_raw("rm %s.out" % self.moxi_server.ip) shell.disconnect()
def webHookMutipleWebHooks(self): for server in self.servers: shell = RemoteMachineShellConnection(server) type = shell.extract_remote_info().type.lower() shell.copy_file_local_to_remote("pytests/sg/simpleServe.go", "{0}/tmp/simpleServe2.go".format(self.folder_prefix)) self.log.info('=== Starting SimpleServe second instances') if type == 'windows': shell.terminate_process(process_name='simpleServe2.exe') output, error = shell.execute_command_raw('c:/Go/bin/go.exe run c:/tmp/simpleServe2.go 8082' ' >{0}/tmp/simpleServe2.txt 2>&1 &'.format(self.folder_prefix)) else: shell.terminate_process(process_name='simpleServe2') shell.execute_command("kill $(ps aux | grep '8082' | awk '{print $2}')") output, error = shell.execute_command_raw('go run /tmp/simpleServe2.go 8082' ' >/tmp/simpleServe2.txt 2>&1 &') self.start_sync_gateway(shell, self.configfile) shell.log_command_output(output, error) success, revision, status = self.create_doc_logfiles(shell, self.doc_id, self.doc_content, ['{0}/tmp/simpleServe.txt'.format(self.folder_prefix), '{0}/tmp/simpleServe2.txt'.format(self.folder_prefix)]) self.assertTrue(success) shell.disconnect()
def serviceInstallBasic(self): for server in self.servers: shell = RemoteMachineShellConnection(server) self.assertTrue(self.service_clean(shell)) self.assertTrue(self.install_gateway(shell)) shell.execute_command_raw( 'rm -rf {0}/* {1}/* {2}/sync_gateway.json {3}/tmp/test*; mkdir {3}/tmp/test {3}/tmp/test2'. format(self.logsdir, self.datadir, self.configdir, self.folder_prefix)) output, error = self.run_sync_gateway_service_install(shell, self.extra_param) self.check_normal_error_output(shell, output, error) self.assertTrue(self.is_sync_gateway_service_running(shell)) self.assertTrue(self.is_sync_gateway_process_running(shell)) if not "--runbase" in self.extra_param: # hardcoded for services LOGS_TEMPLATE_VAR=${RUNBASE_TEMPLATE_VAR}/logs self.datadir = '/home/sync_gateway' if not "--logsdir" in self.extra_param: self.logsdir = '/home/sync_gateway/logs' if not "--cfgpath" in self.extra_param: self.configdir = '/home/sync_gateway' self.assertTrue(shell.file_exists(self.logsdir, 'sync_gateway_error.log')) self.assertTrue(shell.file_exists(self.datadir, 'data')) self.assertTrue(shell.file_exists(self.configdir, self.configfile))
def serviceInstallBasic(self): for server in self.servers: shell = RemoteMachineShellConnection(server) self.assertTrue(self.service_clean(shell)) self.assertTrue(self.install_gateway(shell)) output, error = shell.execute_command_raw( 'rm -rf {0}/* {1}/* {2}/sync_gateway.json /tmp/test*; mkdir /tmp/test /tmp/test2'. format(self.logsdir, self.datadir, self.configdir)) output, error = self.run_sync_gateway_service_install(shell, self.extra_param) self.check_normal_error_output(shell, output, error) self.assertTrue(self.is_sync_gateway_service_running(shell)) self.assertTrue(self.is_sync_gateway_process_running(shell)) self.assertTrue(shell.file_exists(self.logsdir, 'sync_gateway_error.log')) self.assertTrue(shell.file_exists(self.datadir, 'data')) self.assertTrue(shell.file_exists(self.configdir, self.configfile))
def _run_moxi(self, cb_server, bucket): command = ("nohup /opt/moxi/bin/moxi -u root -Z usr={0},pwd={1},port_listen={2}," + "concurrency=1024,wait_queue_timeout=200,connect_timeout=400,connect_max_errors=3," + "connect_retry_interval=30000,auth_timeout=100,downstream_conn_max=16,downstream_timeout=5000" + ",cycle=200,default_bucket_name={3} http://{4}:{5}/pools/default/bucketsStreaming/{3} -d").\ format(cb_server.rest_username, cb_server.rest_password, self.moxi_port, bucket.name, cb_server.ip, (cb_server.port or '8091')) if bucket.name != 'default' and bucket.authType == "sasl": command = ("nohup /opt/moxi/bin/moxi -u root -Z usr={0},pwd={1},port_listen={2}," + "concurrency=1024,wait_queue_timeout=200,connect_timeout=400,connect_max_errors=3," + "connect_retry_interval=30000,auth_timeout=100,downstream_conn_max=16,downstream_timeout=5000" + ",cycle=200 http://{4}:{5}/pools/default/bucketsStreaming/{3} -d").\ format(bucket.name, bucket.saslPassword, self.moxi_port, bucket.name, cb_server.ip, (cb_server.port or '8091')) shell = RemoteMachineShellConnection(self.moxi_server) output, error = shell.execute_command_raw(command) shell.log_command_output(output, error) shell.disconnect() self.sleep(5, "sleep during moxi start")
def _run_moxi(self, cb_server, bucket): command = ("nohup /opt/moxi/bin/moxi -u root -Z usr={0},pwd={1},port_listen={2}," + "concurrency=1024,wait_queue_timeout=200,connect_timeout=400,connect_max_errors=3," + "connect_retry_interval=30000,auth_timeout=100,downstream_conn_max=16,downstream_timeout=5000" + ",cycle=200,default_bucket_name={3} http://{4}:{5}/pools/default/bucketsStreaming/{3} -d").\ format(cb_server.rest_username, cb_server.rest_password, self.moxi_port, bucket.name, cb_server.ip, (cb_server.port or '8091')) if bucket.name != 'default' and bucket.authType == "sasl": command = ("nohup /opt/moxi/bin/moxi -u root -Z usr={0},pwd={1},port_listen={2}," + "concurrency=1024,wait_queue_timeout=200,connect_timeout=400,connect_max_errors=3," + "connect_retry_interval=30000,auth_timeout=100,downstream_conn_max=16,downstream_timeout=5000" + ",cycle=200 http://{4}:{5}/pools/default/bucketsStreaming/{3} -d").\ format(bucket.name, bucket.saslPassword, self.moxi_port, bucket.name, cb_server.ip, (cb_server.port or '8091')) shell = RemoteMachineShellConnection(self.moxi_server) output, error = shell.execute_command_raw(command) shell.log_command_output(output, error) shell.disconnect() self.sleep(5, "sleep during moxi start")
def stop_moxi(self, server, port_listen): command = "kill -9 $(ps aux | grep -v grep | grep {0} | awk '{{print $2}}')".format(port_listen) shell = RemoteMachineShellConnection(server) output, error = shell.execute_command_raw(command) shell.log_command_output(output, error) shell.disconnect()
def test_moxi_cve_2016_8704(self): """ An integer overflow can cause heap overflow if bodylen less than keylen First, set a regular key Second, set key above again with bodylen < and keylen + extlen if there is no fixes, memcached could crash If issue cve_2016_8704 is fixed, there is no memcached crash. Memcached just close connection. Affected commands: append, appendQ, prepend, prependQ since there is no check on body length """ OPCODE_PREPEND_Q = "\x1a" keylen = struct.pack("!H",0xfa) extlen = "\x00" bodylen = struct.pack("!I",0) opaque = struct.pack("!I",0) CAS = struct.pack("!Q",0) body = "A"*1024 packet = MEMCACHED_REQUEST_MAGIC + OPCODE_PREPEND_Q + keylen + extlen packet += DATA_TYPE + VBUCKET + bodylen + opaque + CAS packet += body set_packet = "set testkey 0 60 4\r\ntest\r\n" get_packet = "get testkey\r\n" option = " -vv > %s.out 2>&1" % self.moxi_server.ip for bucket in self.buckets: try: self._run_moxi(self.master, bucket, option=option) mc1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) mc1.connect((self.moxi_server.ip, int(self.moxi_port))) mc1.sendall(set_packet) self.log.info("key status: %s " % mc1.recv(1024)) mc1.close() mc2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) mc2.connect((self.moxi_server.ip, int(self.moxi_port))) mc2.sendall(packet) self.log.info("Invalid key status: %s " % mc2.recv(1024)) mc2.close() shell = RemoteMachineShellConnection(self.moxi_server) grep_cmd = "grep 'Content of packet bigger than encoded body: 0xfa > 0x0' %s.out "\ % self.moxi_server.ip o, e = shell.execute_command_raw(grep_cmd) if o: self.assertTrue('Content of packet bigger than encoded body: 0xfa > 0x0' in o[0], "Memcached failed in bodylen < and keylen + extlen") else: self.log.error("there is no error in output") shell.disconnect() mc3 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) mc3.connect((self.moxi_server.ip, int(self.moxi_port))) mc3.sendall(get_packet) self.log.info("get key value: %s " % mc3.recv(1024)) mc3.close() finally: self._stop_moxi() shell = RemoteMachineShellConnection(self.moxi_server) shell.execute_command_raw("rm %s.out" % self.moxi_server.ip) shell.disconnect()
def test_moxi_cve_2016_8704(self): """ An integer overflow can cause heap overflow if bodylen less than keylen First, set a regular key Second, set key above again with bodylen < and keylen + extlen if there is no fixes, memcached could crash If issue cve_2016_8704 is fixed, there is no memcached crash. Memcached just close connection. Affected commands: append, appendQ, prepend, prependQ since there is no check on body length """ OPCODE_PREPEND_Q = "\x1a" keylen = struct.pack("!H", 0xfa) extlen = "\x00" bodylen = struct.pack("!I", 0) opaque = struct.pack("!I", 0) CAS = struct.pack("!Q", 0) body = "A" * 1024 packet = MEMCACHED_REQUEST_MAGIC + OPCODE_PREPEND_Q + keylen + extlen packet += DATA_TYPE + VBUCKET + bodylen + opaque + CAS packet += body set_packet = "set testkey 0 60 4\r\ntest\r\n" get_packet = "get testkey\r\n" option = " -vv > %s.out 2>&1" % self.moxi_server.ip for bucket in self.buckets: try: self._run_moxi(self.master, bucket, option=option) mc1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) mc1.connect((self.moxi_server.ip, int(self.moxi_port))) mc1.sendall(set_packet) self.log.info("key status: %s " % mc1.recv(1024)) mc1.close() mc2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) mc2.connect((self.moxi_server.ip, int(self.moxi_port))) mc2.sendall(packet) self.log.info("Invalid key status: %s " % mc2.recv(1024)) mc2.close() shell = RemoteMachineShellConnection(self.moxi_server) grep_cmd = "grep 'Content of packet bigger than encoded body: 0xfa > 0x0' %s.out "\ % self.moxi_server.ip o, e = shell.execute_command_raw(grep_cmd) if o: self.assertTrue( 'Content of packet bigger than encoded body: 0xfa > 0x0' in o[0], "Memcached failed in bodylen < and keylen + extlen") else: self.log.error("there is no error in output") shell.disconnect() mc3 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) mc3.connect((self.moxi_server.ip, int(self.moxi_port))) mc3.sendall(get_packet) self.log.info("get key value: %s " % mc3.recv(1024)) mc3.close() finally: self._stop_moxi() shell = RemoteMachineShellConnection(self.moxi_server) shell.execute_command_raw("rm %s.out" % self.moxi_server.ip) shell.disconnect()