#32718: [3.2.1] Issue with assigning file to FileField
-------------------------------------+-------------------------------------
Reporter: Jakub Kleň | Owner: nobody
Type: Bug | Status: new
Component: Database layer | Version: 2.2
(models, ORM) |
Severity: Release blocker | Resolution:
Keywords: 3.2.1 file model | Triage Stage: Accepted
filefield fieldfile |
Has patch: 1 | Needs documentation: 1
Needs tests: 1 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Brian Bouterse):
I think I see why some installations broke with this but other's haven't.
Look at this reproducer:
{{{
from django.core.files import File
from django.db import models
class MyModelWithUploadTo(models.Model):
def upload_to_func(self, name):
return 'qqq'
file = models.FileField(upload_to=upload_to_func)
class MyModel(models.Model):
file = models.FileField()
with open('/tmp/somefile', 'w') as f:
f.write('asdfasdfasdf')
f.flush()
with open('/tmp/anotherfile', 'w') as f:
f.write('fsfoisufsiofdsoiufd')
f.flush()
model_instance_with_upload_to = MyModelWithUploadTo()
model_instance_with_upload_to.file = File(open('/tmp/somefile', 'rb'))
model_instance_with_upload_to.save()
print('I saved the one with upload_to()\n\n')
model_instance = MyModel()
model_instance.file = File(open('/tmp/anotherfile', 'rb'))
model_instance.save()
}}}
On 2.2.20 when I makemigrations for those two models, apply them, and the
run the reproducer I get:
{{{
I saved the one with upload_to()
Traceback (most recent call last):
File "/home/vagrant/devel/django_file_name_2_2_21_reproducer.py", line
30, in <module>
model_instance.save()
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/db/models/base.py", line 743, in save
self.save_base(using=using, force_insert=force_insert,
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/db/models/base.py", line 780, in save_base
updated = self._save_table(
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/db/models/base.py", line 873, in _save_table
result = self._do_insert(cls._base_manager, using, fields, update_pk,
raw)
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/db/models/base.py", line 910, in _do_insert
return manager._insert([self], fields=fields, return_id=update_pk,
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/db/models/query.py", line 1186, in _insert
return query.get_compiler(using=using).execute_sql(return_id)
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/db/models/sql/compiler.py", line 1376, in execute_sql
for sql, params in self.as_sql():
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/db/models/sql/compiler.py", line 1318, in as_sql
value_rows = [
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/db/models/sql/compiler.py", line 1319, in <listcomp>
[self.prepare_value(field, self.pre_save_val(field, obj)) for field in
fields]
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/db/models/sql/compiler.py", line 1319, in <listcomp>
[self.prepare_value(field, self.pre_save_val(field, obj)) for field in
fields]
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/db/models/sql/compiler.py", line 1270, in pre_save_val
return field.pre_save(obj, add=True)
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/db/models/fields/files.py", line 288, in pre_save
file.save(file.name, file.file, save=False)
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/db/models/fields/files.py", line 87, in save
self.name = self.storage.save(name, content,
max_length=self.field.max_length)
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/core/files/storage.py", line 52, in save
return self._save(name, content)
File "/home/vagrant/devel/pulpcore/pulpcore/app/models/storage.py", line
46, in _save
full_path = self.path(name)
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/core/files/storage.py", line 323, in path
return safe_join(self.location, name)
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/utils/_os.py", line 44, in safe_join
raise SuspiciousFileOperation(
django.core.exceptions.SuspiciousFileOperation: The joined path
(/tmp/anotherfile) is located outside of the base path component
(/var/lib/pulp/media)
}}}
Notice how the output includes the `I saved the one with upload_to()`.
That shows this was working with 2.2.20.
Now run that same reproducer, migrations, etc against 2.2.21. I see:
{{{
Traceback (most recent call last):
File "/home/vagrant/devel/django_file_name_2_2_21_reproducer.py", line
25, in <module>
model_instance_with_upload_to.save()
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/db/models/base.py", line 743, in save
self.save_base(using=using, force_insert=force_insert,
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/db/models/base.py", line 780, in save_base
updated = self._save_table(
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/db/models/base.py", line 873, in _save_table
result = self._do_insert(cls._base_manager, using, fields, update_pk,
raw)
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/db/models/base.py", line 910, in _do_insert
return manager._insert([self], fields=fields, return_id=update_pk,
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/db/models/query.py", line 1186, in _insert
return query.get_compiler(using=using).execute_sql(return_id)
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/db/models/sql/compiler.py", line 1376, in execute_sql
for sql, params in self.as_sql():
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/db/models/sql/compiler.py", line 1318, in as_sql
value_rows = [
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/db/models/sql/compiler.py", line 1319, in <listcomp>
[self.prepare_value(field, self.pre_save_val(field, obj)) for field in
fields]
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/db/models/sql/compiler.py", line 1319, in <listcomp>
[self.prepare_value(field, self.pre_save_val(field, obj)) for field in
fields]
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/db/models/sql/compiler.py", line 1270, in pre_save_val
return field.pre_save(obj, add=True)
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/db/models/fields/files.py", line 289, in pre_save
file.save(file.name, file.file, save=False)
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/db/models/fields/files.py", line 87, in save
name = self.field.generate_filename(self.instance, name)
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/db/models/fields/files.py", line 303, in generate_filename
filename = validate_file_name(filename)
File "/usr/local/lib/pulp/lib64/python3.9/site-
packages/django/core/files/utils.py", line 8, in validate_file_name
raise SuspiciousFileOperation("File name '%s' includes path elements"
% name)
django.core.exceptions.SuspiciousFileOperation: File name '/tmp/somefile'
includes path elements
}}}
Here the `SuspiciousFileOperation` is also raised on the saving of
`MyModelWithUploadTo`. Do you all know why this difference is significant?
Regarding non reproducer discussion...
Yes let's take how many folks are broken out of the equation; we have to
do what's secure, even if its inconvenient. I agree with that, and thank
you for saying that. I think what is contributing to the issue is
confusion on why these 2 lines are necessary given how the CVE reads. I'm
not here to second guess the good work of the security response team or
it's review process, but I am confused.
As a practical matter, I'm still trying to figure out if another release
removing these two lines will occur, or if the CVE description needs
revision. Do you have some advice for me on which you think will happen?
Also I'd like to exchange perspectives on version pinning for shipped
django apps depending on the Django LTS, but not until we resolve the
matter at hand first.
Thank you for everything. Our project and users really appreciate it.
Please let me know how we can help.
--
Ticket URL: <https://code.djangoproject.com/ticket/32718#comment:21>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/064.d454cc6e13c5f7e71e393459ddc580c7%40djangoproject.com.