diff options
| author | Aymeric Augustin <aymeric.augustin@m4x.org> | 2013-02-12 11:22:41 +0100 |
|---|---|---|
| committer | Carl Meyer <carl@oddbird.net> | 2013-02-19 11:23:30 -0700 |
| commit | 35c991aa06aa34fa458f01eac49275ff4c2d76f9 (patch) | |
| tree | 176feb553b823a20fadc21f084df5d8cb463ef92 /django/forms/formsets.py | |
| parent | 1f39eafd60761bf6a60b74d9e9859621da1b9363 (diff) | |
Added a default limit to the maximum number of forms in a formset.
This is a security fix. Disclosure and advisory coming shortly.
Diffstat (limited to 'django/forms/formsets.py')
| -rw-r--r-- | django/forms/formsets.py | 23 |
1 files changed, 15 insertions, 8 deletions
diff --git a/django/forms/formsets.py b/django/forms/formsets.py index 1addbc617b..81b75f2796 100644 --- a/django/forms/formsets.py +++ b/django/forms/formsets.py @@ -21,6 +21,9 @@ MAX_NUM_FORM_COUNT = 'MAX_NUM_FORMS' ORDERING_FIELD_NAME = 'ORDER' DELETION_FIELD_NAME = 'DELETE' +# default maximum number of forms in a formset, to prevent memory exhaustion +DEFAULT_MAX_NUM = 1000 + class ManagementForm(Form): """ ``ManagementForm`` is used to keep track of how many form instances @@ -97,11 +100,10 @@ class BaseFormSet(object): total_forms = initial_forms + self.extra # Allow all existing related objects/inlines to be displayed, # but don't allow extra beyond max_num. - if self.max_num is not None: - if initial_forms > self.max_num >= 0: - total_forms = initial_forms - elif total_forms > self.max_num >= 0: - total_forms = self.max_num + if initial_forms > self.max_num >= 0: + total_forms = initial_forms + elif total_forms > self.max_num >= 0: + total_forms = self.max_num return total_forms def initial_form_count(self): @@ -111,14 +113,14 @@ class BaseFormSet(object): else: # Use the length of the inital data if it's there, 0 otherwise. initial_forms = self.initial and len(self.initial) or 0 - if self.max_num is not None and (initial_forms > self.max_num >= 0): + if initial_forms > self.max_num >= 0: initial_forms = self.max_num return initial_forms def _construct_forms(self): # instantiate all the forms and put them in self.forms self.forms = [] - for i in xrange(self.total_form_count()): + for i in xrange(min(self.total_form_count(), self.absolute_max)): self.forms.append(self._construct_form(i)) def _construct_form(self, i, **kwargs): @@ -367,9 +369,14 @@ class BaseFormSet(object): def formset_factory(form, formset=BaseFormSet, extra=1, can_order=False, can_delete=False, max_num=None): """Return a FormSet for the given form class.""" + if max_num is None: + max_num = DEFAULT_MAX_NUM + # hard limit on forms instantiated, to prevent memory-exhaustion attacks + # limit defaults to DEFAULT_MAX_NUM, but developer can increase it via max_num + absolute_max = max(DEFAULT_MAX_NUM, max_num) attrs = {'form': form, 'extra': extra, 'can_order': can_order, 'can_delete': can_delete, - 'max_num': max_num} + 'max_num': max_num, 'absolute_max': absolute_max} return type(form.__name__ + str('FormSet'), (formset,), attrs) def all_valid(formsets): |
