S3 Fuzzer: Output and garbage data tweaks.

- Output tweaks
- added support for printable_no_whitespace and binary_no_whitespace
This commit is contained in:
Kyle Marsh 2011-08-23 15:08:18 -07:00
parent f45d28765d
commit 18c3fe53c2
3 changed files with 67 additions and 32 deletions

View file

@ -3,6 +3,9 @@ start:
garbage:
- '{random 10-3000 printable}'
- '{random 10-1000 binary}'
garbage_no_whitespace:
- '{random 10-3000 printable_no_whitespace}'
- '{random 10-1000 binary_no_whitespace}'
choices:
- bucket
@ -25,7 +28,7 @@ bucket_garbage_method:
- '{bucket_not_readable}'
- '{bucket_writable}'
- '{bucket_not_writable}'
- '2 {garbage}'
- '2 {garbage_no_whitespace}'
choices:
- bucket_get_simple
- bucket_get_filtered
@ -40,12 +43,12 @@ bucket_delete:
bucket:
- '{bucket_writable}'
- '{bucket_not_writable}'
- '2 {garbage}'
- '2 {garbage_no_whitespace}'
query:
- null
- policy
- website
- '2 {garbage}'
- '2 {garbage_no_whitespace}'
choices: []
bucket_get:
@ -54,7 +57,7 @@ bucket_get:
bucket:
- '{bucket_readable}'
- '{bucket_not_readable}'
- '2 {garbage}'
- '2 {garbage_no_whitespace}'
choices:
- 11 bucket_get_simple
- bucket_get_filtered
@ -72,56 +75,56 @@ bucket_get_simple:
- requestPayment
- versioning
- website
- '2 {garbage}'
- '2 {garbage_no_whitespace}'
choices: []
bucket_get_uploads:
set:
delimiter:
- null
- '3 delimiter={garbage}'
- '3 delimiter={garbage_no_whitespace}'
prefix:
- null
- '3 prefix={garbage}'
- '3 prefix={garbage_no_whitespace}'
key_marker:
- null
- 'key-marker={object_readable}'
- 'key-marker={object_not_readable}'
- 'key-marker={invalid_key}'
- 'key-marker={random 100-1000 printable}'
- 'key-marker={random 100-1000 printable_no_whitespace}'
max_uploads:
- null
- 'max-uploads={random 1-5 binary}'
- 'max-uploads={random 1-5 binary_no_whitespace}'
- 'max-uploads={random 1-1000 digits}'
upload_id_marker:
- null
- '3 upload-id-marker={random}'
- '3 upload-id-marker={random 0-1000 printable_no_whitespace}'
query:
- 'uploads'
- 'uploads&{delimiter}&{prefix}'
- 'uploads&{max_uploads}&{key_marker}&{upload_id_marker}'
- '2 {garbage}'
- '2 {garbage_no_whitespace}'
choices: []
bucket_get_filtered:
set:
delimiter:
- 'delimiter={garbage}'
- 'delimiter={garbage_no_whitespace}'
prefix:
- 'prefix={garbage}'
- 'prefix={garbage_no_whitespace}'
marker:
- 'marker={object_readable}'
- 'marker={object_not_readable}'
- 'marker={invalid_key}'
- 'marker={random 100-1000 printable}'
- 'marker={random 100-1000 printable_no_whitespace}'
max_keys:
- 'max-keys={random 1-5 binary}'
- 'max-keys={random 1-5 binary_no_whitespace}'
- 'max-keys={random 1-1000 digits}'
query:
- null
- '{delimiter}&{prefix}'
- '{max-keys}&{marker}'
- '2 {garbage}'
- '2 {garbage_no_whitespace}'
choices: []
bucket_put:
@ -129,7 +132,7 @@ bucket_put:
bucket:
- '{bucket_writable}'
- '{bucket_not_writable}'
- '2 {garbage}'
- '2 {garbage_no_whitespace}'
method: PUT
choices:
- bucket_put_simple
@ -142,9 +145,14 @@ bucket_put_create:
- '2 {garbage}'
- '<CreateBucketConfiguration><LocationConstraint>{random 2-10 binary}</LocationConstraint></CreateBucketConfiguration>'
acl:
- private
- 'private'
- 'public-read'
- 'public-read-write'
- 'authenticated-read'
- 'bucket-owner-read'
- 'bucket-owner-full-control'
- '{random 3000 letters}'
- '{random 100-1000 binary}'
- '{random 100-1000 binary_no_whitespace}'
headers:
- ['0-1', 'x-amz-acl', '{acl}']
choices: []
@ -163,7 +171,7 @@ bucket_put_versioning:
- '<MfaDelete>{random 2-10 binary}</MfaDelete>'
- '<MfaDelete>{random 2000-3000 printable}</MfaDelete>'
mfa_header:
- '{random 10-1000 printable} {random 10-1000 printable}'
- '{random 10-1000 printable_no_whitespace} {random 10-1000 printable_no_whitespace}'
headers:
- ['0-1', 'x-amz-mfa', '{mfa_header}']
choices: []
@ -225,7 +233,7 @@ bucket_put_simple:
notification_body:
- null
- '<NotificationConfiguration />'
- '2 <NotificationConfiguration><TopicConfiguration>{topic}{event}</TopicConfiguration}</NotificationConfiguration>'
- '2 <NotificationConfiguration><TopicConfiguration>{topic}{event}</TopicConfiguration></NotificationConfiguration>'
topic:
- null
- '2 <Topic>{garbage}</Topic>'

View file

@ -158,6 +158,20 @@ def test_expand_random_binary():
eq(got, '\xdfj\xf1\xd80>a\xcd\xc4\xbb')
def test_expand_random_printable_no_whitespace():
prng = random.Random(1)
for _ in xrange(1000):
got = expand({}, '{random 500 printable_no_whitespace}', prng)
assert_true(reduce(lambda x, y: x and y, [x not in string.whitespace and x in string.printable for x in got]))
def test_expand_random_binary():
prng = random.Random(1)
for _ in xrange(1000):
got = expand({}, '{random 500 binary_no_whitespace}', prng)
assert_true(reduce(lambda x, y: x and y, [x not in string.whitespace for x in got]))
def test_expand_random_no_args():
prng = random.Random(1)
for _ in xrange(1000):

View file

@ -136,6 +136,7 @@ def expand(decision, value, prng):
class RepeatExpandingFormatter(string.Formatter):
charsets = {
'printable_no_whitespace': string.printable.translate(None, string.whitespace),
'printable': string.printable,
'punctuation': string.punctuation,
'whitespace': string.whitespace,
@ -161,8 +162,7 @@ class RepeatExpandingFormatter(string.Formatter):
if self._recursion > 5:
raise RecursionError(key)
fmt = self.__class__(self.prng, _recursion=self._recursion+1)
# must use vformat not **kwargs so our SpecialVariables is not
# downgraded to just a dict
n = fmt.vformat(val, args, kwargs)
return n
@ -185,10 +185,12 @@ class RepeatExpandingFormatter(string.Formatter):
except IndexError:
charset_arg = 'printable'
if charset_arg == 'binary':
if charset_arg == 'binary' or charset_arg == 'binary_no_whitespace':
num_bytes = length + 8
tmplist = [self.prng.getrandbits(64) for _ in xrange(num_bytes / 8)]
tmpstring = struct.pack((num_bytes / 8) * 'Q', *tmplist)
if charset_arg == 'binary_no_whitespace':
tmpstring = ''.join(c for c in tmpstring if c not in string.whitespace)
return tmpstring[0:length]
else:
charset = self.charsets[charset_arg]
@ -198,14 +200,16 @@ class RepeatExpandingFormatter(string.Formatter):
def parse_options():
parser = OptionParser()
parser.add_option('-O', '--outfile', help='write output to FILE. Defaults to STDOUT', metavar='FILE')
parser.add_option('--seed', dest='seed', type='int', help='initial seed for the random number generator', metavar='SEED')
parser.add_option('--seed', dest='seed', type='int', help='initial seed for the random number generator')
parser.add_option('--seed-file', dest='seedfile', help='read seeds for specific requests from FILE', metavar='FILE')
parser.add_option('-n', dest='num_requests', type='int', help='issue NUM requests before stopping', metavar='NUM')
parser.add_option('-v', '--verbose', dest='verbose', action="store_true", help='turn on verbose output')
parser.add_option('-d', '--debug', dest='debug', action="store_true", help='turn on debugging (very verbose) output')
parser.add_option('--decision-graph', dest='graph_filename', help='file in which to find the request decision graph', metavar='NUM')
parser.add_option('--decision-graph', dest='graph_filename', help='file in which to find the request decision graph')
parser.add_option('--no-cleanup', dest='cleanup', action="store_false", help='turn off teardown so you can peruse the state of buckets after testing')
parser.set_defaults(num_requests=5)
parser.set_defaults(cleanup=True)
parser.set_defaults(graph_filename='request_decision_graph.yml')
return parser.parse_args()
@ -317,10 +321,10 @@ def _main():
except KeyError:
headers = {}
print>>VERBOSE, "%s %s" %(method[:100], path[:100])
print>>VERBOSE, "%r %r" %(method[:100], path[:100])
for h, v in headers.iteritems():
print>>VERBOSE, "%s: %s" %(h[:50], v[:50])
print>>VERBOSE, "%s\n" % body[:100]
print>>VERBOSE, "%r: %r" %(h[:50], v[:50])
print>>VERBOSE, "%r\n" % body[:100]
print>>DEBUG, 'FULL REQUEST'
print>>DEBUG, 'Method: %r' %method
@ -333,13 +337,22 @@ def _main():
#response = s3_connection.make_request(method, path, data=body, headers=headers, override_num_retries=0)
response = s3_connection.make_request(method, path, data=body, headers=headers)
failed = True if response.status in [500, 503] else False
if failed:
print>>OUT, 'FAILED:'
OLD_VERBOSE = VERBOSE
OLD_DEBUG = DEBUG
VERBOSE = DEBUG = OUT
print>>VERBOSE, 'Response status code: %d %s' %(response.status, response.reason)
print>>DEBUG, 'Body:\n%s' %response.read()
if response.status == 500 or response.status == 503:
print>>OUT, 'FAILED:\n%s' %request
print>>VERBOSE, '='*80
if failed:
VERBOSE = OLD_VERBOSE
DEBUG = OLD_DEBUG
print>>OUT, '...done fuzzing'
common.teardown()
if options.cleanup:
common.teardown()
def main():