Opened 60 minutes ago
#37292 new Bug
TemporaryUploadedFile raises OSError for a filename with a very long extension
| Reported by: | Prakhar Pratyush | Owned by: | |
|---|---|---|---|
| Component: | File uploads/storage | Version: | 5.2 |
| Severity: | Normal | Keywords: | |
| Cc: | Prakhar Pratyush | Triage Stage: | Unreviewed |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
Uploading a file whose extension is long enough makes the request die with an unhandled OSError instead of the name being sanitized.
TemporaryUploadedFile takes the extension straight off the client-supplied filename and uses it as the suffix of the temporary file:
_, ext = os.path.splitext(name)
file = tempfile.NamedTemporaryFile(
suffix=".upload" + ext, dir=settings.FILE_UPLOAD_TEMP_DIR
)
super().__init__(file, name, content_type, size, charset, content_type_extra)
NAME_MAX is 255 bytes on ext4 and most other filesystems, and tempfile adds "tmp" plus 8 random characters on top of the 7-byte ".upload", so an extension of 238 bytes or more is enough to make os.open() fail.
Replication
>>> from django.core.files.uploadedfile import TemporaryUploadedFile
>>> TemporaryUploadedFile("x." + "a" * 250, "text/plain", 6, None)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/srv/zulip/.venv/lib/python3.10/site-packages/django/core/files/uploadedfile.py", line 77, in __init__
file = tempfile.NamedTemporaryFile(
File "/usr/lib/python3.10/tempfile.py", line 714, in NamedTemporaryFile
file = _io.open(dir, mode, buffering=buffering,
File "/usr/lib/python3.10/tempfile.py", line 711, in opener
fd, name = _mkstemp_inner(dir, prefix, suffix, flags, output_type)
File "/usr/lib/python3.10/tempfile.py", line 395, in _mkstemp_inner
fd = _os.open(file, flags, 0o600)
OSError: [Errno 36] File name too long: '/tmp/tmpm5gby_up.upload.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
Also:
Over a real request you need an upload larger than FILE_UPLOAD_MAX_MEMORY_SIZE so that MemoryFileUploadHandler declines it and the temporary file handler takes over. Anything that reads request.POST on that request will then raise, it comes out as a 500.