Permalink
Browse files

feature: assignment cfg: MaxSubmissionSize

We want to limit, by default, the number of bytes that are unpacked from
the archive. One could upload an archive that unpacks to a huge file,
causing a DoS on the checker.

Reported-by: Alyssa Milburn <amilburn@zall.org>
Signed-off-by: Lucian Cojocar <cojocar@gmail.com>
  • Loading branch information...
cojocar committed Sep 13, 2014
1 parent 65bef3d commit 86571600cc6050d6b7e2d32d2118096542382405
Showing with 47 additions and 1 deletion.
  1. +18 −0 vmchecker/config.py
  2. +8 −0 vmchecker/examples/config-template
  3. +6 −1 vmchecker/submit.py
  4. +15 −0 vmchecker/ziputil.py
@@ -226,6 +226,24 @@ def is_deadline_hard(self, assignment):
val = val.strip().lower()
return (val == 'yes') or (val == 'y') or (val == 'true')

def max_submission_size(self, assignment):
"""Return the maximum size of the unpacked contents.
Useful for avoiding a DoS.
Default is '10M'
"""
val = self.getd(assignment, 'MaxSubmissionSize', '10M')
val = val.strip().lower()
try:
sz = int(re.findall(r"^[0-9]+", val)[0])
if 'k' in val:
return sz * (2 ** 10)
if 'm' in val:
return sz * (2 ** 20)
return sz
except:
return 10*(2 ** 20)

def delay_between_tools_and_tests(self, assignment):
"""After Vmware tools are loaded, there may be some time
before the machine is actually usable (services like apache,
@@ -214,6 +214,14 @@ Timeout = 120
# Set to true if you want to disable upload after the deadline of the
# assignment. Default is 'no'
#
# MaxSubmissionSize
#
# Optional parameter
#
# Specify the maximum number of bytes that the unpacked archive can
# have. Example: 10MB, 23k
#
# Default: 10MB
#
# # These are only for Large assignments
# AssignmentStorage = Large # this is a MD5Submission.
@@ -31,6 +31,7 @@

from penalty import str_to_time
from ziputil import check_archive_for_file_override
from ziputil import check_archive_size

from .courselist import CourseList

@@ -420,6 +421,11 @@ def submit(submission_filename, assignment, user, course_id,

check_valid_time(course_id, assignment, user,
upload_time_str, skip_toosoon_check, False)
storage_type = vmcfg.assignments().getd(assignment, "AssignmentStorage", "")
if storage_type.lower() != "large":
max_submission_size = vmcfg.assignments().max_submission_size(assignment)
check_archive_size(submission_filename, max_submission_size)

sbcfg = save_submission_in_storer(submission_filename, user, assignment,
course_id, upload_time_str)

@@ -441,7 +447,6 @@ def submit(submission_filename, assignment, user, course_id,
raise
return

storage_type = vmcfg.assignments().getd(assignment, "AssignmentStorage", "")
if storage_type.lower() != "large":
queue_for_testing(assignment, user, course_id)

@@ -52,6 +52,21 @@ def check_archive_for_file_override(archive_filename, \
finally:
z.close()

def check_archive_size(archive_filename, max_file_size=10*1024*1024):
"""Sanity check for the unpacked archive file.
We are checking without unpacking the archive.
"""
z = zipfile.ZipFile(archive_filename)
size = 0
try:
for zinfo in z.filelist:
size += zinfo.file_size
if size > max_file_size:
raise zipfile.LargeZipFile
finally:
z.close()


def create_zip(file_handler, file_list):
"""Create a zip into the opened file_handler. The zip is comprised

0 comments on commit 8657160

Please sign in to comment.